/*
RFC-0479: PBT test for the rfc-0479 bootstrapping migrator — verifies
idempotency (f(f(x)) == f(x)) over the pin cursor transformation.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-0479: initial PBT test for bootstrapping migrator.
*/
import { test, expect } from "vitest";
import fc from "fast-check";
import fs from "node:fs/promises";
import path from "node:path";
import os from "node:os";
import { rfc0479Migrator, RFC_0479_MIGRATOR_ID } from "../migrators/rfc-0479.ts";
import type { SternsystemData, MigrationContext } from "../migrators/types.ts";
async function withTempPin(cursor: unknown, fn: (dir: string) => Promise): Promise {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "rfc-0479-pbt-"));
const pinPath = path.join(dir, "system.pin.json");
await fs.writeFile(pinPath, JSON.stringify({ migratorCursor: cursor }, null, 2));
try {
await fn(dir);
} finally {
await fs.rm(dir, { recursive: true, force: true });
}
}
const ctx: MigrationContext = {
systemId: "test",
missionId: "test-mission",
logger: { info: () => {} },
};
test("rfc-0479 migrator is idempotent: f(f(x)) == f(x) for string cursor", async () => {
await fc.asyncProperty(fc.string({ minLength: 1 }), async (version) => {
await withTempPin(version, async (dir) => {
const data: SternsystemData = { rootPath: dir, dataPaths: [] };
const once = await rfc0479Migrator.transform(data, ctx);
const twice = await rfc0479Migrator.transform(once, ctx);
const pin1 = JSON.parse(await fs.readFile(path.join(dir, "system.pin.json"), "utf8"));
expect(pin1.migratorCursor).toEqual([RFC_0479_MIGRATOR_ID]);
// Second application should be a no-op
expect(twice).toEqual(once);
});
});
});
test("rfc-0479 migrator is idempotent: f(f(x)) == f(x) for null cursor", async () => {
await withTempPin(null, async (dir) => {
const data: SternsystemData = { rootPath: dir, dataPaths: [] };
const once = await rfc0479Migrator.transform(data, ctx);
const twice = await rfc0479Migrator.transform(once, ctx);
const pin = JSON.parse(await fs.readFile(path.join(dir, "system.pin.json"), "utf8"));
expect(pin.migratorCursor).toEqual([RFC_0479_MIGRATOR_ID]);
expect(twice).toEqual(once);
});
});
test("rfc-0479 migrator is idempotent: f(f(x)) == f(x) for array cursor", async () => {
await withTempPin(["rfc-0479"], async (dir) => {
const data: SternsystemData = { rootPath: dir, dataPaths: [] };
const once = await rfc0479Migrator.transform(data, ctx);
const twice = await rfc0479Migrator.transform(once, ctx);
const pin = JSON.parse(await fs.readFile(path.join(dir, "system.pin.json"), "utf8"));
expect(pin.migratorCursor).toEqual(["rfc-0479"]);
expect(twice).toEqual(once);
});
});