import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import createModule from "../../build-wasm/linuxcnc-sim-core.js"; import { SimSession, CONTEXT_ID } from "./sim-session.mjs"; const core = await createModule({ wasmBinary: await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url)) }); const session = new SimSession(core, { sessionId: "runner-session" }); const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: "runner-session" }; const send = (kind, seq, operation_id, payload = {}) => session.accept({ ...base, kind, seq, operation_id, payload }); send("HELLO", 1); send("SESSION_ATTACH", 2, "attach"); send("LOAD_WORKSPACE", 3, "load", { root_path: "/workspace" }); const mdi = send("MDI_EXECUTE", 4, "mdi", { block: "G21 G90 G1 X3 Y4 F60" }); assert.equal(mdi.payload.state.x, 3); assert.equal(mdi.payload.runner.canonical.includes('"x":3'), true); assert.match(mdi.payload.runner.modal_hash, /^fnv1a64:/); assert.equal(mdi.payload.runner.state.line, 1); assert.equal(mdi.payload.runner.program_status, "idle"); const offset = send("MDI_EXECUTE", 5, "mdi-offset", { block: "G10 L2 P1 X10 Y20 Z30" }); assert.equal(offset.payload.runner.state.x, 3); const offsetMove = send("MDI_EXECUTE", 6, "mdi-offset-move", { block: "G54 G90 X1 Y2 Z3" }); assert.equal(offsetMove.payload.state.x, 11); assert.equal(offsetMove.payload.state.y, 22); assert.equal(offsetMove.payload.state.z, 33); const loaded = send("PROGRAM_LOAD", 7, "program-load", { source: "G21 G90\nG1 X2 F60\nM2\n", path: "runner.ngc" }); assert.equal(loaded.payload.canonical.includes('"units":21'), true); send("PROGRAM_RUN", 8, "program-run"); const tick = send("SIM_STEP", 9, "tick", { cycles: 1 }); assert.equal(tick.payload.program.state.line, 1); assert.equal(tick.payload.task.current_line, 1); send("PROGRAM_PAUSE", 10, "pause"); send("PROGRAM_RESUME", 11, "resume"); const abort = send("PROGRAM_ABORT", 12, "abort"); assert.equal(abort.payload.task.program_status, "aborted"); const checkpoint = send("CHECKPOINT", 13, "checkpoint").payload.checkpoint; const recovered = session.restoreCheckpoint(checkpoint, null, (operation) => operation); assert.equal(recovered.status, "recovered"); assert.equal(recovered.state.task.program_status, "aborted"); const errorCore = await createModule({ wasmBinary: await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url)) }); const errorSession = new SimSession(errorCore, { sessionId: "runner-error" }); const errorBase = { schema_version: 1, context_id: CONTEXT_ID, session_id: "runner-error" }; const errorSend = (kind, seq, operation_id, payload = {}) => errorSession.accept({ ...errorBase, kind, seq, operation_id, payload }); errorSend("HELLO", 1); errorSend("SESSION_ATTACH", 2, "a"); errorSend("LOAD_WORKSPACE", 3, "l", { root_path: "/workspace" }); errorSend("PROGRAM_LOAD", 4, "bad-load", { source: "G999\n" }); errorSend("PROGRAM_RUN", 5, "bad-run"); const error = errorSend("PROGRAM_STEP", 6, "bad-step"); assert.equal(error.kind, "ERROR"); assert.equal(error.payload.code, "program_interpreter"); assert.equal(error.payload.line, 1); assert.equal(error.payload.column, 1); assert.equal(error.payload.error_code, -504); console.log(`sim_runner=passed mdi_x=${mdi.payload.state.x} tick_line=${tick.payload.task.current_line} recovery=${recovered.state.task.program_status}`);