import { describe, expect, it } from "@suaveplan/testing/runner"; import { buildFixtureWasm, WITNESS_OFFSET } from "./build-wasm.js"; async function instantiate(bytes: Uint8Array) { const mod = await WebAssembly.compile(bytes); const instance = await WebAssembly.instantiate(mod, {}); return instance.exports as Record & { memory: WebAssembly.Memory; }; } describe("buildFixtureWasm", () => { it("compiles and exports the full ABI surface", { timeout: 30000, }, async () => { const bytes = buildFixtureWasm(); const exports = await instantiate(bytes); const required = [ "memory", "__suaveplan_alloc", "__suaveplan_free", "__suaveplan_handle_request", "__suaveplan_routes", "__suaveplan_start", "__suaveplan_dispose", ]; for (const name of required) { expect(exports[name]).toBeDefined(); } }); it("default routes JSON decodes to a single GET route", { timeout: 30000, }, async () => { const exports = await instantiate(buildFixtureWasm()); const routes = exports.__suaveplan_routes as () => bigint; const packed = routes(); const ptr = Number((packed >> 32n) & 0xffff_ffffn); const len = Number(packed & 0xffff_ffffn); const json = new TextDecoder().decode( new Uint8Array(exports.memory.buffer, ptr, len) ); expect(JSON.parse(json)).toEqual([{ method: "GET", path: "/hello" }]); }); it("handle_request copies request bytes into the witness range", { timeout: 30000, }, async () => { const exports = await instantiate(buildFixtureWasm()); const alloc = exports.__suaveplan_alloc as (n: number) => number; const handle = exports.__suaveplan_handle_request as ( p: number, l: number ) => bigint; const payload = new TextEncoder().encode("hello-witness"); const ptr = alloc(payload.length); new Uint8Array(exports.memory.buffer).set(payload, ptr); handle(ptr, payload.length); const witnessBytes = new Uint8Array( exports.memory.buffer, WITNESS_OFFSET, payload.length ); expect(new TextDecoder().decode(witnessBytes)).toBe("hello-witness"); }); it("clamps oversize requests to WITNESS_CAPACITY", { timeout: 30000, }, async () => { const exports = await instantiate(buildFixtureWasm()); const alloc = exports.__suaveplan_alloc as (n: number) => number; const handle = exports.__suaveplan_handle_request as ( p: number, l: number ) => bigint; const payload = new Uint8Array(2048).fill(0x41); const ptr = alloc(payload.length); new Uint8Array(exports.memory.buffer).set(payload, ptr); handle(ptr, payload.length); // First 1024 witness bytes are populated; reading the FULL // witness range should be all 0x41 (since the clamp wrote // exactly WITNESS_CAPACITY bytes, not more). const witness = new Uint8Array( exports.memory.buffer, WITNESS_OFFSET, 1024 ); expect(witness.every((b) => b === 0x41)).toBe(true); }); it("allocAlwaysZero produces an alloc that returns 0", { timeout: 30000, }, async () => { const exports = await instantiate( buildFixtureWasm({ allocAlwaysZero: true }) ); const alloc = exports.__suaveplan_alloc as (n: number) => number; expect(alloc(16)).toBe(0); }); it("handlerTraps fixture traps via unreachable", { timeout: 30000, }, async () => { const exports = await instantiate( buildFixtureWasm({ handlerTraps: true }) ); const handle = exports.__suaveplan_handle_request as ( p: number, l: number ) => bigint; expect(() => handle(0, 0)).toThrow(WebAssembly.RuntimeError); }); it("startTraps + disposeTraps both surface as RuntimeError", { timeout: 30000, }, async () => { const startExports = await instantiate( buildFixtureWasm({ startTraps: true }) ); expect(() => (startExports.__suaveplan_start as () => void)()).toThrow( WebAssembly.RuntimeError ); const disposeExports = await instantiate( buildFixtureWasm({ disposeTraps: true }) ); expect(() => (disposeExports.__suaveplan_dispose as () => void)() ).toThrow(WebAssembly.RuntimeError); }); it("routesTraps fixture traps __suaveplan_routes", { timeout: 30000, }, async () => { const exports = await instantiate( buildFixtureWasm({ routesTraps: true }) ); expect(() => (exports.__suaveplan_routes as () => bigint)()).toThrow( WebAssembly.RuntimeError ); }); it("routesEmpty returns (0, 0)", { timeout: 30000 }, async () => { const exports = await instantiate( buildFixtureWasm({ routesEmpty: true }) ); expect((exports.__suaveplan_routes as () => bigint)()).toBe(0n); }); it("handlerEmptyResponse returns (0, 0)", { timeout: 30000 }, async () => { const exports = await instantiate( buildFixtureWasm({ handlerEmptyResponse: true }) ); const handle = exports.__suaveplan_handle_request as ( p: number, l: number ) => bigint; expect(handle(0, 0)).toBe(0n); }); it("dropExports omits the requested symbols", { timeout: 30000, }, async () => { const exports = await instantiate( buildFixtureWasm({ dropExports: ["__suaveplan_start"] }) ); expect(exports.__suaveplan_start).toBeUndefined(); // Memory and the rest remain. expect(exports.memory).toBeInstanceOf(WebAssembly.Memory); }); it("rejects oversize routes JSON", { timeout: 5000 }, () => { expect(() => buildFixtureWasm({ routesJson: "x".repeat(2048) }) ).toThrow(RangeError); }); it("rejects oversize response JSON", { timeout: 5000 }, () => { expect(() => buildFixtureWasm({ responseJson: "x".repeat(2048) }) ).toThrow(RangeError); }); });