1// @effect-diagnostics nodeBuiltinImport:off - Compiles and runs the native dependency regression directly.
2import * as NodeChildProcess from "node:child_process";
3import * as NodeFS from "node:fs";
4import * as NodeOS from "node:os";
5import * as NodePath from "node:path";
6import * as NodeURL from "node:url";
7import { 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.
10describe.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);