/* Unit tests for validate declarations covering RFC-1173: collectDeclarationDiagnostics — MUTATES-STATE-DECLARED; RFC-1173: collectDeclarationDiagnostics — MUTATES-STATE-WRITES-MISMATCH. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the validate suite's contract for test-file scaffold coverage. */ import "./load-verification.test.ts"; import { describe, expect, it, vi } from "vitest"; import type { CommandDeclaration } from "@warpgogol/werkstatt-shared/kernel"; import { collectDeclarationDiagnostics, validateDeclarations } from "../validate-declarations.ts"; function baseCommand(over: Partial = {}): CommandDeclaration { return { name: "sample.validate", modulePath: "packages/x/src/checks/sample-validate.ts", description: "sample validator", scope: "workspace", flags: {}, mutatesState: false, contract: "sample", rules: [], execute: async () => ({ data: null, exitCode: 0, summary: "ok" }), ...over, }; } describe("RFC-1173: collectDeclarationDiagnostics — MUTATES-STATE-DECLARED", () => { it("emits an error diagnostic when mutatesState is absent", () => { const cmd = baseCommand(); delete (cmd as { mutatesState?: boolean }).mutatesState; const commands = new Map([[cmd.name, cmd]]); const diagnostics = collectDeclarationDiagnostics(commands); const hit = diagnostics.find( (d) => d.ruleId === "MUTATES-STATE-DECLARED" && d.command === "sample.validate", ); expect(hit).toBeDefined(); expect(hit?.severity).toBe("error"); expect(hit?.message).toContain("mutatesState"); }); it("is silent for both mutating and read-only declarations", () => { const commands = new Map([ ["a.validate", baseCommand({ name: "a.validate", mutatesState: false })], [ "b.generate", baseCommand({ name: "b.generate", mutatesState: true, generates: [{ path: "dist/x.js", phase: "build.post" }], }), ], ]); const diagnostics = collectDeclarationDiagnostics(commands); expect(diagnostics.filter((d) => d.ruleId === "MUTATES-STATE-DECLARED")).toHaveLength(0); }); it("skips non-platform registrations without modulePath", () => { const cmd = baseCommand({ modulePath: undefined }); delete (cmd as { mutatesState?: boolean }).mutatesState; const commands = new Map([[cmd.name, cmd]]); const diagnostics = collectDeclarationDiagnostics(commands); expect(diagnostics.find((d) => d.ruleId === "MUTATES-STATE-DECLARED")).toBeUndefined(); }); it("validateDeclarations stays warn-only: logs diagnostics, never throws", () => { const cmd = baseCommand(); delete (cmd as { mutatesState?: boolean }).mutatesState; const commands = new Map([[cmd.name, cmd]]); const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); try { expect(() => validateDeclarations(commands)).not.toThrow(); const out = warn.mock.calls.map((c) => String(c[0])).join("\n"); expect(out).toContain("MUTATES-STATE-DECLARED"); expect(out).toContain("sample.validate"); } finally { warn.mockRestore(); } }); }); describe("RFC-1173: collectDeclarationDiagnostics — MUTATES-STATE-WRITES-MISMATCH", () => { it("warns when mutatesState:false but writes are declared", () => { const cmd = baseCommand({ mutatesState: false, writes: ["dist/out.json"] }); const commands = new Map([[cmd.name, cmd]]); const hit = collectDeclarationDiagnostics(commands).find( (d) => d.ruleId === "MUTATES-STATE-WRITES-MISMATCH" && d.command === "sample.validate", ); expect(hit).toBeDefined(); expect(hit?.severity).toBe("warn"); }); it("warns when mutatesState:false but generates are declared", () => { const cmd = baseCommand({ mutatesState: false, generates: [{ path: "dist/x.js", phase: "build.post" }], }); const commands = new Map([[cmd.name, cmd]]); const hit = collectDeclarationDiagnostics(commands).find( (d) => d.ruleId === "MUTATES-STATE-WRITES-MISMATCH" && d.command === "sample.validate", ); expect(hit).toBeDefined(); }); it("is silent when mutatesState matches declared outputs", () => { const commands = new Map([ [ "a.generate", baseCommand({ name: "a.generate", mutatesState: true, generates: [{ path: "dist/x.js", phase: "build.post" }], }), ], ["b.validate", baseCommand({ name: "b.validate", mutatesState: false })], ]); const diagnostics = collectDeclarationDiagnostics(commands); expect(diagnostics.filter((d) => d.ruleId === "MUTATES-STATE-WRITES-MISMATCH")).toHaveLength(0); }); });