import { assert, assertEquals, assertStringIncludes } from "@std/assert"; import { FAVICON_VERSION, type FaviconFace, faviconHref, faviconLink, faviconPng, faviconStatus, } from "./favicon.ts"; import { faviconSvg } from "./favicon-artwork.ts"; import { FAVICON_FACES } from "./favicon-types.ts"; import { STATUS_COLOR } from "./palette.ts"; Deno.test("faviconStatus: red wins, then orange, and gray never replaces green", () => { assertEquals(faviconStatus([]), "good"); assertEquals(faviconStatus(["unknown"]), "good"); assertEquals(faviconStatus(["good", "unknown"]), "good"); assertEquals(faviconStatus(["warn", "good", "unknown"]), "warn"); assertEquals(faviconStatus(["warn", "bad", "good"]), "bad"); assertEquals(faviconStatus(["bad", "warn"]), "bad"); }); Deno.test("favicon artwork: each face has one matching URL-backed raster icon", () => { const artwork: Record< FaviconFace, { color: string; shape: string; eyes: readonly [number, number]; mouth: string; drop?: number; detail?: string; } > = { good: { color: STATUS_COLOR.good, shape: ``, eyes: [12, 20], mouth: `d="M11 19c2.8 2.6 7.2 2.6 10 0"`, }, warn: { color: STATUS_COLOR.warn, shape: ``, eyes: [13, 19], mouth: `d="M11 20h10"`, drop: 3.2, }, bad: { color: STATUS_COLOR.bad, shape: ``, eyes: [12, 20], mouth: `d="M11 21c2.8-2.6 7.2-2.6 10 0"`, }, "bad-crying": { color: STATUS_COLOR.bad, shape: ``, eyes: [12, 20], mouth: `d="M10.5 22c3-4 8-4 11 0"`, detail: `fill="#9edcff"`, }, }; for (const status of FAVICON_FACES) { const { color, shape, eyes, mouth, drop, detail } = artwork[status]; assertEquals( faviconHref(status), `/favicon.png?status=${status}&v=${FAVICON_VERSION}`, ); if (status !== "bad-crying") { const link = faviconLink(status); assertStringIncludes( link, `type="image/png" sizes="32x32" href="/favicon.png?status=${status}&v=${FAVICON_VERSION}"`, ); assertEquals((link.match(/rel="icon"/g) ?? []).length, 1); assert(!link.includes("image/svg+xml")); } const svg = faviconSvg(status); assertStringIncludes(svg, `fill="${color}"`); assertStringIncludes(svg, shape); assertStringIncludes(svg, ``); } if (detail) assertStringIncludes(svg, detail); if (status === "bad-crying") { assertStringIncludes(svg, `d="M12 16.5`); assertEquals((svg.match(/fill="#9edcff"/g) ?? []).length, 1); assert(!svg.includes(`d="M20 16.5`), "the right eye has no tear"); } if (status !== "good") { assert( !svg.includes(`d="M11 19c2.8 2.6 7.2 2.6 10 0"`), `${status} has no smile`, ); } } }); Deno.test("faviconPng: each status has a distinct 32-pixel PNG and unsupported statuses stay green", () => { const signature = new Uint8Array([ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, ]); const encoded: string[] = []; for (const status of FAVICON_FACES) { const png = new Uint8Array(faviconPng(status)); assertEquals(png.slice(0, signature.length), signature); const view = new DataView(png.buffer, png.byteOffset, png.byteLength); assertEquals(view.getUint32(16), 32); assertEquals(view.getUint32(20), 32); encoded.push(png.toBase64()); } assertEquals(new Set(encoded).size, 4); assertEquals( new Uint8Array(faviconPng("unknown")), new Uint8Array(faviconPng("good")), ); assertEquals( new Uint8Array(faviconPng(null)), new Uint8Array(faviconPng("good")), ); }); Deno.test("favicon cache version is derived from all generated PNGs", async () => { const encoded = FAVICON_FACES.map((face) => `${face}\0${new Uint8Array(faviconPng(face)).toBase64()}` ).join("\0"); const digest = new Uint8Array( await crypto.subtle.digest("SHA-256", new TextEncoder().encode(encoded)), ); const expected = Array.from( digest, (byte) => byte.toString(16).padStart(2, "0"), ).join(""); assertEquals(FAVICON_VERSION, expected); });