memlnaut-nisps/codegen/tests/golden_test.ts
monkey-w1n5t0n c45b91a5f9 feat(codegen): P5 — TS emission targets manifold/src/modes/generated/
- generate.ts re-activates the TS emitters against manifold (types.ts,
  per-mode <id>_schema.ts, index.ts); 9 schemas emitted
- firmware-fit check: exactly 3 hidden layers (fixed 4-layer topology) and
  every dim within (0, 4096] (the browser kMaxDim)
- golden test restores the TS case against the manifold path (byte-
  identical to the retained P1-era snapshot)
2026-07-18 12:28:16 +02:00

120 lines
3.6 KiB
TypeScript

#!/usr/bin/env bun
/**
* Golden test: re-runs codegen and asserts that the freshly-generated
* paf_synth_schema.{hpp,ts} files are byte-identical to the snapshots in
* codegen/tests/golden/. (The TS target moved playground → manifold at P5
* of docs/specs/plans/one-core-engine-refactor.md.)
*
* If you change the codegen template intentionally, regenerate the goldens:
* bun run generate.ts
* cp ../nisps/modes/generated/paf_synth_schema.hpp tests/golden/
* cp ../manifold/src/modes/generated/paf_synth_schema.ts tests/golden/
*/
import { readFileSync, existsSync } from "node:fs";
import { join, dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { main as runGenerate } from "../generate.ts";
const __dirname = dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = resolve(__dirname, "..", "..");
const GOLDEN_DIR = join(__dirname, "golden");
interface Case {
name: string;
generatedPath: string;
goldenPath: string;
}
const CASES: Case[] = [
{
name: "paf_synth_schema.hpp",
generatedPath: join(REPO_ROOT, "nisps", "modes", "generated", "paf_synth_schema.hpp"),
goldenPath: join(GOLDEN_DIR, "paf_synth_schema.hpp"),
},
{
name: "paf_synth_schema.ts",
generatedPath: join(REPO_ROOT, "manifold", "src", "modes", "generated", "paf_synth_schema.ts"),
goldenPath: join(GOLDEN_DIR, "paf_synth_schema.ts"),
},
];
function diff(name: string, expected: string, actual: string): string {
const e = expected.split("\n");
const a = actual.split("\n");
const out: string[] = [];
out.push(`mismatch in ${name}:`);
const maxLen = Math.max(e.length, a.length);
let mismatches = 0;
for (let i = 0; i < maxLen; i++) {
if (e[i] !== a[i]) {
mismatches++;
if (mismatches <= 10) {
out.push(` L${i + 1}:`);
out.push(` expected: ${JSON.stringify(e[i] ?? "<EOF>")}`);
out.push(` actual : ${JSON.stringify(a[i] ?? "<EOF>")}`);
}
}
}
if (mismatches > 10) {
out.push(` ... and ${mismatches - 10} more line mismatches`);
}
return out.join("\n");
}
function run(): number {
console.log("running codegen…");
const code = runGenerate();
if (code !== 0) {
console.error(`codegen exited ${code}; aborting golden test`);
return code;
}
let failed = 0;
for (const c of CASES) {
if (!existsSync(c.goldenPath)) {
console.error(`MISSING golden file: ${c.goldenPath}`);
failed++;
continue;
}
if (!existsSync(c.generatedPath)) {
console.error(`MISSING generated file: ${c.generatedPath}`);
failed++;
continue;
}
const expected = readFileSync(c.goldenPath, "utf8");
const actual = readFileSync(c.generatedPath, "utf8");
if (expected !== actual) {
console.error(diff(c.name, expected, actual));
failed++;
} else {
console.log(` ok ${c.name}`);
}
}
// Idempotency check: re-run codegen, files must still match goldens.
console.log("re-running codegen for idempotency check…");
const code2 = runGenerate();
if (code2 !== 0) {
console.error(`second codegen run exited ${code2}; aborting`);
return code2;
}
for (const c of CASES) {
if (!existsSync(c.goldenPath) || !existsSync(c.generatedPath)) continue;
const expected = readFileSync(c.goldenPath, "utf8");
const actual = readFileSync(c.generatedPath, "utf8");
if (expected !== actual) {
console.error(`idempotency: ${c.name} drifted on second run`);
failed++;
}
}
if (failed > 0) {
console.error(`\n${failed} golden test(s) failed.`);
return 1;
}
console.log("\nall golden tests passed.");
return 0;
}
process.exit(run());