mirror of
https://github.com/pupperpowell/bibdle.git
synced 2026-06-25 08:45:22 -04:00
Add card components, cards route, xml-bible tests, and progress page update
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
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<string, Map<number, number[]>> {
|
||||
const allVerses = getAllNKJVVerses();
|
||||
const map = new Map<string, Map<number, number[]>>();
|
||||
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");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user