Files
suaveplan/packages/foundation/data/media/src/signatures/signatures.test.ts
2026-05-27 23:47:53 +01:00

149 lines
5.0 KiB
TypeScript

import { describe, expect, it } from "@suaveplan/testing/runner";
import { MEDIA_CODES, MediaError } from "../errors/errors.js";
import {
BUILTIN_SIGNATURES,
defaultSignatureRegistry,
SignatureRegistry,
} from "./signatures.js";
describe("BUILTIN_SIGNATURES", () => {
it("includes PNG, JPEG, MP3, FLAC, OGG, WebM, MP4, WEBP", {
timeout: 5000,
}, () => {
const labels = BUILTIN_SIGNATURES.map((s) => s.label);
for (const expected of [
"PNG",
"JPEG",
"MP3-ID3",
"FLAC",
"OGG",
"WebM/MKV",
"MP4/MOV",
"WEBP",
]) {
expect(labels).toContain(expected);
}
});
it("is frozen", { timeout: 5000 }, () => {
expect(Object.isFrozen(BUILTIN_SIGNATURES)).toBe(true);
});
});
describe("SignatureRegistry", () => {
it("detects PNG via default registry", { timeout: 5000 }, () => {
const png = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x00]);
expect(defaultSignatureRegistry.detect(png)).toBe("image");
});
it("returns 'unknown' for unrecognised bytes", { timeout: 5000 }, () => {
const bytes = new Uint8Array([0x00, 0x01, 0x02]);
expect(defaultSignatureRegistry.detect(bytes)).toBe("unknown");
});
it("match returns the signature record", { timeout: 5000 }, () => {
const flac = new Uint8Array([0x66, 0x4c, 0x61, 0x43, 0x00]);
const sig = defaultSignatureRegistry.match(flac);
expect(sig?.label).toBe("FLAC");
expect(sig?.type).toBe("audio");
});
it("match returns null for empty input", { timeout: 5000 }, () => {
expect(defaultSignatureRegistry.match(new Uint8Array([]))).toBeNull();
});
it("honours non-zero offset (MP4 ftyp)", { timeout: 5000 }, () => {
// 4 padding bytes then 'ftyp' (0x66 0x74 0x79 0x70)
const mp4 = new Uint8Array([
0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f,
0x6d,
]);
expect(defaultSignatureRegistry.detect(mp4)).toBe("video");
});
it("ignores signature when input shorter than offset+bytes", {
timeout: 5000,
}, () => {
const short = new Uint8Array([0x00]);
expect(defaultSignatureRegistry.detect(short)).toBe("unknown");
});
it("can register custom signature", { timeout: 5000 }, () => {
const reg = new SignatureRegistry([]);
reg.register({ type: "image", label: "X", bytes: [0xde, 0xad] });
const detected = reg.detect(new Uint8Array([0xde, 0xad, 0xbe]));
expect(detected).toBe("image");
});
it("unregister removes signature and returns true", {
timeout: 5000,
}, () => {
const reg = new SignatureRegistry();
expect(reg.unregister("PNG")).toBe(true);
expect(reg.detect(new Uint8Array([0x89, 0x50, 0x4e, 0x47]))).toBe(
"unknown"
);
});
it("unregister returns false for unknown label", {
timeout: 5000,
}, () => {
const reg = new SignatureRegistry();
expect(reg.unregister("NOPE")).toBe(false);
});
it("list returns frozen snapshot", { timeout: 5000 }, () => {
const reg = new SignatureRegistry();
const snap = reg.list();
expect(Object.isFrozen(snap)).toBe(true);
expect(snap.length).toBe(BUILTIN_SIGNATURES.length);
});
it("register rejects empty byte array", { timeout: 5000 }, () => {
const reg = new SignatureRegistry([]);
expect(() =>
reg.register({ type: "image", label: "E", bytes: [] })
).toThrow(MediaError);
});
it("register rejects non-byte values", { timeout: 5000 }, () => {
const reg = new SignatureRegistry([]);
try {
reg.register({ type: "image", label: "N", bytes: [256] });
throw new Error("should have thrown");
} catch (err) {
expect(err).toBeInstanceOf(MediaError);
expect((err as MediaError).code).toBe(
MEDIA_CODES.INVALID_SIGNATURE
);
}
});
it("register rejects negative byte values", { timeout: 5000 }, () => {
const reg = new SignatureRegistry([]);
expect(() =>
reg.register({ type: "image", label: "N", bytes: [-1] })
).toThrow(MediaError);
});
it("register rejects non-integer byte values", { timeout: 5000 }, () => {
const reg = new SignatureRegistry([]);
expect(() =>
reg.register({ type: "image", label: "N", bytes: [1.5] })
).toThrow(MediaError);
});
it("rejects duplicate label", { timeout: 5000 }, () => {
const reg = new SignatureRegistry();
try {
reg.register({ type: "image", label: "PNG", bytes: [0x00] });
throw new Error("should have thrown");
} catch (err) {
expect(err).toBeInstanceOf(MediaError);
expect((err as MediaError).code).toBe(
MEDIA_CODES.DUPLICATE_SIGNATURE
);
}
});
});