import { describe, expect, it } from "@suaveplan/testing/runner"; import { CHUNKS_CODES } from "../error-codes.js"; import { encodeChunk, parseChunk, validateChunk } from "./chunk.js"; describe("CHUNKS-FORMAT-V1-01 — Chunk binary layout is byte-exact", () => { it("round-trips every field at exact offsets", { timeout: 5000 }, () => { const metadata = { version: 0x0001, fileId: new Uint8Array(32).fill(0xab), chunkId: 7, totalChunks: 10, fileSize: 12345n, chunkSize: 65536, payloadLen: 100, flags: 0x0000, nonce: new Uint8Array(24).fill(0xcd), aeadTag: new Uint8Array(16).fill(0xef), }; const sig = new Uint8Array(64).fill(0x12); const ciphertext = new Uint8Array(100).fill(0x34); const encoded = encodeChunk({ metadata, sig, ciphertext }); expect(encoded.length).toBe(164 + 100); const view = new DataView(encoded.buffer, encoded.byteOffset); expect(view.getUint16(0, false)).toBe(0x0001); expect(encoded.slice(2, 34)).toEqual(metadata.fileId); expect(view.getUint32(34, false)).toBe(7); expect(view.getUint32(38, false)).toBe(10); expect(view.getBigUint64(42, false)).toBe(12345n); expect(view.getUint32(50, false)).toBe(65536); expect(view.getUint32(54, false)).toBe(100); expect(view.getUint16(58, false)).toBe(0x0000); expect(encoded.slice(60, 84)).toEqual(metadata.nonce); expect(encoded.slice(84, 100)).toEqual(metadata.aeadTag); expect(encoded.slice(100, 164)).toEqual(sig); expect(encoded.slice(164)).toEqual(ciphertext); const parsed = parseChunk(encoded); expect(parsed.metadata.version).toBe(0x0001); expect(parsed.metadata.chunkId).toBe(7); expect(parsed.metadata.payloadLen).toBe(100); expect(parsed.sig).toEqual(sig); expect(parsed.ciphertext).toEqual(ciphertext); }); }); describe("CHUNKS-FORMAT-V1-02 — flags reserved in v1", () => { it("rejects non-zero flags", { timeout: 5000 }, () => { const metadata = { version: 0x0001, fileId: new Uint8Array(32), chunkId: 0, totalChunks: 1, fileSize: 1n, chunkSize: 65536, payloadLen: 1, flags: 0x0001, nonce: new Uint8Array(24), aeadTag: new Uint8Array(16), }; const chunk = { metadata, sig: new Uint8Array(64), ciphertext: new Uint8Array(1), }; expect(() => validateChunk(chunk)).toThrow(); try { validateChunk(chunk); } catch (e) { expect((e as Error).code).toBe(CHUNKS_CODES.FLAGS_RESERVED_NONZERO); } }); }); describe("CHUNKS-FORMAT-V1-03 — Payload length invariants", () => { it("rejects non-final chunk payloadLen mismatch", { timeout: 5000 }, () => { const metadata = { version: 0x0001, fileId: new Uint8Array(32), chunkId: 0, totalChunks: 2, fileSize: 100000n, chunkSize: 65536, payloadLen: 100, flags: 0x0000, nonce: new Uint8Array(24), aeadTag: new Uint8Array(16), }; const chunk = { metadata, sig: new Uint8Array(64), ciphertext: new Uint8Array(100), }; expect(() => validateChunk(chunk)).toThrow(); try { validateChunk(chunk); } catch (e) { expect((e as Error).code).toBe(CHUNKS_CODES.PAYLOAD_LEN_INVALID); } }); it("accepts correct non-final payloadLen", { timeout: 5000 }, () => { const metadata = { version: 0x0001, fileId: new Uint8Array(32), chunkId: 0, totalChunks: 2, fileSize: 100000n, chunkSize: 65536, payloadLen: 65536 - 164, flags: 0x0000, nonce: new Uint8Array(24), aeadTag: new Uint8Array(16), }; const chunk = { metadata, sig: new Uint8Array(64), ciphertext: new Uint8Array(65536 - 164), }; expect(() => validateChunk(chunk)).not.toThrow(); }); it("rejects final chunk payloadLen mismatch", { timeout: 5000 }, () => { const metadata = { version: 0x0001, fileId: new Uint8Array(32), chunkId: 1, totalChunks: 2, fileSize: 500n, chunkSize: 65536, payloadLen: 100, flags: 0x0000, nonce: new Uint8Array(24), aeadTag: new Uint8Array(16), }; const chunk = { metadata, sig: new Uint8Array(64), ciphertext: new Uint8Array(100), }; expect(() => validateChunk(chunk)).toThrow(); try { validateChunk(chunk); } catch (e) { expect((e as Error).code).toBe(CHUNKS_CODES.PAYLOAD_LEN_INVALID); } }); }); describe("CHUNKS-FORMAT-V1-04 — parseChunk edge cases", () => { it("rejects chunk shorter than header", { timeout: 5000 }, () => { expect(() => parseChunk(new Uint8Array(10))).toThrow(); try { parseChunk(new Uint8Array(10)); } catch (e) { expect((e as Error).code).toBe(CHUNKS_CODES.METADATA_INVALID); } }); it("rejects unsupported chunk version", { timeout: 5000 }, () => { const metadata = { version: 0x0002, fileId: new Uint8Array(32), chunkId: 0, totalChunks: 1, fileSize: 1n, chunkSize: 65536, payloadLen: 1, flags: 0x0000, nonce: new Uint8Array(24), aeadTag: new Uint8Array(16), }; const chunk = { metadata, sig: new Uint8Array(64), ciphertext: new Uint8Array(1), }; expect(() => validateChunk(chunk)).toThrow(); try { validateChunk(chunk); } catch (e) { expect((e as Error).code).toBe(CHUNKS_CODES.VERSION_UNSUPPORTED); } }); });