Thing/packages/thing-contract/test/deep.test.ts
Meta Vens b8ad36a189 thing-contract-ts: seq, version and segment checked on the encode door of the leaf (integer and bound) where a caller hands a number in
The factory and key builders took a non-integer through the decode leaf; the encode leaf refuses it. Deep chain bound corrected to 83 Box levels.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 08:40:20 +02:00

76 lines
3.3 KiB
TypeScript

// The deepest tree the payload bound admits decodes and re-encodes on Node's default stack (no --stack-size), and one
// level deeper is refused with CultCachePayloadDepthError, never an abort. The Rust test of the same name needs a 16 MiB
// thread for this; here the stack holds, and the bound refuses first.
import assert from "node:assert/strict";
import test from "node:test";
import {
CultCachePayloadDepthError,
MAX_PAYLOAD_DEPTH,
decodeDocumentPayload,
documentPayloadBytes,
documentPayloadFromBytes,
encodeDocumentPayload,
} from "@gamecult/cultcache-ts";
import { surfaceDocument } from "@gamecult/thing-contract";
import type { Node, SurfaceDocument } from "@gamecult/thing-contract";
import { boxNode, boxed, text } from "./builders.js";
function chain(levels: number): SurfaceDocument {
let root: Node = text("leaf", "bottom");
for (let depth = levels - 1; depth >= 0; depth--) root = boxed(`deep-${depth}`, [root]);
return { providerId: "provider.a", label: "deep", version: 1, title: "deep", root, commands: [] };
}
const admits = (levels: number): boolean => {
try {
encodeDocumentPayload(surfaceDocument, chain(levels));
return true;
} catch (error) {
assert.ok(error instanceof CultCachePayloadDepthError, "the only refusal of a plain chain is the depth bound");
assert.equal(error.limit, MAX_PAYLOAD_DEPTH);
return false;
}
};
test("the deepest Box chain the bound admits round-trips on the default stack, and one more is refused", () => {
let deepest = 1;
while (admits(deepest + 1)) deepest++;
assert.equal(deepest, 83, "the bound admits 83 Box levels above the text leaf, 84 nodes deep");
assert.ok(!admits(deepest + 1));
const value = chain(deepest);
const bytes = documentPayloadBytes(encodeDocumentPayload(surfaceDocument, value));
const decoded = decodeDocumentPayload(surfaceDocument, documentPayloadFromBytes(bytes));
assert.deepStrictEqual(decoded, value);
assert.deepEqual(documentPayloadBytes(encodeDocumentPayload(surfaceDocument, decoded)), bytes);
});
test("a payload one container past the bound is refused with the depth error, before any codec reads it", () => {
const nested = (levels: number) => new Uint8Array([...new Array<number>(levels).fill(0x91), 0xc0]);
assert.throws(
() => decodeDocumentPayload(surfaceDocument, documentPayloadFromBytes(nested(MAX_PAYLOAD_DEPTH + 1))),
(error: unknown) => error instanceof CultCachePayloadDepthError && error.depth === MAX_PAYLOAD_DEPTH + 1,
);
// At the bound the walk admits it and the codec refuses the shape instead.
assert.throws(
() => decodeDocumentPayload(surfaceDocument, documentPayloadFromBytes(nested(MAX_PAYLOAD_DEPTH))),
(error: unknown) => error instanceof Error && !(error instanceof CultCachePayloadDepthError),
);
});
test("a wide tree of a thousand nodes round-trips", () => {
const children: Node[] = Array.from({ length: 998 }, (_, index) => text(`t${index}`, "x"));
children.push(boxed("tail", []));
const wide: SurfaceDocument = {
providerId: "provider.a",
label: "wide",
version: 1,
title: "wide",
root: { kind: "Box", ...boxNode("root", children) },
commands: [],
};
const bytes = documentPayloadBytes(encodeDocumentPayload(surfaceDocument, wide));
assert.deepStrictEqual(decodeDocumentPayload(surfaceDocument, documentPayloadFromBytes(bytes)), wide);
});