- add the search/ npm workspace (root workspaces + search:test/search:typecheck delegates) - zero-dependency runner/harness copied from the bot/test precedent - 9 named normalizer laws: rule vectors, symmetry, whole-token-only, slash preservation, glued split, vowel-drop, idempotence, folding, table-is-data (>= 47 rows, one generic builder) All 9 cases fail while src/normalize.ts is absent — the RED gate.
49 lines
1.3 KiB
JavaScript
49 lines
1.3 KiB
JavaScript
#!/usr/bin/env node
|
|
/*
|
|
* runner.mjs — hand-rolled zero-dependency test runner.
|
|
*
|
|
* Same shape as bot/test/runner.mjs (the Phase 2 precedent):
|
|
* - Auto-discovers *.test.mjs in this directory (sorted) and dynamic-imports them.
|
|
* - A suite that fails to LOAD is recorded as one failing case
|
|
* ("suite load failed: <file>") — the run never crashes mid-way.
|
|
* - Per case: PASS <name> / FAIL <name> (+ error detail).
|
|
* - Summary line + exit codes: exit 0 only when every case passed.
|
|
*/
|
|
import { readdirSync } from "node:fs";
|
|
import { registry } from "./harness.mjs";
|
|
|
|
const dir = import.meta.dirname;
|
|
const suites = readdirSync(dir)
|
|
.filter((f) => f.endsWith(".test.mjs"))
|
|
.sort();
|
|
|
|
for (const file of suites) {
|
|
try {
|
|
await import(`./${file}`);
|
|
} catch (loadErr) {
|
|
registry.push({
|
|
name: `suite load failed: ${file}`,
|
|
fn: () => {
|
|
throw loadErr;
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
let passedCount = 0;
|
|
let failedCount = 0;
|
|
for (const { name, fn } of registry) {
|
|
try {
|
|
await fn();
|
|
passedCount++;
|
|
console.log(`PASS ${name}`);
|
|
} catch (err) {
|
|
failedCount++;
|
|
console.log(`FAIL ${name}`);
|
|
console.error(` ${err && err.stack ? err.stack : String(err)}`);
|
|
}
|
|
}
|
|
|
|
console.log(`[runner] ${passedCount} passed, ${failedCount} failed`);
|
|
process.exitCode = failedCount > 0 ? 1 : 0;
|