import { test } from "node:test"; import assert from "node:assert/strict"; import { computeLineHash } from "./hash.ts"; const ALLOWED = new Set("0123456789ABCDEFGHJKMNPQRSTVWXYZ"); test("computeLineHash is stable and uses the configured base32 length", () => { const a = computeLineHash(3, "code", 4); const b = computeLineHash(3, "code", 4); assert.equal(a, b); assert.equal(a.length, 4); for (const ch of a) assert.ok(ALLOWED.has(ch), `bad char ${ch}`); for (let i = 0; i < 2000; i++) { const hash = computeLineHash(i + 1, `line ${i}`, 4); for (const ch of hash) assert.ok(ALLOWED.has(ch), `bad char ${ch} in ${hash}`); } for (let i = 1; i <= 20; i++) { assert.equal(computeLineHash(i, `content ${i}`, 8).length, 8); } }); test("different line number → different hash (even for identical content)", () => { assert.notEqual(computeLineHash(2, "", 4), computeLineHash(5, "", 4)); assert.notEqual(computeLineHash(1, "}", 4), computeLineHash(2, "}", 4)); }); test("different content → different hash", () => { assert.notEqual(computeLineHash(1, "a", 4), computeLineHash(1, "b", 4)); }); test("truncated checksums can collide", () => { assert.equal(computeLineHash(1, "const value = 558;", 4), "TM02"); assert.equal(computeLineHash(1, "const value = 9344;", 4), "TM02"); }); test("computeLineHash produces output identical to hashing full interpolated string", () => { function referenceHash(line: number, content: string, len: number): string { let h = 0x811c9dc5; const str = `${line}\n${content}`; for (let i = 0; i < str.length; i++) { h ^= str.charCodeAt(i); h = Math.imul(h, 0x01000193); } let s = ""; const BASE32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; let n = h >>> 0; for (let i = 0; i < len; i++) { s = BASE32[n & 31] + s; n = n >>> 5; } return s; } for (const line of [1, 9, 10, 99, 100, 999, 10000]) { for (const content of [ "", "a", "function test() {}", "long line with symbols !@#$%^&*()_+-=[]{}|;:,.<>?/`~", ]) { assert.equal(computeLineHash(line, content, 4), referenceHash(line, content, 4)); assert.equal(computeLineHash(line, content, 6), referenceHash(line, content, 6)); } } });