import { test, expect } from "vitest";
import { mkdtemp, rm, readFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
resolveValidationStatePath,
readValidationState,
writeValidationState,
buildValidatorStatesFromSteps,
type ValidationState,
} from "../validation-state.ts";
import type { KernelExecutionReport } from "@warpgogol/werkstatt-shared/kernel";
/*
RFC-1028: Test validation-state.ts — path resolution, read/write round-trip,
and buildValidatorStatesFromSteps conversion.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1028: initial tests for validation-state.ts helpers.
*/
test("resolveValidationStatePath produces correct path", () => {
const result = resolveValidationStatePath("/workspace", "m000123");
expect(result).toBe(join("/workspace", "missions", "m000123", ".validation-state.json"));
});
test("writeValidationState creates file and readValidationState reads it back", async () => {
const tmpDir = await mkdtemp(join(tmpdir(), "rfc1028-"));
try {
const state: ValidationState = {
missionId: "m-test",
lastValidatedAt: "2025-01-01T00:00:00Z",
lastValidationStatus: "pass",
validatorStates: [
{
commandName: "test.check",
status: "pass",
cached: false,
durationMs: 100,
},
],
};
await writeValidationState(tmpDir, state);
const read = await readValidationState(tmpDir, "m-test");
expect(read).toEqual(state);
// Verify file content is valid JSON with newline
const raw = await readFile(
join(tmpDir, "missions", "m-test", ".validation-state.json"),
"utf-8",
);
expect(raw.endsWith("\n")).toBe(true);
expect(JSON.parse(raw)).toEqual(state);
} finally {
await rm(tmpDir, { recursive: true, force: true });
}
});
test("readValidationState returns null when file does not exist", async () => {
const tmpDir = await mkdtemp(join(tmpdir(), "rfc1028-"));
try {
const read = await readValidationState(tmpDir, "nonexistent");
expect(read).toBeNull();
} finally {
await rm(tmpDir, { recursive: true, force: true });
}
});
test("buildValidatorStatesFromSteps converts KernelExecutionReport[] to ValidatorState[]", () => {
const steps: KernelExecutionReport[] = [
{
commandName: "check.ownership",
exitCode: 0,
ok: true,
metadata: {} as never,
logs: [],
timing: { durationMs: 50, exceededTimeout: false, fromCache: true } as never,
logSummary: { error: 0, warning: 2, notice: 1, expectedFallback: 0, suppressedDebug: 0 },
},
{
commandName: "check.content",
exitCode: 1,
ok: false,
metadata: {} as never,
logs: [],
timing: { durationMs: 200, exceededTimeout: false, fromCache: false } as never,
logSummary: { error: 3, warning: 0, notice: 0, expectedFallback: 0, suppressedDebug: 0 },
},
];
const result = buildValidatorStatesFromSteps(steps);
expect(result).toHaveLength(2);
expect(result[0]).toEqual({
commandName: "check.ownership",
status: "pass",
cached: true,
durationMs: 50,
diagnosticCounts: { error: 0, warning: 2, info: 1 },
});
expect(result[1]).toEqual({
commandName: "check.content",
status: "fail",
cached: false,
durationMs: 200,
diagnosticCounts: { error: 3, warning: 0, info: 0 },
});
});
test("buildValidatorStatesFromSteps handles empty array", () => {
const result = buildValidatorStatesFromSteps([]);
expect(result).toEqual([]);
});
test("buildValidatorStatesFromSteps handles missing logSummary", () => {
const steps: KernelExecutionReport[] = [
{
commandName: "check.basic",
exitCode: 0,
ok: true,
metadata: {} as never,
logs: [],
timing: { durationMs: 10, exceededTimeout: false } as never,
},
];
const result = buildValidatorStatesFromSteps(steps);
expect(result[0].diagnosticCounts).toBeUndefined();
expect(result[0].cached).toBe(false);
});