// Tests for the STEG 0 nav-golden corpus gate (check-nav-golden.mjs). // Style mirrors check-okf-parity.test.mjs: node:test, temp fixtures, a subprocess for // the CLI exit contract, zero npm deps. Two layers: // 1. Over the COMMITTED corpus — both consumed fixtures conform + their goldens are present. // 2. Runtime-materialized meta-tests that drive each FAIL axis (untyped concept, missing // okf_version, absent bundle/, absent golden, empty golden) + the orphan-dir report. // SCOPE mirror: this gate is THIN (conformance + golden presence). It does NOT run a // navigator, so there is no byte-exact golden assertion here — that is a consumer concern. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { execFileSync } from 'node:child_process'; import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { checkFixture, runCorpus, GOLDEN_FILE } from './check-nav-golden.mjs'; const HERE = dirname(fileURLToPath(import.meta.url)); const RUNNER = join(HERE, 'check-nav-golden.mjs'); const CORPUS = join(HERE, '..', 'test', 'nav-golden-corpus'); function tmpRoot() { return mkdtempSync(join(tmpdir(), 'nav-golden-')); } // Materialize a minimal fixture directory: //{bundle/{index.md,concept.md},golden}. // Options flip each FAIL axis independently. function makeFixture(base, name, opts = {}) { const { withBundle = true, okfVersion = true, conceptTyped = true, golden = 'read-context body\n', } = opts; const fdir = join(base, name); mkdirSync(fdir, { recursive: true }); if (withBundle) { const bundle = join(fdir, 'bundle'); mkdirSync(bundle, { recursive: true }); writeFileSync( join(bundle, 'index.md'), okfVersion ? '---\ntype: index\nokf_version: 0.1\n---\n# root\n' : '---\ntype: index\n---\n# root\n', ); writeFileSync( join(bundle, 'concept.md'), conceptTyped ? '---\ntype: project\ntitle: C\n---\n# c\n' : '---\ntitle: C\n---\n# c\n', ); } if (golden !== null) writeFileSync(join(fdir, GOLDEN_FILE), golden); return fdir; } // --- Layer 1: the committed corpus (the acceptance binding for the consumed fixtures) --- test('committed corpus: both nav-golden fixtures conform and their goldens are present', () => { const { results, failed, orphans, exitCode } = runCorpus(CORPUS); assert.equal(exitCode, 0, `committed corpus must be green; failed: ${JSON.stringify(failed.map((f) => f.fixture))}`); assert.deepEqual(failed, []); assert.deepEqual(orphans, [], `no unmanifested corpus dirs; orphans: ${orphans.join(', ')}`); const byName = Object.fromEntries(results.map((r) => [r.fixture, r])); for (const name of ['nav-golden-hierarchy', 'nav-golden-escape']) { const r = byName[name]; assert.ok(r, `${name} must be in the manifest`); assert.equal(r.status, 'PASS', `${name} must PASS`); assert.equal(r.okf.okfVersion, '0.1', `${name} bundle root must echo okf_version 0.1`); assert.equal(r.goldenPresent, true); assert.equal(r.goldenNonEmpty, true); assert.deepEqual(r.problems, []); } }); test('CLI over committed corpus: exit 0 + "OK: nav-golden" line', () => { const stdout = execFileSync('node', [RUNNER], { encoding: 'utf8' }); assert.match(stdout, /OK: nav-golden fixtures conform/); }); // --- Layer 2: materialized FAIL axes (checkFixture is pure over a fixture dir) --- test('PASS: a well-formed fixture (typed concept + okf_version + non-empty golden)', () => { const base = tmpRoot(); try { const fdir = makeFixture(base, 'ok'); const r = checkFixture(fdir, 'ok'); assert.equal(r.status, 'PASS'); assert.deepEqual(r.problems, []); assert.equal(r.okf.okfVersion, '0.1'); assert.equal(r.goldenNonEmpty, true); } finally { rmSync(base, { recursive: true, force: true }); } }); test('FAIL: a concept file without type', () => { const base = tmpRoot(); try { const fdir = makeFixture(base, 'untyped', { conceptTyped: false }); const r = checkFixture(fdir, 'untyped'); assert.equal(r.status, 'FAIL'); assert.ok(r.problems.some((p) => /without type/.test(p)), `problems: ${r.problems.join('; ')}`); } finally { rmSync(base, { recursive: true, force: true }); } }); test('FAIL: root index.md without okf_version', () => { const base = tmpRoot(); try { const fdir = makeFixture(base, 'nover', { okfVersion: false }); const r = checkFixture(fdir, 'nover'); assert.equal(r.status, 'FAIL'); assert.ok(r.problems.some((p) => /okf_version/.test(p)), `problems: ${r.problems.join('; ')}`); } finally { rmSync(base, { recursive: true, force: true }); } }); test('FAIL: missing bundle/ directory', () => { const base = tmpRoot(); try { const fdir = makeFixture(base, 'nobundle', { withBundle: false }); const r = checkFixture(fdir, 'nobundle'); assert.equal(r.status, 'FAIL'); assert.ok(r.problems.some((p) => /bundle\//.test(p)), `problems: ${r.problems.join('; ')}`); } finally { rmSync(base, { recursive: true, force: true }); } }); test('FAIL: the committed golden is absent', () => { const base = tmpRoot(); try { const fdir = makeFixture(base, 'nogolden', { golden: null }); const r = checkFixture(fdir, 'nogolden'); assert.equal(r.status, 'FAIL'); assert.equal(r.goldenPresent, false); assert.ok(r.problems.some((p) => new RegExp(GOLDEN_FILE).test(p)), `problems: ${r.problems.join('; ')}`); } finally { rmSync(base, { recursive: true, force: true }); } }); test('FAIL: the golden is present but empty (whitespace only)', () => { const base = tmpRoot(); try { const fdir = makeFixture(base, 'emptygolden', { golden: ' \n\n' }); const r = checkFixture(fdir, 'emptygolden'); assert.equal(r.status, 'FAIL'); assert.equal(r.goldenPresent, true); assert.equal(r.goldenNonEmpty, false); } finally { rmSync(base, { recursive: true, force: true }); } }); // --- Layer 2b: runCorpus over a materialized corpus (manifest + orphan report + exit code) --- test('runCorpus: a FAIL fixture drives exit 1; an unmanifested dir is reported as an orphan', () => { const base = tmpRoot(); try { makeFixture(base, 'good'); makeFixture(base, 'bad', { conceptTyped: false }); makeFixture(base, 'stowaway'); // on disk but NOT in the manifest -> orphan writeFileSync( join(base, 'manifest.json'), JSON.stringify({ fixtures: { good: { axis: 'a' }, bad: { axis: 'b' }, }, }), ); const { results, orphans, failed, exitCode } = runCorpus(base); assert.equal(exitCode, 1, 'a FAIL fixture must make the corpus red'); assert.deepEqual(failed.map((f) => f.fixture).sort(), ['bad']); assert.deepEqual(orphans, ['stowaway']); const good = results.find((r) => r.fixture === 'good'); assert.equal(good.status, 'PASS'); } finally { rmSync(base, { recursive: true, force: true }); } }); test('runCorpus: a manifested fixture absent on disk is reported MISSING (exit 1)', () => { const base = tmpRoot(); try { makeFixture(base, 'present'); writeFileSync( join(base, 'manifest.json'), JSON.stringify({ fixtures: { present: { axis: 'a' }, ghost: { axis: 'b' } } }), ); const { failed, exitCode } = runCorpus(base); assert.equal(exitCode, 1); assert.ok(failed.some((f) => f.fixture === 'ghost' && f.status === 'MISSING')); } finally { rmSync(base, { recursive: true, force: true }); } });