| 1 | import assert from "node:assert/strict"; |
| 2 | import { readdirSync, readFileSync } from "node:fs"; |
| 3 | import path from "node:path"; |
| 4 | import test from "node:test"; |
| 5 | import vm from "node:vm"; |
| 6 | import { fileURLToPath } from "node:url"; |
| 7 | import { darwinRoots, selectPackages, testArgs } from "./macos-go-tests.mjs"; |
| 8 | |
| 9 | const root = path.dirname(path.dirname(fileURLToPath(import.meta.url))); |
| 10 | const packages = ["reasonix/cmd/reasonix", "reasonix/internal/agent", "reasonix/internal/cli", |
| 11 | "reasonix/internal/cli/theme", "reasonix/internal/clipboard", "reasonix/internal/sandbox", |
| 12 | "reasonix/internal/tool/builtin", "reasonix/internal/toolbox", "reasonix/tools/repolint"]; |
| 13 | |
| 14 | test("the pull-request group keeps darwin packages and drops the rest", () => { |
| 15 | assert.deepEqual(selectPackages(packages, "darwin"), ["reasonix/internal/cli", |
| 16 | "reasonix/internal/cli/theme", "reasonix/internal/sandbox", "reasonix/internal/tool/builtin"]); |
| 17 | // Prefix matching must not swallow a sibling that merely shares a name stem. |
| 18 | assert.ok(!selectPackages(packages, "darwin").includes("reasonix/internal/clipboard")); |
| 19 | assert.ok(!selectPackages(packages, "darwin").includes("reasonix/internal/toolbox")); |
| 20 | assert.deepEqual(selectPackages(packages, "full"), packages); |
| 21 | assert.deepEqual(testArgs(packages, "darwin").slice(0, 2), ["test", "-timeout=8m"]); |
| 22 | assert.throws(() => testArgs(packages, "typo"), /Unknown/); |
| 23 | assert.throws(() => testArgs([], "full"), /Empty/); |
| 24 | }); |
| 25 | |
| 26 | // The root-module packages whose behaviour only a macOS runner can prove. |
| 27 | // Without this the list silently rots: a new _darwin source would be validated |
| 28 | // on pushes but never on the pull request that introduced it. |
| 29 | test("every darwin-specific package is inside the pull-request group", () => { |
| 30 | const owners = new Set(); |
| 31 | const walk = dir => { |
| 32 | for (const entry of readdirSync(dir, { withFileTypes: true })) { |
| 33 | const full = path.join(dir, entry.name); |
| 34 | if (entry.isDirectory()) { |
| 35 | if (!["testdata", "node_modules", "third_party", "vendor"].includes(entry.name)) walk(full); |
| 36 | continue; |
| 37 | } |
| 38 | if (!entry.name.endsWith(".go")) continue; |
| 39 | const darwin = /_darwin(_test)?\.go$/.test(entry.name) |
| 40 | || /^\/\/go:build[^\n]*\bdarwin\b/m.test(readFileSync(full, "utf8").slice(0, 2048)); |
| 41 | if (darwin) owners.add(`reasonix/${path.relative(root, dir).replaceAll(path.sep, "/")}`); |
| 42 | } |
| 43 | }; |
| 44 | for (const top of ["internal", "cmd"]) walk(path.join(root, top)); |
| 45 | assert.ok(owners.size > 0, "expected to find darwin-specific packages"); |
| 46 | const covered = [...owners].filter(pkg => selectPackages([pkg], "darwin").length === 1); |
| 47 | assert.deepEqual(covered.toSorted(), [...owners].toSorted(), |
| 48 | "add the uncovered package to darwinRoots in scripts/macos-go-tests.mjs"); |
| 49 | // And the reverse: a root that no longer owns darwin code is dead weight. |
| 50 | for (const declared of darwinRoots) |
| 51 | assert.ok([...owners].some(pkg => pkg === declared || pkg.startsWith(`${declared}/`)), |
| 52 | `${declared} declares darwin coverage but owns no darwin source`); |
| 53 | }); |
| 54 | |
| 55 | test("CI runs the darwin group on pull requests and the full sweep on pushes", () => { |
| 56 | const source = readFileSync(path.join(root, ".github/workflows/ci.yml"), "utf8"); |
| 57 | assert.match(source, /run: node scripts\/macos-go-tests\.mjs darwin\n/); |
| 58 | const releaseControl = source.match(/\n release-control:\n([\s\S]*?)(?=\n [a-z][a-z0-9-]*:|$)/)?.[1]; |
| 59 | assert.ok(releaseControl, "release-control job must still exist"); |
| 60 | assert.match(releaseControl, /node --test[\s\S]*?scripts\/macos-go-tests\.test\.mjs/); |
| 61 | const enabled = (name, event, run) => { |
| 62 | const step = source.split(` - name: ${name}\n`)[1]?.split(/\n - /)[0]; |
| 63 | assert.ok(step, `${name} must still exist`); |
| 64 | const expression = step.match(/^ if: (.+)$/m)[1]; |
| 65 | return vm.runInNewContext(expression, { |
| 66 | env: { RUN_STEPS: run }, runner: { os: "macOS" }, github: { event_name: event }, |
| 67 | }); |
| 68 | }; |
| 69 | for (const event of ["pull_request", "push", "workflow_dispatch"]) { |
| 70 | for (const run of ["true", "false"]) { |
| 71 | assert.equal(enabled("test", event, run), run === "true" && event !== "pull_request"); |
| 72 | assert.equal(enabled("test (macOS platform packages)", event, run), run === "true" && event === "pull_request"); |
| 73 | } |
| 74 | } |
| 75 | }); |
| 76 |