import { describe, expect, it } from "vitest"; import { TOOLCRAFT_MODEL_IMPORT_LIMIT_CEILINGS, } from "../model-import-limits"; import { decodeToolcraftModelDocument, encodeToolcraftModelDocument, ToolcraftModelDocumentCodecError, } from "./model-document-codec"; import { resolveToolcraftCanonicalModelLimits } from "./model-document-limits"; import { createValidModelDocument } from "./model-document-test-support"; import { validateToolcraftModelDocument } from "./model-document-validation"; const invalidLimitCases = [ ["misspelled key", { maxVerticies: 1 }, "limits.maxVerticies"], ["wrong value type", { maxNodes: "1" }, "limits.maxNodes"], ["NaN", { maxNodes: Number.NaN }, "limits.maxNodes"], ["fractional", { maxNodes: 1.5 }, "limits.maxNodes"], ["zero", { maxNodes: 0 }, "limits.maxNodes"], ["Infinity", { maxNodes: Number.POSITIVE_INFINITY }, "limits.maxNodes"], [ "above ceiling", { maxNodes: TOOLCRAFT_MODEL_IMPORT_LIMIT_CEILINGS.maxNodes + 1 }, "limits.maxNodes", ], ] as const; function expectCodecLimitFailure( operation: () => unknown, path: string, ): void { try { operation(); throw new Error("Expected canonical limit resolution to fail."); } catch (error) { expect(error).toBeInstanceOf(ToolcraftModelDocumentCodecError); expect(error).toMatchObject({ code: "invalid-limit-options", path, }); } } describe("canonical direct limit options", () => { it.each(invalidLimitCases)( "returns a typed validation failure for a %s", (_label, limits, path) => { expect( validateToolcraftModelDocument( createValidModelDocument(), limits as never, ), ).toMatchObject({ code: "invalid-limit-options", ok: false, path, }); }, ); it.each(invalidLimitCases)( "throws typed codec failures for a %s", (_label, limits, path) => { const document = createValidModelDocument(); const encoded = encodeToolcraftModelDocument(document); expectCodecLimitFailure( () => encodeToolcraftModelDocument(document, limits as never), path, ); expectCodecLimitFailure( () => decodeToolcraftModelDocument(encoded, limits as never), path, ); }, ); it.each([null, [], "limits"])( "rejects a non-object limit container %#", (limits) => { expect( validateToolcraftModelDocument( createValidModelDocument(), limits as never, ), ).toMatchObject({ code: "invalid-limit-options", ok: false, path: "limits", }); }, ); it("rejects limit accessors without invoking them", () => { const limits = {} as Record; let calls = 0; Object.defineProperty(limits, "maxNodes", { enumerable: true, get() { calls += 1; throw new Error("limit getter escaped"); }, }); const document = createValidModelDocument(); const encoded = encodeToolcraftModelDocument(document); expect( validateToolcraftModelDocument( document, limits as never, ), ).toMatchObject({ code: "invalid-limit-options", ok: false, path: "limits.maxNodes", }); expectCodecLimitFailure( () => encodeToolcraftModelDocument(document, limits as never), "limits.maxNodes", ); expectCodecLimitFailure( () => decodeToolcraftModelDocument(encoded, limits as never), "limits.maxNodes", ); expect(calls).toBe(0); }); it("returns a typed limit failure for a revoked options proxy", () => { const revocable = Proxy.revocable({}, {}); revocable.revoke(); expect( validateToolcraftModelDocument( createValidModelDocument(), revocable.proxy, ), ).toMatchObject({ code: "invalid-limit-options", ok: false, path: "limits", }); }); it("accepts recognized non-canonical import-limit keys", () => { expect(() => resolveToolcraftCanonicalModelLimits({ maxArchiveCompressionRatio: 1.5, maxArchiveEntries: 10, maxBundleFiles: 1, maxSourceBytes: 1024, }), ).not.toThrow(); }); });