import { describe, expect, test } from "bun:test"; import { motifs, sagas, songs } from "../src/data/sample"; import { gapYears, motifsInSong, sagaOf, songsWithMotif } from "../src/data/query"; describe("sample data", () => { test("every song references a known saga", () => { const ids = new Set(sagas.map((s) => s.id)); for (const song of songs) expect(ids.has(song.sagaId)).toBe(true); }); test("every part motif id exists", () => { const ids = new Set(motifs.map((m) => m.id)); for (const song of songs) for (const part of song.parts) for (const id of part.motifIds) expect(ids.has(id)).toBe(true); }); test("every motif appears in at least one song", () => { for (const m of motifs) expect(songsWithMotif(m.id).length).toBeGreaterThanOrEqual(1); }); test("saga coverage", () => { expect(songs.filter((s) => s.sagaId === "troy")).toHaveLength(5); expect(songs.filter((s) => s.sagaId === "cyclops")).toHaveLength(4); expect(songs.filter((s) => s.sagaId !== "troy" && s.sagaId !== "cyclops").length).toBeGreaterThanOrEqual(1); }); test("every song has parts, facts and videos", () => { for (const s of songs) { expect(s.parts.length).toBeGreaterThanOrEqual(1); expect(s.facts.length).toBeGreaterThanOrEqual(1); expect(s.videos.length).toBeGreaterThanOrEqual(1); } }); test("songs are sorted by track and the first gap is non-negative", () => { const tracks = songs.map((s) => s.track); expect(tracks).toEqual([...tracks].sort((a, b) => a - b)); expect(gapYears(songs[0]!, songs[1]!)).toBeGreaterThanOrEqual(0); }); test("ids are unique", () => { for (const list of [songs, motifs, sagas]) expect(new Set(list.map((x) => x.id)).size).toBe(list.length); }); test("motif mix and distinct colours", () => { expect(motifs.filter((m) => m.kind === "motif").length).toBeGreaterThanOrEqual(4); expect(motifs.filter((m) => m.kind === "character").length).toBeGreaterThanOrEqual(3); expect(new Set(motifs.map((m) => m.color)).size).toBe(motifs.length); }); test("a later song reuses an earlier motif", () => { const later = songs.filter((s) => s.sagaId !== "troy" && s.sagaId !== "cyclops"); const earlier = new Set(songs.filter((s) => s.sagaId === "troy" || s.sagaId === "cyclops").flatMap((s) => motifsInSong(s).map((m) => m.id))); expect(later.some((s) => motifsInSong(s).some((m) => earlier.has(m.id)))).toBe(true); }); test("motifsInSong is unique and in first-appearance order; sagaOf resolves", () => { const s = songs[0]!; const ids = motifsInSong(s).map((m) => m.id); expect(new Set(ids).size).toBe(ids.length); expect(ids).toEqual([...new Set(s.parts.flatMap((p) => p.motifIds))]); expect(sagaOf(s).id).toBe(s.sagaId); }); });