38 lines
1.7 KiB
TypeScript
38 lines
1.7 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { mkdtempSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { ZipError, crc32, zipStore, type ZipEntry } from "../src/core/zip";
|
|
|
|
const text = (s: string) => new TextEncoder().encode(s);
|
|
|
|
test("crc32 matches the standard check value", () => {
|
|
expect(crc32(text("123456789"))).toBe(0xcbf43926);
|
|
expect(crc32(new Uint8Array())).toBe(0);
|
|
});
|
|
|
|
test("a stored archive passes unzip -t and gives back the exact bytes", async () => {
|
|
const image = new Uint8Array(70_000).map((_, i) => (i * 31) & 0xff);
|
|
const entries: ZipEntry[] = [
|
|
{ name: "03_poster_zh-Hant_480x623.jpg", bytes: image, modified: new Date("2026-10-15T12:34:56Z") },
|
|
{ name: "covers.txt", bytes: text("Tower of God — 탑\n"), modified: new Date("2026-10-15T12:34:56Z") },
|
|
];
|
|
const zip = zipStore(entries);
|
|
// General-purpose flag bit 11: names are UTF-8.
|
|
expect(new DataView(zip.buffer, zip.byteOffset).getUint16(6, true) & 0x0800).toBe(0x0800);
|
|
|
|
const path = join(mkdtempSync(join(tmpdir(), "mbseed-zip-")), "covers.zip");
|
|
await Bun.write(path, zip);
|
|
const check = Bun.spawnSync(["unzip", "-t", path]);
|
|
expect(check.exitCode).toBe(0);
|
|
const out = Bun.spawnSync(["unzip", "-p", path, "03_poster_zh-Hant_480x623.jpg"]);
|
|
expect(new Uint8Array(out.stdout)).toEqual(image);
|
|
const txt = Bun.spawnSync(["unzip", "-p", path, "covers.txt"]);
|
|
expect(new TextDecoder().decode(txt.stdout)).toBe("Tower of God — 탑\n");
|
|
});
|
|
|
|
test("refuses archives past 4 GiB instead of writing a broken one", () => {
|
|
const huge = { length: 2 ** 32 } as unknown as Uint8Array;
|
|
expect(() => zipStore([{ name: "big.jpg", bytes: huge, modified: new Date() }])).toThrow(ZipError);
|
|
});
|