1import { describe, expect, it } from "vite-plus/test";
2
3import { extractIcnsPng } from "./icns.ts";
4
5function pngHeader(size: number): Uint8Array {
6 const png = new Uint8Array(24);
7 png.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0, 0, 0, 13, 0x49, 0x48, 0x44, 0x52]);
8 new DataView(png.buffer).setUint32(16, size);
9 new DataView(png.buffer).setUint32(20, size);
10 return png;
11}
12
13function icns(...entries: ReadonlyArray<readonly [type: string, data: Uint8Array]>): Uint8Array {
14 const length = 8 + entries.reduce((total, [, data]) => total + 8 + data.length, 0);
15 const bytes = new Uint8Array(length);
16 const view = new DataView(bytes.buffer);
17 bytes.set(new TextEncoder().encode("icns"));
18 view.setUint32(4, length);
19 let offset = 8;
20 for (const [type, data] of entries) {
21 bytes.set(new TextEncoder().encode(type), offset);
22 view.setUint32(offset + 4, 8 + data.length);
23 bytes.set(data, offset + 8);
24 offset += 8 + data.length;
25 }
26 return bytes;
27}
28
29const widthOf = (png: Uint8Array | null) =>
30 png ? new DataView(png.buffer, png.byteOffset).getUint32(16) : null;
31
32describe("extractIcnsPng", () => {
33 it("picks the smallest PNG that covers the requested size", () => {
34 const file = icns(
35 ["TOC ", new Uint8Array(16)],
36 ["ic09", pngHeader(512)],
37 ["icp5", pngHeader(32)],
38 ["ic07", pngHeader(128)],
39 ["ic08", pngHeader(256)],
40 );
41
42 expect(widthOf(extractIcnsPng(file, 96))).toBe(128);
43 });
44
45 it("stops at an entry whose length runs past the file", () => {
46 const file = icns(["ic07", pngHeader(128)], ["ic08", pngHeader(256)]);
47 new DataView(file.buffer).setUint32(8 + 8 + 24 + 4, 4096);
48
49 expect(widthOf(extractIcnsPng(file, 200))).toBe(128);
50 });
51});