import { describe, expect, it } from "vitest"; import { decodeEmbedding, inspectDirectory } from "../../src/core/sfnt"; describe("SFNT directory validation", () => { it("inventories bounded TrueType tables", () => { const report = inspectDirectory(sfnt(["head", "cmap", "OS/2"])); expect(report.container).toBe("truetype"); expect(report.tables.map((table) => table.tag)).toEqual([ "head", "cmap", "OS/2", ]); expect(report.tables[2]?.description).toContain("embedding"); }); it("rejects unsupported and out-of-bounds containers before library parsing", () => { expect(() => inspectDirectory(signature("wOF2"))).toThrow(/WOFF2/u); const invalid = sfnt(["head"]), view = new DataView(invalid); view.setUint32(12 + 8, invalid.byteLength - 2, false); view.setUint32(12 + 12, 12, false); expect(() => inspectDirectory(invalid)).toThrow(/file boundary/u); }); }); describe("embedding flags", () => { it("decodes and enforces subsetting restrictions", () => { expect(decodeEmbedding(0).subsetAllowed).toBe(true); expect(decodeEmbedding(0x0002).level).toBe("restricted"); expect(decodeEmbedding(0x0100)).toMatchObject({ noSubsetting: true, subsetAllowed: false, }); expect(decodeEmbedding(0x0208)).toMatchObject({ level: "editable", bitmapOnly: true, subsetAllowed: false, }); }); }); function signature(value: string) { const bytes = new Uint8Array(4); [...value].forEach( (character, index) => (bytes[index] = character.charCodeAt(0)), ); return bytes.buffer; } function sfnt(tags: string[]) { const directoryBytes = 12 + tags.length * 16, tableBytes = 12, buffer = new ArrayBuffer(directoryBytes + tags.length * tableBytes), view = new DataView(buffer); view.setUint32(0, 0x0001_0000, false); view.setUint16(4, tags.length, false); tags.forEach((tag, index) => { const base = 12 + index * 16; [...tag].forEach((character, offset) => view.setUint8(base + offset, character.charCodeAt(0)), ); view.setUint32(base + 4, index + 1, false); view.setUint32(base + 8, directoryBytes + index * tableBytes, false); view.setUint32(base + 12, tableBytes, false); }); return buffer; }