import { test, expect } from "bun:test"; import { verifySama } from "./b32_sama_verify.ts"; const baseInput = { repoOwner: "test", repoName: "repo", defaultBranch: "main", srcPaths: [] as string[], contents: new Map(), }; test("empty input: all checks pass, sorted has a 'no SAMA files' note", () => { const r = verifySama(baseInput); expect(r.overallPassed).toBe(true); const sorted = r.checks.find((c) => c.letter === "S")!; expect(sorted.passed).toBe(true); expect(sorted.examined).toBe(0); expect(sorted.note).toMatch(/no cXX_\*\.ts files found/); }); test("Sorted: c14 importing c51 is flagged", () => { const r = verifySama({ ...baseInput, srcPaths: ["c14_io.ts", "c51_render.ts"], contents: new Map([ ["c14_io.ts", `import { x } from "./c51_render.ts";`], ["c51_render.ts", "export const x = 1;"], ]), }); const sorted = r.checks.find((c) => c.letter === "S")!; expect(sorted.passed).toBe(false); expect(sorted.violations[0]?.file).toBe("c14_io.ts"); expect(sorted.violations[0]?.detail).toMatch(/UI/); }); test("Sorted: c21 importing c51 is NOT flagged (handlers may compose UI)", () => { const r = verifySama({ ...baseInput, srcPaths: ["c21_handler.ts", "c51_render.ts"], contents: new Map([ ["c21_handler.ts", `import { x } from "./c51_render.ts";`], ["c51_render.ts", "export const x = 1;"], ]), }); const sorted = r.checks.find((c) => c.letter === "S")!; expect(sorted.passed).toBe(true); }); test("Sorted: c31 importing c32 (sibling layer, non-UI) is NOT flagged", () => { const r = verifySama({ ...baseInput, srcPaths: ["c31_model.ts", "c32_logic.ts"], contents: new Map([ ["c31_model.ts", `import { x } from "./c32_logic.ts";`], ["c32_logic.ts", "export const x = 1;"], ]), }); const sorted = r.checks.find((c) => c.letter === "S")!; expect(sorted.passed).toBe(true); }); test("Architecture: unknown prefix is flagged", () => { const r = verifySama({ ...baseInput, srcPaths: ["c99_thing.ts"], contents: new Map([["c99_thing.ts", "export const x = 1;"]]), }); const arch = r.checks.find((c) => c.property === "Architecture")!; expect(arch.passed).toBe(false); expect(arch.violations[0]?.detail).toMatch(/unknown layer prefix/); }); test("Modeled: c32 file without sibling test is flagged; c31 without sibling is informational", () => { const r = verifySama({ ...baseInput, srcPaths: ["c32_logic.ts", "c31_model.ts"], contents: new Map([ ["c32_logic.ts", "export const x = 1;"], ["c31_model.ts", "export const y = 2;"], ]), }); const modeled = r.checks.find((c) => c.property === "Modeled")!; expect(modeled.passed).toBe(false); expect(modeled.violations.length).toBe(1); expect(modeled.violations[0]?.file).toBe("c32_logic.ts"); expect(modeled.note).toMatch(/c31_\* file/); }); test("Modeled: c32 file with sibling test passes", () => { const r = verifySama({ ...baseInput, srcPaths: ["c32_logic.ts", "c32_logic.test.ts"], contents: new Map([ ["c32_logic.ts", "export const x = 1;"], ["c32_logic.test.ts", "test('x', () => { expect(true).toBe(true); });"], ]), }); const modeled = r.checks.find((c) => c.property === "Modeled")!; expect(modeled.passed).toBe(true); }); test("Atomic: file over 700 lines is flagged", () => { const big = "// line\n".repeat(800); const r = verifySama({ ...baseInput, srcPaths: ["c21_huge.ts"], contents: new Map([["c21_huge.ts", big]]), }); const atomic = r.checks.find((c) => c.property === "Atomic")!; expect(atomic.passed).toBe(false); expect(atomic.violations[0]?.detail).toMatch(/line/); }); test("Atomic: placeholder test (zero expect calls) is flagged", () => { const placeholderFixture = `test("does nothing", () => { /* TODO */ })`; const r = verifySama({ ...baseInput, srcPaths: ["c32_x.test.ts"], contents: new Map([["c32_x.test.ts", placeholderFixture]]), }); const atomic = r.checks.find((c) => c.property === "Atomic")!; expect(atomic.passed).toBe(false); expect(atomic.violations[0]?.detail).toMatch(/placeholder test/); }); test("overallPassed reflects every check passing", () => { const r = verifySama({ ...baseInput, srcPaths: ["c31_model.ts", "c32_logic.ts", "c32_logic.test.ts"], contents: new Map([ ["c31_model.ts", "export const x = 1;"], ["c32_logic.ts", `import { x } from "./c31_model.ts";\nexport const y = x + 1;`], ["c32_logic.test.ts", `import { y } from "./c32_logic.ts";\ntest("y", () => { expect(y).toBe(2); });`], ]), }); expect(r.overallPassed).toBe(true); });