/*
RFC-0502: PBT test for the rfc-0502 migrator — verifies idempotency
(f(f(x)) == f(x)) by running the migrator twice and checking the result is
identical.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-0502: initial PBT test for rfc-0502 migrator idempotency.
*/
import { test, expect } from "vitest";
import fs from "node:fs/promises";
import path from "node:path";
import os from "node:os";
import { rfc0502Migrator } from "./rfc-0502.ts";
import type { SternsystemData, MigrationContext } from "./types.ts";
function makeCtx(_tmpDir: string): MigrationContext {
return {
systemId: "test-system",
missionId: "test-mission",
logger: {
info: () => {},
},
};
}
function makeData(tmpDir: string): SternsystemData {
return {
rootPath: tmpDir,
dataPaths: [],
};
}
test("rfc-0502 migrator is idempotent — f(f(x)) == f(x)", async () => {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "rfc-0502-pbt-"));
const data = makeData(tmpDir);
const ctx = makeCtx(tmpDir);
try {
const first = await rfc0502Migrator.transform(data, ctx);
const firstAuthorsDir = path.join(tmpDir, "src", "content", "surface", "authors");
const firstFiles = await fs.readdir(firstAuthorsDir).catch(() => []);
const _second = await rfc0502Migrator.transform(first, ctx);
const secondAuthorsDir = path.join(tmpDir, "src", "content", "surface", "authors");
const secondFiles = await fs.readdir(secondAuthorsDir).catch(() => []);
expect(firstFiles.sort()).toEqual(secondFiles.sort());
for (const lang of firstFiles) {
const langDir = path.join(firstAuthorsDir, lang);
const secondLangDir = path.join(secondAuthorsDir, lang);
const firstContent = await fs.readFile(path.join(langDir, "andrii-syrokomskyi.md"), "utf-8");
const secondContent = await fs.readFile(
path.join(secondLangDir, "andrii-syrokomskyi.md"),
"utf-8",
);
expect(firstContent).toBe(secondContent);
}
} finally {
await fs.rm(tmpDir, { recursive: true, force: true });
}
});
test("rfc-0502 migrator creates author record in de and uk", async () => {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "rfc-0502-pbt-"));
const data = makeData(tmpDir);
const ctx = makeCtx(tmpDir);
try {
await rfc0502Migrator.transform(data, ctx);
const deFile = path.join(
tmpDir,
"src",
"content",
"surface",
"authors",
"de",
"andrii-syrokomskyi.md",
);
const ukFile = path.join(
tmpDir,
"src",
"content",
"surface",
"authors",
"uk",
"andrii-syrokomskyi.md",
);
const deContent = await fs.readFile(deFile, "utf-8");
const ukContent = await fs.readFile(ukFile, "utf-8");
expect(deContent).toContain("id: andrii-syrokomskyi");
expect(deContent).toContain('name: "Andrii Syrokomskyi"');
expect(deContent).toContain('role: "Redakteur"');
expect(ukContent).toContain("id: andrii-syrokomskyi");
expect(ukContent).toContain('name: "Andrii Syrokomskyi"');
expect(ukContent).toContain('role: "Редактор"');
} finally {
await fs.rm(tmpDir, { recursive: true, force: true });
}
});
test("rfc-0502 migrator does not overwrite existing author record", async () => {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "rfc-0502-pbt-"));
const data = makeData(tmpDir);
const ctx = makeCtx(tmpDir);
try {
const authorsDir = path.join(tmpDir, "src", "content", "surface", "authors", "de");
await fs.mkdir(authorsDir, { recursive: true });
const customContent = `---
id: andrii-syrokomskyi
name: "Custom Name"
role: "Custom Role"
bio: "Custom bio"
---
`;
await fs.writeFile(path.join(authorsDir, "andrii-syrokomskyi.md"), customContent, "utf-8");
await rfc0502Migrator.transform(data, ctx);
const after = await fs.readFile(path.join(authorsDir, "andrii-syrokomskyi.md"), "utf-8");
expect(after).toBe(customContent);
} finally {
await fs.rm(tmpDir, { recursive: true, force: true });
}
});