Initial Commit
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* DMP-05 / DMP-21 — selectForm threshold; codec-mandate enforcement.
|
||||
*
|
||||
* `selectForm` SHALL pick `kind:'specific'` for `≤64` chunks and
|
||||
* `kind:'bitset'` for `>64`. Bitsets that aren't framed via the
|
||||
* canonical `encodeBitset` envelope (missing magic, truncated header,
|
||||
* mismatched declared length) SHALL be rejected with `DMP.CODEC_MISMATCH`.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
BITSET_HEADER_SIZE,
|
||||
BITSET_MAGIC,
|
||||
chunkIdsToRawBitset,
|
||||
DMP_CODES,
|
||||
DmpError,
|
||||
decodeFramedBitset,
|
||||
decodeRequestPayload,
|
||||
encodeFramedBitset,
|
||||
SELECT_FORM_BITSET_THRESHOLD,
|
||||
selectForm,
|
||||
} from "../src/index.js";
|
||||
|
||||
const FILE_ID = "0".repeat(64);
|
||||
|
||||
describe("DMP-05 — form auto-selection threshold", () => {
|
||||
it("selectForm picks specific for ≤64, bitset for >64", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
for (let n = 1; n <= SELECT_FORM_BITSET_THRESHOLD; n++) {
|
||||
const ids = Array.from({ length: n }, (_, i) => i);
|
||||
const r = selectForm(ids);
|
||||
expect(r.kind).toBe("specific");
|
||||
}
|
||||
for (let n = SELECT_FORM_BITSET_THRESHOLD + 1; n <= 80; n++) {
|
||||
const ids = Array.from({ length: n }, (_, i) => i);
|
||||
const r = selectForm(ids);
|
||||
expect(r.kind).toBe("bitset");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("DMP-21 — codec mandates", () => {
|
||||
it("non-bitpacker-compressed bitset rejected (missing magic)", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const fakeBitset = new Uint8Array(20).fill(0xff);
|
||||
// Wire payload synthesised manually with a non-magic byte.
|
||||
const wire = new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
fileId: FILE_ID,
|
||||
request: {
|
||||
kind: "bitset",
|
||||
bytes: { _b: btoa(String.fromCharCode(...fakeBitset)) },
|
||||
},
|
||||
priority: "normal",
|
||||
})
|
||||
);
|
||||
try {
|
||||
decodeRequestPayload(wire);
|
||||
throw new Error("expected codec mismatch");
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(DmpError);
|
||||
expect((err as DmpError).code).toBe(DMP_CODES.CODEC_MISMATCH);
|
||||
}
|
||||
});
|
||||
|
||||
it("truncated bitset header rejected with CODEC_MISMATCH", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const tooShort = new Uint8Array(BITSET_HEADER_SIZE - 2);
|
||||
try {
|
||||
decodeFramedBitset(tooShort);
|
||||
throw new Error("expected truncation rejection");
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(DmpError);
|
||||
expect((err as DmpError).code).toBe(DMP_CODES.CODEC_MISMATCH);
|
||||
}
|
||||
});
|
||||
|
||||
it("valid bitset with magic decodes successfully", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const raw = chunkIdsToRawBitset([0, 5, 17], 18);
|
||||
const framed = encodeFramedBitset(raw, 18);
|
||||
for (let i = 0; i < BITSET_MAGIC.length; i++) {
|
||||
expect(framed[i]).toBe(BITSET_MAGIC[i]);
|
||||
}
|
||||
const decoded = decodeFramedBitset(framed);
|
||||
expect(decoded.bitLength).toBe(18);
|
||||
});
|
||||
|
||||
it("framed length mismatch rejected", { timeout: 5000 }, () => {
|
||||
const raw = chunkIdsToRawBitset([0, 1], 8);
|
||||
const framed = encodeFramedBitset(raw, 8);
|
||||
// Truncate the body so rawByteLen no longer matches.
|
||||
const broken = framed.slice(0, framed.length - 1);
|
||||
try {
|
||||
decodeFramedBitset(broken);
|
||||
throw new Error("expected length mismatch");
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(DmpError);
|
||||
expect((err as DmpError).code).toBe(DMP_CODES.CODEC_MISMATCH);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user