| 1 | // @effect-diagnostics nodeBuiltinImport:off - Compiles and runs the native dependency regression directly. |
| 2 | import * as NodeChildProcess from "node:child_process"; |
| 3 | import * as NodeFS from "node:fs"; |
| 4 | import * as NodeOS from "node:os"; |
| 5 | import * as NodePath from "node:path"; |
| 6 | import * as NodeURL from "node:url"; |
| 7 | import { afterAll, beforeAll, describe, expect, it } from "vite-plus/test"; |
| 8 | |
| 9 | // oxlint-disable-next-line t3code/no-global-process-runtime -- This native integration test uses the host Swift compiler. |
| 10 | describe.skipIf(NodeOS.platform() !== "darwin")( |
| 11 | "NotificationCenterManager native concurrency", |
| 12 | () => { |
| 13 | let directory: string; |
| 14 | let executable: string; |
| 15 | |
| 16 | beforeAll(() => { |
| 17 | directory = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-notifications-test-")); |
| 18 | executable = NodePath.join(directory, "notification-regression"); |
| 19 | const source = NodeFS.readFileSync( |
| 20 | new URL( |
| 21 | "../node_modules/expo-notifications/ios/ExpoNotifications/Notifications/NotificationCenterManager.swift", |
| 22 | import.meta.url, |
| 23 | ), |
| 24 | "utf8", |
| 25 | ); |
| 26 | const manager = NodePath.join(directory, "NotificationCenterManager.swift"); |
| 27 | NodeFS.writeFileSync( |
| 28 | manager, |
| 29 | source.replace(/^import (ExpoModulesCore|UserNotifications)\n/gm, ""), |
| 30 | ); |
| 31 | NodeChildProcess.execFileSync( |
| 32 | "swiftc", |
| 33 | [ |
| 34 | "-swift-version", |
| 35 | "5", |
| 36 | "-sanitize=thread", |
| 37 | manager, |
| 38 | NodeURL.fileURLToPath( |
| 39 | new URL("./fixtures/NotificationCenterManagerRegression.swift", import.meta.url), |
| 40 | ), |
| 41 | "-o", |
| 42 | executable, |
| 43 | ], |
| 44 | { timeout: 30_000, encoding: "utf8" }, |
| 45 | ); |
| 46 | }); |
| 47 | |
| 48 | afterAll(() => { |
| 49 | if (directory) NodeFS.rmSync(directory, { recursive: true, force: true }); |
| 50 | }); |
| 51 | |
| 52 | it.each([ |
| 53 | ["reentrant", "allows callbacks to replace delegates without deadlocking"], |
| 54 | ["handoff", "delivers responses to delegates registering during delivery"], |
| 55 | ["pending", "retains new responses received while replaying pending responses"], |
| 56 | ["concurrent", "registers, removes, and broadcasts concurrently without data races"], |
| 57 | ])("%s: %s", (name) => { |
| 58 | const output = NodeChildProcess.execFileSync(executable, [name], { |
| 59 | encoding: "utf8", |
| 60 | timeout: 15_000, |
| 61 | }); |
| 62 | expect(output.trim()).toBe("passed"); |
| 63 | }); |
| 64 | }, |
| 65 | ); |