import { describe, it, expect } from 'vitest'; import { validateFixture } from './validateFixture'; import canonicalFixture from './stammbaum.json'; // The fixture validator is the load-bearing contract for the canonical // Stammbaum snapshot: every gate here corresponds to an invariant that // buildLayout.test.ts relies on. Adding or removing a gate without updating // these tests is the failure we want to catch. function networkWithNodes(count: number) { return { nodes: Array.from({ length: count }, (_, i) => ({ id: `n${i}`, generation: i % 6 })), edges: [] }; } function spouseEdge(a: string, b: string) { return { id: `${a}|${b}`, personId: a, relatedPersonId: b, personDisplayName: '', relatedPersonDisplayName: '', relationType: 'SPOUSE_OF' }; } describe('validateFixture', () => { it('passes_for_the_canonical_fixture', () => { expect(() => validateFixture(canonicalFixture)).not.toThrow(); }); it('rejects_a_fixture_below_the_min_node_floor', () => { expect(() => validateFixture(networkWithNodes(10))).toThrow(/>= 50 nodes/); }); it('rejects_a_fixture_with_no_multi_spouse_person', () => { // 50 nodes, 5 generations, several SPOUSE_OF edges — but every spouse // edge connects a different pair, so nobody has more than one partner. // Without the multi-spouse floor this would silently pass and the // canonical_fixture_assigns_a_position_to_every_node_with_multiple_spouses // test in buildLayout.test.ts would degrade to vacuous truth. const nodes = Array.from({ length: 50 }, (_, i) => ({ id: `n${i}`, generation: i % 5 })); const edges = [spouseEdge('n0', 'n1'), spouseEdge('n2', 'n3'), spouseEdge('n4', 'n5')]; expect(() => validateFixture({ nodes, edges })).toThrow( />= 1 person with multiple SPOUSE_OF edges/ ); }); it('accepts_a_fixture_where_one_person_has_multiple_spouse_edges', () => { const nodes = Array.from({ length: 50 }, (_, i) => ({ id: `n${i}`, generation: i % 5 })); const edges = [spouseEdge('n0', 'n1'), spouseEdge('n0', 'n2')]; expect(() => validateFixture({ nodes, edges })).not.toThrow(); }); it('counts_multi_spouse_persons_via_either_edge_direction', () => { const nodes = Array.from({ length: 50 }, (_, i) => ({ id: `n${i}`, generation: i % 5 })); // n5 is the related party in both edges — still counts as multi-spouse. const edges = [spouseEdge('n1', 'n5'), spouseEdge('n2', 'n5')]; expect(() => validateFixture({ nodes, edges })).not.toThrow(); }); });