返回 CodeWhale
d8-executable.test.js
根目录 / .github / scripts / d8-executable.test.js
1 const assert = require("node:assert/strict");
2 const fs = require("node:fs");
3 const os = require("node:os");
4 const path = require("node:path");
5 const { spawnSync } = require("node:child_process");
6 const { test } = require("node:test");
7
8 const sourceRoot = path.resolve(__dirname, "../..");
9
10 function fixture(t) {
11 const root = fs.mkdtempSync(path.join(os.tmpdir(), "cw-d8-launch-"));
12 t.after(() => fs.rmSync(root, { recursive: true, force: true }));
13 const repo = path.join(root, "source");
14 fs.mkdirSync(path.join(repo, "scripts"), { recursive: true });
15 for (const name of ["dev-test.sh", "dev-cache.sh", "dev-cargo.sh", "with-hermetic-test-home.sh", "build-lock.py"]) {
16 fs.copyFileSync(path.join(sourceRoot, "scripts", name), path.join(repo, "scripts", name));
17 fs.chmodSync(path.join(repo, "scripts", name), 0o755);
18 }
19 fs.writeFileSync(path.join(repo, "Cargo.toml"), '[workspace]\nmembers = []\n');
20 const bin = path.join(root, "bin");
21 const home = path.join(root, "ambient home");
22 fs.mkdirSync(bin); fs.mkdirSync(home);
23 const log = path.join(root, "cargo-invocations.jsonl");
24 fs.writeFileSync(path.join(bin, "cargo"), `#!${process.execPath}
25
26 const fs = require("node:fs");
27 const args = process.argv.slice(2);
28 if (args.includes("--version")) { console.log("cargo 1.97.0 (source fixture)"); process.exit(0); }
29 fs.appendFileSync(process.env.D8_INVOCATIONS, JSON.stringify({args, home: process.env.HOME, cache: process.env.CODEWHALE_CACHE_ROOT}) + "\\n");
30 if (args.includes("build") && process.env.D8_BUILD_FAILURE) process.exit(Number(process.env.D8_BUILD_FAILURE));
31 console.log("test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s");
32 `);
33 fs.writeFileSync(path.join(bin, "rustc"), `#!/bin/sh\nprintf '%s\n' 'rustc 1.97.0 (source fixture)' 'commit-hash: source-fixture'\n`);
34 fs.writeFileSync(path.join(bin, "rustup"), `#!/bin/sh\nif [ "$1" = which ] && [ "$2" = rustc ]; then printf '%s\n' "$D8_TOOLCHAIN/rustc"; else exit 99; fi\n`);
35 for (const name of ["cargo", "rustc", "rustup"]) fs.chmodSync(path.join(bin, name), 0o755);
36 return {
37 home, log,
38 run(area, failure) {
39 const result = spawnSync("sh", [path.join(repo, "scripts/dev-test.sh"), area, "filter with spaces"], {
40 cwd: repo, encoding: "utf8",
41 env: { ...process.env, PATH: `${bin}${path.delimiter}${process.env.PATH}`, HOME: home,
42 USERPROFILE: home, CARGO_HOME: path.join(root, "cargo-home"), RUSTUP_HOME: path.join(root, "rustup-home"),
43 CODEWHALE_DEV_NEXTEST: "0", CODEWHALE_BUILD_LOCK: "0", CODEWHALE_BUILD_LOCK_HELD: "",
44 CODEWHALE_CACHE_ROOT: path.join(root, "cache"), D8_INVOCATIONS: log, D8_TOOLCHAIN: bin,
45 D8_BUILD_FAILURE: failure ? String(failure) : "" },
46 });
47 const calls = fs.existsSync(log) ? fs.readFileSync(log, "utf8").trim().split("\n").map(JSON.parse) : [];
48 return { result, calls };
49 },
50 };
51 }
52
53 for (const area of ["tui-integration", "tui-cucumber"]) {
54 test(`${area} builds the canonical executable before isolated acceptance`, (t) => {
55 const f = fixture(t); const { result, calls } = f.run(area);
56 assert.equal(result.status, 0, result.stderr + result.stdout);
57 assert.equal(calls.length, 2);
58 const build = calls[0].args.slice(calls[0].args.indexOf("build"));
59 assert.deepEqual(build, ["build", "-p", "codewhale-cli", "--bin", "codewhale", "--locked"]);
60 const check = calls[1].args.slice(calls[1].args.indexOf("test"));
61 assert.deepEqual(check, ["test", "-p", "codewhale-tui", "--test", area === "tui-integration" ? "integration" : "cucumber", "--locked", "filter with spaces"]);
62 for (const call of calls) {
63 assert.notEqual(call.home, f.home);
64 assert.equal(fs.existsSync(call.home), false, "temporary test HOME is removed");
65 assert.ok(call.cache.endsWith("cache"));
66 }
67 });
68 }
69
70 test("canonical build failure prevents acceptance and preserves its exit status", (t) => {
71 const f = fixture(t); const { result, calls } = f.run("tui-integration", 39);
72 assert.equal(result.status, 39, result.stderr + result.stdout);
73 assert.equal(calls.length, 1);
74 assert.ok(calls[0].args.includes("build"));
75 });
76
77 test("library-only verification does not build an executable", (t) => {
78 const f = fixture(t); const { result, calls } = f.run("config");
79 assert.equal(result.status, 0, result.stderr + result.stdout);
80 assert.equal(calls.length, 1);
81 assert.ok(calls[0].args.includes("test"));
82 assert.ok(calls[0].args.includes("--lib"));
83 });
84
84 lines JAVASCRIPT