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(); });