import { describe, expect, test } from "bun:test"; import { escapeXml, renderSitemap, STATIC_PATHS, type SitemapUrl, } from "./b32_sitemap.ts"; describe("escapeXml", () => { test("escapes the five named entities", () => { expect(escapeXml("&")).toBe("&"); expect(escapeXml("<")).toBe("<"); expect(escapeXml(">")).toBe(">"); expect(escapeXml('"')).toBe("""); expect(escapeXml("'")).toBe("'"); }); test("leaves regular URL characters untouched", () => { const s = "https://tdd.md/blog/2026-05/sama-v2-workingset-cross-repo-baseline"; expect(escapeXml(s)).toBe(s); }); test("ampersand always escapes first (no double-escape)", () => { expect(escapeXml("a & b < c")).toBe("a & b < c"); }); }); describe("renderSitemap", () => { test("empty list → valid urlset with no children", () => { const xml = renderSitemap([]); expect(xml).toBe(` `); }); test("single URL with lastmod", () => { const xml = renderSitemap([ { loc: "https://tdd.md/blog/x", lastmod: "2026-05-25" }, ]); expect(xml).toBe(` https://tdd.md/blog/x2026-05-25 `); }); test("single URL without lastmod omits the element", () => { const xml = renderSitemap([{ loc: "https://tdd.md/sama" }]); expect(xml).toContain("https://tdd.md/sama"); expect(xml).not.toContain(""); }); test("multiple URLs preserve input order", () => { const xml = renderSitemap([ { loc: "https://tdd.md/a" }, { loc: "https://tdd.md/b" }, { loc: "https://tdd.md/c" }, ]); const aIdx = xml.indexOf("/a"); const bIdx = xml.indexOf("/b"); const cIdx = xml.indexOf("/c"); expect(aIdx).toBeGreaterThan(-1); expect(aIdx).toBeLessThan(bIdx); expect(bIdx).toBeLessThan(cIdx); }); test("XML-escapes & and < inside values", () => { const xml = renderSitemap([ { loc: "https://tdd.md/q?a=1&b=2" }, { loc: "https://tdd.md/" }, ]); expect(xml).toContain("https://tdd.md/q?a=1&b=2"); expect(xml).toContain("https://tdd.md/<weird>"); expect(xml).not.toContain("a=1&b=2"); }); test("opens with the XML declaration and closes with ", () => { const xml = renderSitemap([{ loc: "https://tdd.md/" }]); expect(xml.startsWith('')).toBe(true); expect(xml.endsWith("")).toBe(true); }); test("deterministic — same input twice → byte-identical output", () => { const urls: ReadonlyArray = [ { loc: "https://tdd.md/", lastmod: "2026-05-25" }, { loc: "https://tdd.md/blog" }, ]; expect(renderSitemap(urls)).toBe(renderSitemap(urls)); }); }); describe("STATIC_PATHS", () => { test("covers the load-bearing routes (incl. /goals + /contributing)", () => { expect(STATIC_PATHS).toEqual([ "/", "/blog", "/contributing", "/games", "/goals", "/leaderboard", "/sama", "/sama/v2", "/sama/v2/verify", "/sama/v2/example-crud", "/sama/v2/example-wordpress", "/sama/skill", "/guides", ]); }); test("each path is absolute (starts with /)", () => { for (const p of STATIC_PATHS) { expect(p.startsWith("/")).toBe(true); } }); });