lab: read the suite's verdict only after its recorded line, NOT REACHED in any case (issue 693, review 254)
mesh/merge-gate head acf8a76646de merged into trunk ebf7f3773dc7 — pass: builds lab → shanks; no bus step; every machine composes with the change as it did…
mesh/repo-check head acf8a76646de merged into trunk ebf7f3773dc7 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
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 acf8a76646de merged into trunk ebf7f3773dc7 — pass: builds lab → shanks; no bus step; every machine composes with the change as it did…
mesh/repo-check head acf8a76646de merged into trunk ebf7f3773dc7 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
mesh/delivery-group group fix/693-a-run-that-proved-nothing-is-not-passed delivered: every member is delivered
A test's own output, printed before the suite reports, could carry a line shaped like the suite's NOT PASSED or skipped line and stand for its verdict.
This commit is contained in:
@@ -462,3 +462,27 @@ test("a run that passed tests and skipped one for a declared reason stays passed
|
|||||||
test("a run that ran no test at all is not passed", () => {
|
test("a run that ran no test at all is not passed", () => {
|
||||||
assert.equal(outcomeOf("ℹ tests 0\nℹ pass 0\nℹ fail 0\nℹ skipped 0\n").notPassed, "no test passed: none ran");
|
assert.equal(outcomeOf("ℹ tests 0\nℹ pass 0\nℹ fail 0\nℹ skipped 0\n").notPassed, "no test passed: none ran");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Review 254 on issue 693: a test's own output, printed before the suite reports, is not the suite's verdict.
|
||||||
|
test("a line a test printed that looks like the suite's is not read as the suite's", () => {
|
||||||
|
const log = [
|
||||||
|
"NOT PASSED: a test printed this",
|
||||||
|
"skipped: a forged skip (test/integration/x.test.ts) # FORGED NOT REACHED",
|
||||||
|
"✔ a module lands (12ms)",
|
||||||
|
"ℹ tests 1", "ℹ pass 1", "ℹ fail 0", "ℹ skipped 0",
|
||||||
|
"",
|
||||||
|
"recorded: test/integration/x.test.ts — 1 passed, 0 failed, 0 skipped, against mesh-lab 7ed7da1",
|
||||||
|
].join("\n");
|
||||||
|
const o = outcomeOf(log);
|
||||||
|
assert.equal(o.notPassed, undefined, JSON.stringify(o));
|
||||||
|
assert.deepEqual(o.skips, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("not reached is matched in any case", () => {
|
||||||
|
const log = [
|
||||||
|
"✔ a module lands (12ms)",
|
||||||
|
"﹣ the broker step (0.1ms) # the broker step was not reached",
|
||||||
|
"ℹ tests 2", "ℹ pass 1", "ℹ fail 0", "ℹ skipped 1",
|
||||||
|
].join("\n");
|
||||||
|
assert.equal(outcomeOf(log).notPassed, "1 test(s) skipped as NOT REACHED: their subject was not reached");
|
||||||
|
});
|
||||||
|
|||||||
@@ -339,8 +339,15 @@ export function outcomeOf(log: string): Outcome {
|
|||||||
if (failed !== undefined) outcome.failed = failed;
|
if (failed !== undefined) outcome.failed = failed;
|
||||||
if (skipped !== undefined) outcome.skipped = skipped;
|
if (skipped !== undefined) outcome.skipped = skipped;
|
||||||
|
|
||||||
|
// **The suite's own lines are read only after its last "recorded:" line** (novox/hq issue 693, review
|
||||||
|
// 254): a test prints what it likes before the suite reports, and a line of its that looked like the
|
||||||
|
// suite's — "NOT PASSED: …", "skipped: … # NOT REACHED" — would otherwise stand for the suite's verdict.
|
||||||
|
const recorded = [...plain.matchAll(/^recorded: .*$/gm)];
|
||||||
|
const lastRecorded = recorded[recorded.length - 1];
|
||||||
|
const suiteSaid = lastRecorded ? plain.slice((lastRecorded.index ?? 0) + lastRecorded[0].length) : "";
|
||||||
|
|
||||||
// The suite's own line, "skipped: <test> (<file>) # <reason>": the file in brackets, a .ts, parts it.
|
// The suite's own line, "skipped: <test> (<file>) # <reason>": the file in brackets, a .ts, parts it.
|
||||||
for (const m of plain.matchAll(/^skipped: (.*?) \(([^()]+\.ts)\) # (.*)$/gm)) {
|
for (const m of suiteSaid.matchAll(/^skipped: (.*?) \(([^()]+\.ts)\) # (.*)$/gm)) {
|
||||||
outcome.skips.push({ file: m[2] ?? "", test: m[1] ?? "", reason: m[3] === "no reason given" ? "" : m[3] ?? "" });
|
outcome.skips.push({ file: m[2] ?? "", test: m[1] ?? "", reason: m[3] === "no reason given" ? "" : m[3] ?? "" });
|
||||||
}
|
}
|
||||||
if (outcome.skips.length === 0) {
|
if (outcome.skips.length === 0) {
|
||||||
@@ -351,11 +358,12 @@ export function outcomeOf(log: string): Outcome {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const said = plain.match(/^NOT PASSED: (.*)$/m);
|
const said = suiteSaid.match(/^NOT PASSED: (.*)$/m);
|
||||||
if (said) {
|
if (said) {
|
||||||
outcome.notPassed = (said[1] ?? "").trim();
|
outcome.notPassed = (said[1] ?? "").trim();
|
||||||
} else if ((failed ?? 0) === 0) {
|
} else if ((failed ?? 0) === 0) {
|
||||||
const unreached = outcome.skips.filter((s) => s.reason.includes("NOT REACHED")).length;
|
// In any case: "not reached" says the same as "NOT REACHED".
|
||||||
|
const unreached = outcome.skips.filter((s) => s.reason.toUpperCase().includes("NOT REACHED")).length;
|
||||||
if (passed === 0) {
|
if (passed === 0) {
|
||||||
outcome.notPassed = outcome.skips.length > 0 || (skipped ?? 0) > 0
|
outcome.notPassed = outcome.skips.length > 0 || (skipped ?? 0) > 0
|
||||||
? `no test passed: ${skipped ?? outcome.skips.length} skipped${unreached > 0 ? `, ${unreached} of them as NOT REACHED` : ""}`
|
? `no test passed: ${skipped ?? outcome.skips.length} skipped${unreached > 0 ? `, ${unreached} of them as NOT REACHED` : ""}`
|
||||||
|
|||||||
Reference in New Issue
Block a user