| 1 | import { describe, expect, it } from "vitest"; |
| 2 | import { deflateSync } from "node:zlib"; |
| 3 | import pako from "pako"; |
| 4 | import { deflate, inflate, inflateSized } from "../src/index.js"; |
| 5 | |
| 6 | const same = (a: Uint8Array, b: Uint8Array) => a.length === b.length && Buffer.from(a).equals(Buffer.from(b)); |
| 7 | const text = (n: number) => new TextEncoder().encode("tree and commit text ".repeat(Math.ceil(n / 21)).slice(0, n)); |
| 8 | |
| 9 | describe("zlib", () => { |
| 10 | it("reads what it writes, small objects natively and large ones with pako", () => { |
| 11 | for (const n of [0, 1, 100, 70_000, 1024 * 1024, 1024 * 1024 + 1, 3 * 1024 * 1024]) { |
| 12 | const raw = text(n); |
| 13 | expect(same(inflateSized(deflate(raw), n), raw), `${n}`).toBe(true); |
| 14 | expect(same(inflateSized(new Uint8Array(deflateSync(raw, { level: 9 })), n), raw), `${n}`).toBe(true); |
| 15 | expect(same(inflate(deflate(raw)), raw), `${n}`).toBe(true); |
| 16 | } |
| 17 | }); |
| 18 | |
| 19 | it("refuses data that inflates to more or less than the recorded size, small or large", () => { |
| 20 | for (const n of [500, 2 * 1024 * 1024]) { |
| 21 | const z = deflate(text(n)); |
| 22 | expect(() => inflateSized(z, n - 1)).toThrow(/larger than its recorded size/); |
| 23 | expect(() => inflateSized(z, n + 1)).toThrow(/not its recorded/); |
| 24 | expect(() => inflateSized(z.subarray(0, z.length - 4), n)).toThrow(/zlib error|not its recorded/); |
| 25 | expect(() => inflateSized(pako.gzip(text(n)), n)).toThrow(); |
| 26 | } |
| 27 | }); |
| 28 | |
| 29 | it("stops a small object that would inflate to far more than its recorded size", () => { |
| 30 | const bomb = deflate(new Uint8Array(50 * 1024 * 1024)); |
| 31 | expect(() => inflateSized(bomb, 1000)).toThrow(/larger than its recorded size/); |
| 32 | }); |
| 33 | |
| 34 | it("hands back a plain Uint8Array", () => { |
| 35 | expect(inflateSized(deflate(text(10)), 10).constructor).toBe(Uint8Array); |
| 36 | }); |
| 37 | }); |