test.govlab/content-fingerprint/core/converters/fingerprint.converter.test.ts
test.govlab/content-fingerprint/core/converters/fingerprint.converter.test.ts is a file in Codebase Testing. 60 lines of code and 0 definitions.
import { ABSENT_SENTINEL, digestOf, fingerprint, fingerprintOf, hashFile } from "@govlab/content-fingerprint";
import {
HASH_ALGORITHM,
HASH_ENCODING,
RECORD_SEPARATOR,
UNIT_SEPARATOR,
} from "@govlab/content-fingerprint/configuration/constants/fingerprint.constants.ts";
import { describe, expect, it } from "vitest";
import { createHash } from "node:crypto";
import { join } from "node:path";
import { withTemp } from "./fingerprint.fixture.ts";
import { writeVerbatim } from "@govlab/canonical-write";
describe("hashFile", () => {
it("hashes file bytes deterministically and returns a sentinel for a missing file", () => {
withTemp((dir) => {
const file = join(dir, "a.txt");
writeVerbatim(file, "one");
expect(hashFile(file)).toBe(createHash(HASH_ALGORITHM).update("one").digest(HASH_ENCODING));
expect(hashFile(join(dir, "missing.txt"))).toBe(ABSENT_SENTINEL);
});
});
});
describe("fingerprint", () => {
it("is independent of input order but sensitive to content", () => {
withTemp((dir) => {
const a = join(dir, "a.txt");
const b = join(dir, "b.txt");
writeVerbatim(a, "alpha");
writeVerbatim(b, "beta");
const forward = fingerprint([a, b]);
expect(fingerprint([b, a])).toBe(forward);
writeVerbatim(b, "beta-changed");
expect(fingerprint([a, b])).not.toBe(forward);
});
});
it("folds each path and its content hash between the unit and record separators", () => {
withTemp((dir) => {
const a = join(dir, "a.txt");
writeVerbatim(a, "alpha");
const expected = createHash(HASH_ALGORITHM)
.update(`${a}${UNIT_SEPARATOR}${hashFile(a)}${RECORD_SEPARATOR}`)
.digest(HASH_ENCODING);
expect(fingerprint([a])).toBe(expected);
});
});
});
describe("digestOf", () => {
it("hashes a body's exact bytes, so it differs from the separated composite of the same body", () => {
const body = '{"a":1}\n';
expect(digestOf(body)).toBe(createHash(HASH_ALGORITHM).update(body).digest(HASH_ENCODING));
expect(digestOf(body)).not.toBe(fingerprintOf([body]));
});
});
describe("fingerprintOf", () => {
it("combines ordered parts deterministically", () => {
const combined = fingerprintOf(["shared", "own"]);
expect(fingerprintOf(["shared", "own"])).toBe(combined);
expect(fingerprintOf(["own", "shared"])).not.toBe(combined);
});
});