/*
RFC-1051: test fingerprint normalizers — determinism, known input/output, edge cases.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1051: initial normalizer tests.
*/
import { test, expect } from "vitest";
import { normalizeText } from "../normalizers/text.ts";
import { normalizeBinary } from "../normalizers/binary.ts";
import { normalizeJson } from "../normalizers/json.ts";
import { normalizeJsonStable } from "../normalizers/json-stable.ts";
import { normalizeJsonc } from "../normalizers/jsonc.ts";
import { normalizeCss } from "../normalizers/css.ts";
import { normalizeYaml } from "../normalizers/yaml.ts";
import { normalizeMarkdown } from "../normalizers/markdown.ts";
import { normalizeAstro } from "../normalizers/astro.ts";
import { normalizeTypeScript } from "../normalizers/typescript.ts";
import { normalizeSourceMap } from "../normalizers/sourcemap.ts";
import { normalizePdf } from "../normalizers/pdf.ts";
import { normalizeFileStable } from "../normalizers/stable.ts";
test("normalizeText is deterministic — same input → same output", () => {
const input = "hello world\n";
expect(normalizeText(input)).toBe(normalizeText(input));
});
test("normalizeText normalizes CRLF to LF", () => {
const a = normalizeText("line1\r\nline2\r\n");
const b = normalizeText("line1\nline2\n");
expect(a).toBe(b);
});
test("normalizeBinary is deterministic", () => {
const bytes = new Uint8Array([1, 2, 3, 4, 5]);
expect(normalizeBinary(bytes)).toBe(normalizeBinary(bytes));
});
test("normalizeBinary produces different hashes for different inputs", () => {
const a = new Uint8Array([1, 2, 3]);
const b = new Uint8Array([3, 2, 1]);
expect(normalizeBinary(a)).not.toBe(normalizeBinary(b));
});
test("normalizeJson is deterministic for equivalent JSON", () => {
const a = normalizeJson('{"b":2,"a":1}');
const b = normalizeJson('{"a":1,"b":2}');
expect(a).toBe(b);
});
test("normalizeJson throws on invalid JSON", () => {
expect(() => normalizeJson("{invalid}")).toThrow();
});
test("normalizeJsonStable is deterministic", () => {
const a = normalizeJsonStable('{"b":2,"a":1}');
const b = normalizeJsonStable('{"a":1,"b":2}');
expect(a).toBe(b);
});
test("normalizeJsonc handles comments and trailing commas", () => {
const input = '{\n // comment\n "a": 1,\n}';
expect(() => normalizeJsonc(input)).not.toThrow();
});
test("normalizeCss is deterministic", () => {
const css = "body { color: red; }";
expect(normalizeCss(css)).toBe(normalizeCss(css));
});
test("normalizeYaml is deterministic", () => {
const yaml = "key: value\nlist:\n - item1\n - item2\n";
expect(normalizeYaml(yaml)).toBe(normalizeYaml(yaml));
});
test("normalizeMarkdown is deterministic", () => {
const md = "# Title\n\nSome content\n";
expect(normalizeMarkdown(md)).toBe(normalizeMarkdown(md));
});
test("normalizeAstro is deterministic", async () => {
const astro = "---\nfrontmatter: value\n---\n\nContent";
const a = await normalizeAstro(astro);
const b = await normalizeAstro(astro);
expect(a).toBe(b);
});
test("normalizeTypeScript is deterministic", () => {
const ts = "export const x: number = 42;\n";
expect(normalizeTypeScript(ts)).toBe(normalizeTypeScript(ts));
});
test("normalizeSourceMap is deterministic", () => {
const sm = JSON.stringify({
version: 3,
sources: ["a.ts"],
names: [],
mappings: "AAAA",
});
expect(normalizeSourceMap(sm)).toBe(normalizeSourceMap(sm));
});
test("normalizePdf is deterministic with valid PDF", async () => {
// Use a minimal valid PDF structure
const pdfBytes = new TextEncoder().encode(
"%PDF-1.4\n1 0 obj<>endobj\n2 0 obj<>endobj\n3 0 obj<>endobj\nxref\n0 4\n0000000000 65535 f \n0000000009 00000 n \n0000000058 00000 n \n0000000115 00000 n \ntrailer<>\nstartxref\n190\n%%EOF",
);
const a = await normalizePdf(pdfBytes);
const b = await normalizePdf(pdfBytes);
expect(a).toEqual(b);
});
test("normalizeFileStable is deterministic", async () => {
const bytes = new TextEncoder().encode("some content\n");
const a = await normalizeFileStable("/test.txt", bytes);
const b = await normalizeFileStable("/test.txt", bytes);
expect(a).toEqual(b);
});
test("all normalizers produce sha256-prefixed hashes", () => {
const text = "test";
const result = normalizeText(text);
expect(result).toMatch(/^sha256:[0-9a-f]{64}$/);
});