1// @effect-diagnostics nodeBuiltinImport:off - Compiles the native dependency regression directly.
2import * as NodeChildProcess from "node:child_process";
3import * as NodeFS from "node:fs";
4import * as NodeModule from "node:module";
5import * as NodeOS from "node:os";
6import * as NodePath from "node:path";
7import { expect, it } from "vite-plus/test";
8
9// oxlint-disable-next-line t3code/no-global-process-runtime -- This test compiles against the host Foundation framework.
10it.skipIf(NodeOS.platform() !== "darwin")(
11 "registers and reads native permissions concurrently without corrupting the registry",
12 () => {
13 const directory = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-permissions-test-"));
14 try {
15 const require = NodeModule.createRequire(import.meta.url);
16 const core = NodePath.dirname(
17 NodeModule.createRequire(require.resolve("expo/package.json")).resolve(
18 "expo-modules-core/package.json",
19 ),
20 );
21 const read = (relativePath: string) =>
22 NodeFS.readFileSync(NodePath.join(core, relativePath), "utf8").replace(
23 /^#import .*$/gm,
24 "",
25 );
26 const source = NodePath.join(directory, "regression.m");
27 NodeFS.writeFileSync(
28 source,
29 [
30 "#import <Foundation/Foundation.h>",
31 "#import <objc/runtime.h>",
32 "#include <assert.h>",
33 "#include <pthread.h>",
34 "typedef void (^EXPromiseResolveBlock)(id result);",
35 "typedef void (^EXPromiseRejectBlock)(NSString *, NSString *, NSError *);",
36 "#define RCTLogWarn(...)",
37 read("ios/Interfaces/Permissions/EXPermissionsInterface.h"),
38 read("ios/Legacy/Services/Permissions/EXPermissionsService.h"),
39 read("ios/Legacy/Services/Permissions/EXPermissionsService.m"),
40 NodeFS.readFileSync(
41 new URL("./fixtures/PermissionsServiceRegression.m", import.meta.url),
42 "utf8",
43 ),
44 ].join("\n"),
45 );
46 const executable = NodePath.join(directory, "regression");
47 NodeChildProcess.execFileSync(
48 "clang",
49 [
50 "-fobjc-arc",
51 "-fblocks",
52 "-fsanitize=thread",
53 "-framework",
54 "Foundation",
55 source,
56 "-o",
57 executable,
58 ],
59 { encoding: "utf8", timeout: 30_000 },
60 );
61 expect(
62 NodeChildProcess.execFileSync(executable, { encoding: "utf8", timeout: 15_000 }).trim(),
63 ).toBe("passed");
64 } finally {
65 NodeFS.rmSync(directory, { recursive: true, force: true });
66 }
67 },
68);