Files
mangabaka-seeder/test/zip.test.ts
T
2026-10-15 11:29:04 +02:00

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);
});