tests/quranRefs.test.ts
Rama main · réplica de lectura del repositorio original.
// Quran references (shared/quranRefs.ts) and the verse data beside them.
//
// Two kinds of claim. The GRAMMAR — `2:255`, a range, a name in either
// script, a verse the surah does not have — is what the editor's popup, the
// reading renderer and the blog all parse through, so it is pinned here once.
// The TABLE is data copied by hand, and a wrong ayah count is the quiet kind
// of bug: `2:287` would render nothing and say nothing. So every one of the
// 114 counts is checked against the Tanzil text itself, and the text is
// checked against the mushaf's total.
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { describe, it } from "node:test";
import {
AYAH_COUNT,
findSurah,
formatAyahRef,
matchSurahs,
parseAyahRef,
SURAHS,
} from "../shared/quranRefs.ts";
const DATA_URL = new URL("../client/data/quran-uthmani.json", import.meta.url);
describe("the surah table", () => {
it("has 114 rows, numbered in order", () => {
assert.equal(SURAHS.length, 114);
SURAHS.forEach((s, i) => assert.equal(s.n, i + 1));
});
it("knows the ayah counts a reader would check first", () => {
assert.equal(SURAHS[0].ayahs, 7);
assert.equal(SURAHS[1].ayahs, 286);
assert.equal(SURAHS[113].ayahs, 6);
assert.equal(SURAHS[35].ayahs, 83);
});
it("sums to the mushaf's 6236 verses", () => {
assert.equal(
SURAHS.reduce((n, s) => n + s.ayahs, 0),
AYAH_COUNT,
);
});
});
describe("the verse data (client/data/quran-uthmani.json)", () => {
const doc = JSON.parse(readFileSync(DATA_URL, "utf8")) as {
source: string;
license: string;
verses: string[][];
};
it("holds 6236 verses in 114 surahs, and credits Tanzil", () => {
assert.equal(doc.verses.length, 114);
assert.equal(
doc.verses.reduce((n, s) => n + s.length, 0),
AYAH_COUNT,
);
assert.match(doc.source, /tanzil\.net/);
assert.match(doc.license, /Attribution/);
});
it("agrees with the table on every surah's count", () => {
SURAHS.forEach((s, i) => {
assert.equal(doc.verses[i].length, s.ayahs, `surah ${s.n} (${s.en})`);
});
});
it("is the Uthmani script, pointed", () => {
// Ayat al-Kursi opens with «ٱللَّهُ» — the alef wasla (U+0671) is
// Uthmani's mark, and the shadda + fatha on the second lam are the
// pointing. Matched by code point rather than by a pasted literal,
// because two editors normalise the mark order two ways.
assert.match(doc.verses[1][254], /^ٱلل[َّ]{2}هُ /);
// Every verse has letters and none is empty.
for (const surah of doc.verses) for (const v of surah) assert.ok(/[-ۿ]/.test(v));
});
});
describe("findSurah", () => {
it("takes a number, an Arabic name or a transliteration", () => {
assert.equal(findSurah("2")?.n, 2);
assert.equal(findSurah("114")?.n, 114);
assert.equal(findSurah("البقرة")?.n, 2);
assert.equal(findSurah("بقرة")?.n, 2);
assert.equal(findSurah("الْبَقَرَة")?.n, 2);
assert.equal(findSurah("سورة البقرة")?.n, 2);
assert.equal(findSurah("Al-Baqarah")?.n, 2);
assert.equal(findSurah("al baqara")?.n, 2);
assert.equal(findSurah("Baqarah")?.n, 2);
assert.equal(findSurah("Surah Al-Kahf")?.n, 18);
});
it("is not fooled by article-shaped syllables", () => {
assert.equal(findSurah("Anbiya")?.n, 21);
assert.equal(findSurah("An'am")?.n, 6);
assert.equal(findSurah("Ash-Shura")?.n, 42);
assert.equal(findSurah("shura")?.n, 42);
assert.equal(findSurah("Adh-Dhariyat")?.n, 51);
assert.equal(findSurah("Nas")?.n, 114);
assert.equal(findSurah("Nasr")?.n, 110);
});
it("knows the common alternate spellings", () => {
assert.equal(findSurah("Imran")?.n, 3);
assert.equal(findSurah("Al-Imran")?.n, 3);
assert.equal(findSurah("Fatiha")?.n, 1);
assert.equal(findSurah("Yaseen")?.n, 36);
assert.equal(findSurah("Taha")?.n, 20);
assert.equal(findSurah("Ikhlas")?.n, 112);
assert.equal(findSurah("آل عمران")?.n, 3);
assert.equal(findSurah("ال عمران")?.n, 3);
assert.equal(findSurah("يس")?.n, 36);
});
it("answers null to numbers off the end and names it has never heard", () => {
assert.equal(findSurah("0"), null);
assert.equal(findSurah("115"), null);
assert.equal(findSurah("Genesis"), null);
assert.equal(findSurah("التكوين"), null);
assert.equal(findSurah(""), null);
});
});
describe("parseAyahRef", () => {
it("reads surah:ayah with a number", () => {
assert.deepEqual(parseAyahRef("2:255"), { surah: 2, from: 255, to: 255 });
assert.deepEqual(parseAyahRef(" 1:1 "), { surah: 1, from: 1, to: 1 });
assert.deepEqual(parseAyahRef("114:6"), { surah: 114, from: 6, to: 6 });
});
it("reads a range with any dash", () => {
assert.deepEqual(parseAyahRef("2:255-257"), { surah: 2, from: 255, to: 257 });
assert.deepEqual(parseAyahRef("2:255–257"), { surah: 2, from: 255, to: 257 });
assert.deepEqual(parseAyahRef("2:255 — 257"), { surah: 2, from: 255, to: 257 });
});
it("reads names in either script, with any separator", () => {
assert.deepEqual(parseAyahRef("الفاتحة:1"), { surah: 1, from: 1, to: 1 });
assert.deepEqual(parseAyahRef("البقرة ٢٥٥"), { surah: 2, from: 255, to: 255 });
assert.deepEqual(parseAyahRef("البقرة: ٢٥٥-٢٥٧"), { surah: 2, from: 255, to: 257 });
assert.deepEqual(parseAyahRef("Al-Baqarah 255"), { surah: 2, from: 255, to: 255 });
assert.deepEqual(parseAyahRef("Ali 'Imran 33"), { surah: 3, from: 33, to: 33 });
assert.deepEqual(parseAyahRef("آل عمران ٣٣"), { surah: 3, from: 33, to: 33 });
assert.deepEqual(parseAyahRef("Yusuf/4"), { surah: 12, from: 4, to: 4 });
assert.deepEqual(parseAyahRef("2:255"), { surah: 2, from: 255, to: 255 });
});
it("refuses a verse the surah does not have, and a backwards range", () => {
assert.equal(parseAyahRef("2:287"), null);
assert.equal(parseAyahRef("1:0"), null);
assert.equal(parseAyahRef("2:257-255"), null);
assert.equal(parseAyahRef("2:255-300"), null);
assert.equal(parseAyahRef("115:1"), null);
});
it("refuses what is not a reference at all", () => {
assert.equal(parseAyahRef(""), null);
assert.equal(parseAyahRef("Ayat al-Kursi"), null);
assert.equal(parseAyahRef("2"), null);
assert.equal(parseAyahRef("2:"), null);
assert.equal(parseAyahRef("Bukhari 1"), null);
});
});
describe("formatAyahRef", () => {
it("captions in the chrome's language and numerals", () => {
const one = { surah: 2, from: 255, to: 255 };
const range = { surah: 2, from: 255, to: 257 };
assert.equal(formatAyahRef(one, "ar"), "البقرة ٢٥٥");
assert.equal(formatAyahRef(range, "ar"), "البقرة ٢٥٥–٢٥٧");
assert.equal(formatAyahRef(one, "en"), "Al-Baqarah 2:255");
assert.equal(formatAyahRef(range, "en"), "Al-Baqarah 2:255–257");
});
});
describe("matchSurahs (the popup inside `> [!ayah] `)", () => {
it("lists all 114 for nothing typed, in mushaf order", () => {
assert.equal(matchSurahs("").length, 114);
assert.equal(matchSurahs("")[0].n, 1);
});
it("narrows by number, by Arabic and by transliteration, prefixes first", () => {
assert.deepEqual(matchSurahs("11").map((s) => s.n), [11, 110, 111, 112, 113, 114]);
assert.equal(matchSurahs("الب")[0].n, 2);
assert.equal(matchSurahs("ب")[0].n, 2);
assert.equal(matchSurahs("baq")[0].n, 2);
assert.equal(matchSurahs("al-baq")[0].n, 2);
assert.equal(matchSurahs("kahf")[0].n, 18);
// "al" is every Al-: the writer typed the article, not a name yet.
assert.ok(matchSurahs("al").length > 50);
assert.deepEqual(matchSurahs("zzz"), []);
});
});