Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

scripts/readme/banner.test.ts

Raw
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { ROOT } from "../lib/common.ts";
import {
	DEFAULT_BANNER,
	FONT_CHARS,
	initials,
	type NuguPalette,
	renderBanner,
} from "./banner.ts";
import { extensionDirs } from "./banners.ts";

const palette = JSON.parse(
	readFileSync(join(ROOT, "assets", "nugu.json"), "utf8"),
) as NuguPalette;

/** Geometry only: strip every colour so two renders can be compared for shape. */
const shape = (svg: string) =>
	svg.replaceAll(/fill="[^"]*"/g, "").replaceAll(/#(?:dark|light)/g, "");

describe("README banner", () => {
	it("executes CLI entrypoint and rejects an unknown extension", () => {
		const result = spawnSync(
			process.execPath,
			[join(ROOT, "scripts/readme/banners.ts"), "__missing_banner_cli_probe__"],
			{ cwd: ROOT, encoding: "utf8", timeout: 10_000 },
		);
		expect(result.error).toBeUndefined();
		expect(result.status).not.toBe(0);
		expect(result.stderr).toContain(
			"unknown extension: __missing_banner_cli_probe__",
		);
	});

	it("derives initials from the first and last hyphen part", () => {
		expect(initials("klaus")).toEqual(["k"]);
		expect(initials("git-safe")).toEqual(["g", "s"]);
		expect(initials("the-system")).toEqual(["t", "s"]);
		expect(initials("nu-bang")).toEqual(["n", "b"]);
	});

	it("is deterministic and theme-complete", () => {
		const a = renderBanner("ultra", palette);
		expect(renderBanner("ultra", palette)).toBe(a);
		expect(a).toContain('id="dark"');
		expect(a).toContain('id="light"');
		expect(a).toContain("prefers-color-scheme: light");
		expect(a).toMatch(/^<svg xmlns="http:\/\/www\.w3\.org\/2000\/svg"/);
		expect(a.trimEnd().endsWith("</svg>")).toBe(true);
		expect(a).not.toContain("<text");
	});

	it("changes colour but never geometry across versions", () => {
		const v0 = renderBanner("ultra", palette, { version: 0 });
		const v5 = renderBanner("ultra", palette, { version: 5 });
		expect(v5).not.toBe(v0);
		expect(shape(v5)).toBe(shape(v0));
	});

	it("changes geometry with the seed", () => {
		const a = renderBanner("ultra", palette, { seed: 1 });
		const b = renderBanner("ultra", palette, { seed: 2 });
		expect(shape(a)).not.toBe(shape(b));
	});

	it("uses only palette-derived colours", () => {
		const svg = renderBanner("the-system", palette);
		const fills = [...svg.matchAll(/fill="([^"]+)"/g)].map((m) => m[1]);
		const allowed = new Set([
			...Object.values(palette.dark.content),
			...Object.values(palette.dark.ui),
			...Object.values(palette.light.content),
			...Object.values(palette.light.ui),
		]);
		for (const fill of fills)
			expect(
				fill === undefined || allowed.has(fill) || fill.startsWith("hsl("),
			).toBe(true);
	});

	it("can set every extension name in its pixel font", () => {
		for (const name of extensionDirs())
			for (const ch of name)
				expect(FONT_CHARS.has(ch), `${name}: ${ch}`).toBe(true);
	});

	it("keeps the agreed defaults", () => {
		expect(DEFAULT_BANNER).toEqual({
			seed: 193_581,
			mutation: 4,
			version: 0,
			drift: 0.5,
			cell: 10,
		});
	});
});