/*
Unit tests for validation state covering resolveValidationStatePath; readValidationState; writeValidationState. It also guards the documented public contract and regression-sensitive edge cases.
- 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 validation suite's contract for test-file scaffold coverage.
*/
import { test, expect, describe, beforeEach, afterEach } from "vitest";
import { mkdtempSync, rmSync } from "node:fs";
import { join } from "node:path";
import {
resolveValidationStatePath,
readValidationState,
writeValidationState,
buildValidatorStatesFromSteps,
type ValidationState,
} from "../validation-state.ts";
import type { KernelExecutionReport } from "@warpgogol/werkstatt-shared/kernel";
let tmpDir: string;
beforeEach(() => {
tmpDir = mkdtempSync(join(process.cwd(), "tmp-validation-state-"));
});
afterEach(() => {
rmSync(tmpDir, { recursive: true, force: true });
});
describe("resolveValidationStatePath", () => {
test("joins workspaceRoot with missions//.validation-state.json", () => {
expect(resolveValidationStatePath("/tmp/ws", "m000001")).toBe(
join("/tmp/ws", "missions", "m000001", ".validation-state.json"),
);
});
});
describe("readValidationState", () => {
test("returns null when file does not exist", async () => {
expect(await readValidationState(tmpDir, "m000001")).toBeNull();
});
test("returns parsed state when file exists", async () => {
const state: ValidationState = {
missionId: "m000001",
lastValidatedAt: "2026-01-01T00:00:00Z",
lastValidationStatus: "pass",
validatorStates: [],
};
await writeValidationState(tmpDir, state);
const read = await readValidationState(tmpDir, "m000001");
expect(read).not.toBeNull();
expect(read!.missionId).toBe("m000001");
expect(read!.lastValidationStatus).toBe("pass");
});
});
describe("writeValidationState", () => {
test("writes JSON file with state", async () => {
const state: ValidationState = {
missionId: "m000001",
lastValidatedAt: "2026-01-01T00:00:00Z",
lastValidationStatus: "fail",
validatorStates: [{ commandName: "test.validate", status: "fail", cached: false }],
};
await writeValidationState(tmpDir, state);
const read = await readValidationState(tmpDir, "m000001");
expect(read!.validatorStates).toHaveLength(1);
expect(read!.validatorStates[0]!.commandName).toBe("test.validate");
});
});
describe("buildValidatorStatesFromSteps", () => {
test("returns empty array for empty steps", () => {
expect(buildValidatorStatesFromSteps([])).toEqual([]);
});
test("maps ok report to pass status", () => {
const steps: KernelExecutionReport[] = [
{
commandName: "test.validate",
exitCode: 0,
ok: true,
summary: "ok",
metadata: {} as never,
logs: [],
timing: { durationMs: 100, exceededTimeout: false },
filesModified: [],
},
];
const states = buildValidatorStatesFromSteps(steps);
expect(states).toHaveLength(1);
expect(states[0]!.status).toBe("pass");
expect(states[0]!.commandName).toBe("test.validate");
expect(states[0]!.cached).toBe(false);
expect(states[0]!.durationMs).toBe(100);
});
test("maps failed report to fail status", () => {
const steps: KernelExecutionReport[] = [
{
commandName: "test.validate",
exitCode: 1,
ok: false,
summary: "fail",
metadata: {} as never,
logs: [],
timing: { durationMs: 50, exceededTimeout: false },
filesModified: [],
},
];
const states = buildValidatorStatesFromSteps(steps);
expect(states[0]!.status).toBe("fail");
});
test("maps logSummary to diagnosticCounts", () => {
const steps: KernelExecutionReport[] = [
{
commandName: "test.validate",
exitCode: 0,
ok: true,
summary: "ok",
metadata: {} as never,
logs: [],
timing: { durationMs: 10, exceededTimeout: false },
filesModified: [],
logSummary: { error: 1, warning: 2, notice: 3, expectedFallback: 0, suppressedDebug: 0 },
},
];
const states = buildValidatorStatesFromSteps(steps);
expect(states[0]!.diagnosticCounts).toEqual({ error: 1, warning: 2, info: 3 });
});
test("detects fromCache flag", () => {
const steps: KernelExecutionReport[] = [
{
commandName: "test.validate",
exitCode: 0,
ok: true,
summary: "ok",
metadata: {} as never,
logs: [],
timing: { durationMs: 10, exceededTimeout: false, fromCache: true } as never,
filesModified: [],
},
];
const states = buildValidatorStatesFromSteps(steps);
expect(states[0]!.cached).toBe(true);
});
});