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

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:
jochen
2026-10-14 03:28:20 +02:00
parent c8255eb15d
commit acf8a76646
2 changed files with 35 additions and 3 deletions
+11 -3
View File
@@ -339,8 +339,15 @@ export function outcomeOf(log: string): Outcome {
if (failed !== undefined) outcome.failed = failed;
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.
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] ?? "" });
}
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) {
outcome.notPassed = (said[1] ?? "").trim();
} 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) {
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` : ""}`