import { describe, test, expect } from "bun:test"; import { getRandomVerses, getRandomVersesFromBook, extractVerses, formatReference, getAllNKJVVerses, } from "$lib/server/xml-bible"; import { bibleBooks } from "$lib/server/bible"; // Build a map of bookName → chapters → verse numbers from the full XML dump. // This is the ground truth of what the XML actually contains. function buildVerseMap(): Map> { const allVerses = getAllNKJVVerses(); const map = new Map>(); for (const { book, chapter, verse } of allVerses) { if (!map.has(book)) map.set(book, new Map()); const chapters = map.get(book)!; if (!chapters.has(chapter)) chapters.set(chapter, []); chapters.get(chapter)!.push(verse); } return map; } const verseMap = buildVerseMap(); // ─── 1. XML data completeness ──────────────────────────────────────────────── describe("XML data completeness — all 66 books present", () => { test("getAllNKJVVerses returns a non-empty array", () => { const verses = getAllNKJVVerses(); expect(verses.length).toBeGreaterThan(30_000); // NKJV has ~31,102 verses }); test("every Bible book appears at least once", () => { const booksInXml = new Set(verseMap.keys()); const missing: string[] = []; for (const book of bibleBooks) { if (!booksInXml.has(book.name)) missing.push(book.name); } expect(missing).toEqual([]); }); test("no book has zero chapters", () => { for (const book of bibleBooks) { const chapters = verseMap.get(book.name); expect(chapters).toBeDefined(); expect(chapters!.size).toBeGreaterThan(0); } }); test("no chapter has zero verses", () => { for (const [bookName, chapters] of verseMap) { for (const [chapterNum, verses] of chapters) { expect(verses.length).toBeGreaterThan(0); } } }); test("verse numbers within each chapter are sequential with no gaps", () => { const gaps: string[] = []; for (const [bookName, chapters] of verseMap) { for (const [chapterNum, verses] of chapters) { const sorted = [...verses].sort((a, b) => a - b); for (let i = 0; i < sorted.length; i++) { if (sorted[i] !== i + 1) { gaps.push(`${bookName} ${chapterNum}: expected verse ${i + 1}, got ${sorted[i]}`); } } } } expect(gaps).toEqual([]); }); }); // ─── 2. Every book can be returned as a daily verse ────────────────────────── describe("getRandomVersesFromBook — every book can produce a daily verse", () => { for (let bookNumber = 1; bookNumber <= 66; bookNumber++) { const book = bibleBooks.find((b) => b.order === bookNumber)!; test(`book ${bookNumber} (${book.name}) returns 3 consecutive verses`, () => { const result = getRandomVersesFromBook(bookNumber, 3); expect(result).not.toBeNull(); expect(result!.bookId).toBe(book.id); expect(result!.bookName).toBe(book.name); expect(result!.chapter).toBeGreaterThan(0); expect(result!.startVerse).toBeGreaterThan(0); expect(result!.endVerse).toBe(result!.startVerse + 2); expect(result!.verses).toHaveLength(3); for (const verse of result!.verses) { expect(verse.length).toBeGreaterThan(0); } }); } }); // ─── 3. Every chapter with ≥ 3 verses is reachable via extractVerses ───────── describe("extractVerses — every eligible chapter is reachable", () => { for (let bookNumber = 1; bookNumber <= 66; bookNumber++) { const book = bibleBooks.find((b) => b.order === bookNumber)!; const chapters = verseMap.get(book.name); if (!chapters) continue; for (const [chapterNum, verses] of chapters) { if (verses.length < 3) continue; // getRandomVerses skips these — that's expected test(`${book.name} ${chapterNum} (${verses.length} verses) — extractVerses returns 3`, () => { const result = extractVerses(bookNumber, chapterNum, 1, 3); expect(result).toHaveLength(3); for (const v of result) { expect(v.length).toBeGreaterThan(0); } }); } } }); // ─── 4. getRandomVerses (the actual daily-verse function) ──────────────────── describe("getRandomVerses", () => { test("returns a well-formed result", () => { const result = getRandomVerses(3); expect(result).not.toBeNull(); expect(bibleBooks.some((b) => b.id === result!.bookId)).toBe(true); expect(result!.chapter).toBeGreaterThan(0); expect(result!.startVerse).toBeGreaterThan(0); expect(result!.endVerse).toBe(result!.startVerse + 2); expect(result!.verses).toHaveLength(3); for (const v of result!.verses) { expect(v.length).toBeGreaterThan(0); } }); test("bookId is always a known Bible book", () => { const knownIds = new Set(bibleBooks.map((b) => b.id)); // Run several times to increase confidence for (let i = 0; i < 20; i++) { const result = getRandomVerses(3); expect(result).not.toBeNull(); expect(knownIds.has(result!.bookId)).toBe(true); } }); }); // ─── 5. formatReference ────────────────────────────────────────────────────── describe("formatReference", () => { test("single verse: Book C:V", () => { expect(formatReference("Genesis", 1, 1, 1)).toBe("Genesis 1:1"); }); test("verse range: Book C:V1-V2", () => { expect(formatReference("Matthew", 5, 3, 5)).toBe("Matthew 5:3-5"); }); });