/** * DMP-08 — Advertisement bitset length invariant. * * In `ChunkAdvertisePayload`, the bit-length of `presence` MUST equal * `totalChunks`; padding bits in the final byte MUST be zero. The codec * rejects mismatched bitset wires with either * `DMP.BITSET_LENGTH_MISMATCH` or `DMP.BITSET_PADDING_NONZERO`. */ import { describe, expect, it } from "@suaveplan/testing/runner"; import { BITSET_MAGIC, chunkIdsToRawBitset, DMP_CODES, DmpError, decodeAdvertisePayload, encodeAdvertisePayload, encodeFramedBitset, } from "../src/index.js"; const FILE_ID = "b".repeat(64); function makeAdvertise(presence: Uint8Array, totalChunks: number) { return encodeAdvertisePayload({ fileId: FILE_ID, presence, totalChunks, generation: 1, timestamp: 0, }); } function makeFramedBitset(ids: number[], bitLength: number) { return encodeFramedBitset(chunkIdsToRawBitset(ids, bitLength), bitLength); } describe("DMP-08 — bitset length invariant", () => { it("advertisement with presence.length ≠ totalChunks rejected", { timeout: 5000, }, () => { const presence = makeFramedBitset([0, 5], 16); try { makeAdvertise(presence, 32); throw new Error("expected mismatch rejection"); } catch (err) { expect(err).toBeInstanceOf(DmpError); expect((err as DmpError).code).toBe( DMP_CODES.BITSET_LENGTH_MISMATCH ); } }); it("valid advertisement (bitLength == totalChunks) round-trips", { timeout: 5000, }, () => { const presence = makeFramedBitset([0, 5, 7], 8); const wire = makeAdvertise(presence, 8); const decoded = decodeAdvertisePayload(wire); expect(decoded.totalChunks).toBe(8); expect(decoded.presence).toEqual(presence); }); it("non-zero padding bits rejected", { timeout: 5000 }, () => { // Hand-build a framed bitset with bitLength=10 (so high bits 10..15 // must be zero) but flip bit 14 to violate padding zeroing. const raw = new Uint8Array([0x01, 0xff]); // Build the wire envelope by hand. const wire = new Uint8Array(12 + raw.length); wire.set(BITSET_MAGIC, 0); const view = new DataView( wire.buffer, wire.byteOffset, wire.byteLength ); view.setUint32(4, 10, false); view.setUint32(8, raw.length, false); wire.set(raw, 12); try { makeAdvertise(wire, 10); throw new Error("expected padding-nonzero rejection"); } catch (err) { expect(err).toBeInstanceOf(DmpError); expect((err as DmpError).code).toBe( DMP_CODES.BITSET_PADDING_NONZERO ); } }); });