import { expect, test } from "bun:test";
import { parse, serialize } from "@chopin/dialect";
import {
newResearchProjections,
protectProjections,
removedResearchProjections,
} from "./projections";
let nodes = (source: string) => parse(source).children;
test.each([
'\n\n\n\n\n\n',
'> \n\n',
])("nested protected identities cannot collide across kinds: %s", source => {
let proposed = nodes(source);
expect(protectProjections([], proposed)).toContain("appears twice");
expect(protectProjections(proposed, [])).toContain("appears twice");
expect(newResearchProjections([], proposed)).toEqual([]);
expect(removedResearchProjections(proposed, [])).toEqual([]);
});
test.each([
"\n\n\n\n",
'',
"> ",
])("missing or empty identity fails closed in either snapshot: %s", source => {
let malformed = nodes(source);
expect(protectProjections([], malformed)).toContain("missing its id");
expect(protectProjections(malformed, [])).toContain("missing its id");
expect(newResearchProjections([], malformed)).toEqual([]);
expect(removedResearchProjections(malformed, [])).toEqual([]);
});
test.each(["Questionnaire", "Decision"])(
"Research exceptions never authorize new or removed %s",
kind => {
let projection = nodes(`<${kind} id="card" />`);
let ids = new Set(["card"]);
expect(protectProjections([], projection, ids, ids)).toContain("cannot be authored");
expect(protectProjections(projection, [], ids, ids)).toContain("cannot be dropped");
},
);
test.each([
['', ''],
[
'Original',
'Changed',
],
['', ''],
])("same identity cannot conceal a changed payload or kind: %s", (before, after) => {
let ids = new Set(["card"]);
expect(protectProjections(nodes(before), nodes(after), ids, ids)).toContain("cannot be altered");
});
test("exact nested projections may move while unrelated prose changes", () => {
let card = 'Original choice';
let before = nodes(`Before.\n\n\n\n${card}\n\n\n\n`);
let after = nodes(`\n\nChanged prose.\n\n${card}`);
let canonical = serialize({ type: "root", children: after });
expect(canonical).toContain("Changed prose.");
expect(protectProjections(before, after)).toBeUndefined();
expect(newResearchProjections(before, after)).toEqual([]);
expect(removedResearchProjections(before, after)).toEqual([]);
});
test("Research additions and removals require the exact IDs in the correct authority sets", () => {
let before = nodes('');
let after = nodes('');
expect(newResearchProjections(before, after)).toEqual(["new"]);
expect(removedResearchProjections(before, after)).toEqual(["old"]);
expect(protectProjections(before, after)).toContain("cannot be dropped");
expect(protectProjections(before, after, new Set(["new"]))).toContain("cannot be dropped");
expect(protectProjections(before, after, new Set(), new Set(["old"])))
.toContain("cannot be authored");
expect(protectProjections(before, after, new Set(["old"]), new Set(["new"])))
.toContain("cannot be dropped");
expect(protectProjections(before, after, new Set(["new"]), new Set(["old"])))
.toBeUndefined();
});