Read the runner's last summary and NOT REACHED in any case (issue 693, review 253)
mesh/merge-gate head 5ba88c69fa80 merged into trunk f9be71b9ad44 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 5ba88c69fa80 merged into trunk f9be71b9ad44 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript)…
mesh/delivery delivered
mesh/delivery-group group fix/693-a-run-that-proved-nothing-is-not-passed delivered: every member is delivered
mesh/merge-gate head 5ba88c69fa80 merged into trunk f9be71b9ad44 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 5ba88c69fa80 merged into trunk f9be71b9ad44 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript)…
mesh/delivery delivered
mesh/delivery-group group fix/693-a-run-that-proved-nothing-is-not-passed delivered: every member is delivered
A test that printed a summary-shaped line before it skipped was read as the runner's totals: "ℹ pass 5" made a run that proved nothing pass.
This commit is contained in:
+2
-1
@@ -54,7 +54,8 @@ export function judgeRun(
|
|||||||
skips: Skip[],
|
skips: Skip[],
|
||||||
): { passed: boolean; why: string } {
|
): { passed: boolean; why: string } {
|
||||||
if (counts.failed !== null && counts.failed > 0) return { passed: false, why: `${counts.failed} test(s) failed` };
|
if (counts.failed !== null && counts.failed > 0) return { passed: false, why: `${counts.failed} test(s) failed` };
|
||||||
const unreached = skips.filter((s) => s.reason.includes(NOT_REACHED));
|
// In any case: "not reached" says the same as "NOT REACHED".
|
||||||
|
const unreached = skips.filter((s) => s.reason.toUpperCase().includes(NOT_REACHED));
|
||||||
if (counts.passed === 0) {
|
if (counts.passed === 0) {
|
||||||
return {
|
return {
|
||||||
passed: false,
|
passed: false,
|
||||||
|
|||||||
+9
-5
@@ -28,14 +28,18 @@ export function counted(output: string): { passed: number | null; failed: number
|
|||||||
// running this against the real runner — the fixture it was first written against was output I
|
// running this against the real runner — the fixture it was first written against was output I
|
||||||
// had imagined, which is a test that agrees with the mistake it was written beside.
|
// had imagined, which is a test that agrees with the mistake it was written beside.
|
||||||
const plain = output.replace(/\u001b\[[0-9;]*m/g, "");
|
const plain = output.replace(/\u001b\[[0-9;]*m/g, "");
|
||||||
|
// **The last such line, never the first** (novox/hq issue 693): the runner prints its summary after
|
||||||
|
// everything a test printed, so a test that prints "ℹ pass 5" before it skips would otherwise be read
|
||||||
|
// as five passes, and a run that proved nothing as passed.
|
||||||
const total = (what: RegExp) => {
|
const total = (what: RegExp) => {
|
||||||
const found = plain.match(what);
|
const found = [...plain.matchAll(what)];
|
||||||
return found ? Number(found[1]) : null;
|
const last = found[found.length - 1];
|
||||||
|
return last ? Number(last[1]) : null;
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
passed: total(/^\s*(?:\u2139|#)\s*pass\s+(\d+)\s*$/m),
|
passed: total(/^\s*(?:\u2139|#)\s*pass\s+(\d+)\s*$/gm),
|
||||||
failed: total(/^\s*(?:\u2139|#)\s*fail\s+(\d+)\s*$/m),
|
failed: total(/^\s*(?:\u2139|#)\s*fail\s+(\d+)\s*$/gm),
|
||||||
skipped: total(/^\s*(?:\u2139|#)\s*skipped\s+(\d+)\s*$/m),
|
skipped: total(/^\s*(?:\u2139|#)\s*skipped\s+(\d+)\s*$/gm),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,20 @@ test("the recorded line says what skipped and why, and NOT PASSED", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// A test that prints a summary-shaped line before it skips must not stand for the runner's summary.
|
||||||
|
test("the runner's last summary is read, not a line a test printed before it", () => {
|
||||||
|
const output = "\u2139 pass 5\n\u2139 fail 0\n\u2139 skipped 0\n\ufe63 genesis adopts its bus (1ms) # NOT REACHED\n" +
|
||||||
|
"\u2139 tests 1\n\u2139 pass 0\n\u2139 fail 0\n\u2139 skipped 1\n";
|
||||||
|
const counts = counted(output);
|
||||||
|
assert.deepEqual(counts, { passed: 0, failed: 0, skipped: 1 });
|
||||||
|
assert.equal(exitOf(0, counts, [unreached]), 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("NOT REACHED is matched in any case", () => {
|
||||||
|
const said = judgeRun({ passed: 2, failed: 0 }, [{ ...noBed, reason: "the broker step was not reached" }]);
|
||||||
|
assert.equal(said.passed, false);
|
||||||
|
});
|
||||||
|
|
||||||
test("the runner's skipped total is read", () => {
|
test("the runner's skipped total is read", () => {
|
||||||
assert.deepEqual(counted("ℹ tests 1\nℹ pass 0\nℹ fail 0\nℹ skipped 1\n"), { passed: 0, failed: 0, skipped: 1 });
|
assert.deepEqual(counted("ℹ tests 1\nℹ pass 0\nℹ fail 0\nℹ skipped 1\n"), { passed: 0, failed: 0, skipped: 1 });
|
||||||
});
|
});
|
||||||
@@ -122,6 +136,27 @@ test("the suite exits non-zero for a file whose only test skipped as NOT REACHED
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("the suite does not take a summary a test printed for the runner's", () => {
|
||||||
|
const dir = mkdtempSync(join(tmpdir(), "mesh-lab-693-"));
|
||||||
|
try {
|
||||||
|
const file = join(dir, "forged.test.ts");
|
||||||
|
writeFileSync(file, [
|
||||||
|
`import { test } from "node:test";`,
|
||||||
|
`test("genesis adopts its bus", (t) => {`,
|
||||||
|
` console.log("\\u2139 pass 5\\n\\u2139 fail 0");`,
|
||||||
|
` t.skip("ADR 0333 §5 NOT REACHED: stopped at step 16");`,
|
||||||
|
`});`,
|
||||||
|
].join("\n"));
|
||||||
|
const ran = spawnSync(process.execPath, ["--experimental-strip-types", join(lab, "src", "cli.ts"), "suite", "--no-build", file], {
|
||||||
|
cwd: lab, encoding: "utf8", env: suiteEnv(dir),
|
||||||
|
});
|
||||||
|
assert.equal(ran.status, 1, `the suite exited ${ran.status}:\n${ran.stdout}${ran.stderr}`);
|
||||||
|
assert.match(ran.stdout, /0 passed, 0 failed, 1 skipped/);
|
||||||
|
} finally {
|
||||||
|
rmSync(dir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("the suite still exits 0 for a file that passes a test and skips another for a declared reason", () => {
|
test("the suite still exits 0 for a file that passes a test and skips another for a declared reason", () => {
|
||||||
const dir = mkdtempSync(join(tmpdir(), "mesh-lab-693-"));
|
const dir = mkdtempSync(join(tmpdir(), "mesh-lab-693-"));
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user