import assert from "node:assert/strict"; import fs from "node:fs"; import vm from "node:vm"; import test from "node:test"; import ts from "typescript"; const modules = new Map(); function load(name) { if (modules.has(name)) return modules.get(name); const source = fs.readFileSync(new URL(`../src/${name.replace(/^\.\//, "").replace(/\.js$/, ".ts")}`, import.meta.url), "utf8"); const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 } }).outputText; const module = { exports: {} }; vm.runInNewContext("(function(exports,require,module){" + compiled + "})", { AbortController })(module.exports, load, module); modules.set(name, module.exports); return module.exports; } const facade = load("./part-document-facade.js"); const input = { schema: facade.PART_DOCUMENT_SCHEMA, module: "Part", document: "Main", object: "Cylinder", action: "setPrimitive", primitive: "Cylinder", parameters: { Radius: 3, Height: 7, Angle: 180 } }; const response = { ok: true, result: { document: "Main", objectCount: 1, objects: [{ name: "Cylinder", type: "Part::Cylinder", primitive: "Cylinder", parameters: input.parameters }] } }; test("valid native primitive parameters are transported without computing geometry in JS", async () => { let request; const kernel = { ccall(_name, _type, _types, args) { request = JSON.parse(args[0]); return JSON.stringify(response); } }; await facade.handlePartDocument(input, new AbortController().signal, kernel); assert.deepEqual(request.args, input); assert.equal(request.cmd, "part.document"); }); test("invalid dimensions, angles and primitive types never reach native code", async () => { const kernel = { ccall() { assert.fail("invalid request reached native code"); } }; const variants = [ { primitive: "constructor" }, { parameters: { Radius: 2 } }, { parameters: { Radius: -1, Height: 5, Angle: 360 } }, { parameters: { Radius: 2, Height: 5, Angle: 0 } }, { parameters: { Radius: 2, Height: 5, Angle: 361 } }, { primitive: "Cone", parameters: { Radius1: 3, Radius2: 3, Height: 5, Angle: 360 } }, { primitive: "Torus", parameters: { Radius1: 1, Radius2: 2, Angle1: -180, Angle2: 180, Angle3: 360 } }, { primitive: "Sphere", parameters: { Radius: 2, Angle1: 20, Angle2: -20, Angle3: 360 } }, { primitive: "Sphere", parameters: { Radius: 2, Angle1: -100, Angle2: 90, Angle3: 360 } }, ]; for (const variant of variants) await assert.rejects(facade.handlePartDocument({ ...input, ...variant }, new AbortController().signal, kernel)); }); test("a native reply for another primitive or parameter set cannot pass validation", async () => { for (const override of [{ type: "Part::Sphere" }, { parameters: { Radius: 5, Height: 7, Angle: 180 } }]) { const value = { ...response, result: { ...response.result, objects: [{ ...response.result.objects[0], ...override }] } }; await assert.rejects(facade.handlePartDocument(input, new AbortController().signal, { ccall: () => JSON.stringify(value) }), /type or parameters/); } }); test("boolean operand links use the native document and reject invalid or mismatched results", async () => { const input = { schema: facade.PART_DOCUMENT_SCHEMA, module: "Part", document: "Main", action: "setBoolean", object: "Result", operation: "Cut", base: "Box", tool: "Cylinder" }; const object = { name: "Result", type: "Part::Cut", operation: "Cut", base: "Box", tool: "Cylinder" }; const kernel = { ccall: () => JSON.stringify({ ok: true, result: { document: "Main", objectCount: 1, objects: [object] } }) }; await facade.handlePartDocument(input, new AbortController().signal, kernel); for (const override of [{ operation: "constructor" }, { tool: "Box" }, { base: "Result" }, { tool: "other/doc" }]) await assert.rejects(facade.handlePartDocument({ ...input, ...override }, new AbortController().signal, { ccall() { assert.fail("invalid request reached native code"); } })); object.tool = "Other"; await assert.rejects(facade.handlePartDocument(input, new AbortController().signal, kernel), /operand links/); }); test("native placement requires finite coordinates and validates the returned position", async () => { const input = { schema: facade.PART_DOCUMENT_SCHEMA, module: "Part", document: "Main", action: "setPosition", object: "Box", position: [2, -3, 4] }; const object = { name: "Box", type: "Part::Box", position: input.position }; const kernel = { ccall: () => JSON.stringify({ ok: true, result: { document: "Main", objectCount: 1, objects: [object] } }) }; await facade.handlePartDocument(input, new AbortController().signal, kernel); for (const position of [[1, 2], [1, NaN, 3], [Infinity, 0, 0]]) await assert.rejects(facade.handlePartDocument({ ...input, position }, new AbortController().signal, kernel), /finite position/); object.position = [0, 0, 0]; await assert.rejects(facade.handlePartDocument(input, new AbortController().signal, kernel), /position does not match/); });