import { describe, it, expect } from "vitest"; import { FIFA_2026_R32_TEMPLATE, THIRD_PLACE_SLOTS, assignThirdPlaceSlots, type R32Slot, } from "../fifa-2026-bracket"; const GROUPS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]; describe("FIFA_2026_R32_TEMPLATE", () => { it("has 16 matches with unique DB match numbers 1–16", () => { expect(FIFA_2026_R32_TEMPLATE).toHaveLength(16); const dbNums = FIFA_2026_R32_TEMPLATE.map((m) => m.dbMatchNumber).toSorted((a, b) => a - b); expect(dbNums).toEqual(Array.from({ length: 16 }, (_, i) => i + 1)); }); it("maps onto the official FIFA match numbers 73–88", () => { const fifaNums = FIFA_2026_R32_TEMPLATE.map((m) => m.fifaMatchNumber).toSorted((a, b) => a - b); expect(fifaNums).toEqual(Array.from({ length: 16 }, (_, i) => i + 73)); }); it("uses each group winner and runner-up exactly once across the 32 slots", () => { const winners: string[] = []; const runnersUp: string[] = []; for (const m of FIFA_2026_R32_TEMPLATE) { for (const slot of [m.slot1, m.slot2] as R32Slot[]) { if (slot.kind === "winner") winners.push(slot.group); if (slot.kind === "runnerUp") runnersUp.push(slot.group); } } expect(winners.toSorted()).toEqual(GROUPS); expect(runnersUp.toSorted()).toEqual(GROUPS); }); it("has exactly 8 third-place slots", () => { expect(THIRD_PLACE_SLOTS).toHaveLength(8); }); }); describe("assignThirdPlaceSlots", () => { it("assigns all 8 qualifying thirds to distinct, eligible slots", () => { // Best-8 thirds come from groups A–H (a plausible qualifying set). const qualifying = ["A", "B", "C", "D", "E", "F", "G", "H"]; const assignment = assignThirdPlaceSlots(qualifying); expect(assignment.size).toBe(8); // Every slot filled, each by an eligible & qualifying group, no group reused. const usedGroups = new Set(); for (const slot of THIRD_PLACE_SLOTS) { const group = assignment.get(slot.thirdSlotId) ?? ""; expect(group).not.toBe(""); expect(slot.eligibleGroups).toContain(group); expect(qualifying).toContain(group); expect(usedGroups.has(group)).toBe(false); usedGroups.add(group); } expect(usedGroups.size).toBe(8); }); it("produces a valid matching for every 8-of-12 qualifying combination", () => { // Exhaustively check all C(12,8) = 495 combinations resolve to a complete, // eligibility-respecting, conflict-free assignment. let combinations = 0; const combos = (start: number, chosen: string[]) => { if (chosen.length === 8) { combinations++; const assignment = assignThirdPlaceSlots(chosen); expect(assignment.size).toBe(8); const used = new Set(assignment.values()); expect(used.size).toBe(8); for (const slot of THIRD_PLACE_SLOTS) { const group = assignment.get(slot.thirdSlotId); expect(slot.eligibleGroups).toContain(group); expect(chosen).toContain(group); } return; } for (let i = start; i < GROUPS.length; i++) { combos(i + 1, [...chosen, GROUPS[i]]); } }; combos(0, []); expect(combinations).toBe(495); }); it("is deterministic for a given combination", () => { const qualifying = ["B", "D", "E", "F", "H", "I", "J", "L"]; const a = assignThirdPlaceSlots(qualifying); const b = assignThirdPlaceSlots(qualifying.toReversed()); expect([...a.entries()].toSorted()).toEqual([...b.entries()].toSorted()); }); it("matches FIFA's exact Annex C allocation for option 1 (groups E–L qualify)", () => { // Published row 1: 1A vs 3E, 1B vs 3J, 1D vs 3I, 1E vs 3F, // 1G vs 3H, 1I vs 3G, 1K vs 3L, 1L vs 3K. // Mapped to DB third-slot ids (the match each winner plays in): const assignment = assignThirdPlaceSlots(["E", "F", "G", "H", "I", "J", "K", "L"]); expect(assignment.get(11)).toBe("E"); // winner A's match expect(assignment.get(15)).toBe("J"); // winner B's match expect(assignment.get(7)).toBe("I"); // winner D's match expect(assignment.get(1)).toBe("F"); // winner E's match expect(assignment.get(8)).toBe("H"); // winner G's match expect(assignment.get(2)).toBe("G"); // winner I's match expect(assignment.get(16)).toBe("L"); // winner K's match expect(assignment.get(12)).toBe("K"); // winner L's match }); it("template eligible-group lists exactly match the Annex C table", () => { // For every slot, collect the set of groups the published table ever assigns // to it across all 495 combinations, and assert it equals the hand-written // eligibleGroups list in the template. const observed = new Map>( THIRD_PLACE_SLOTS.map((s) => [s.thirdSlotId, new Set()]) ); const combos = (start: number, chosen: string[]) => { if (chosen.length === 8) { const assignment = assignThirdPlaceSlots(chosen); for (const [slotId, group] of assignment) observed.get(slotId)?.add(group); return; } for (let i = start; i < GROUPS.length; i++) combos(i + 1, [...chosen, GROUPS[i]]); }; combos(0, []); for (const slot of THIRD_PLACE_SLOTS) { expect([...(observed.get(slot.thirdSlotId) ?? [])].toSorted()).toEqual( [...slot.eligibleGroups].toSorted() ); } }); });