import assert from "node:assert/strict"; import { ReplayTimeline } from "./replay.mjs"; import { VirtualDevices } from "./virtual-devices.mjs"; const commands = [ ["SPINDLE_COMMAND", { spindle: 0, rpm: 1200, enabled: true }], ["IO_STEP", { ticks: 20 }], ["TOOL_PREPARE", { tool: 7, pocket: 3 }], ["TOOL_PREPARED", { prepared: true }], ["TOOL_CHANGE", {}], ["SPINDLE_COMMAND", { spindle: 0, rpm: 0, enabled: false }], ["IO_STEP", { ticks: 20 }], ["TOOL_CHANGE", {}], ["TOOL_CHANGED", { changed: true }], ["TOOL_ABORT", { reason: 17 }], ["TOOL_PREPARE", { tool: 7, pocket: 3 }], ["TOOL_PREPARED", { prepared: true }], ["TOOL_CHANGE", {}], ["TOOL_CHANGED", { changed: true }], ["PROBE_CONFIG", { action: "arm", probe_type: 0 }], ["PROBE_CONFIG", { action: "update", input: true, position: { x: 1, y: 2, z: 3 } }], ["LIMIT_SET", { name: "x-positive", active: true }], ["TOOL_FAULT", { fault: true, reason: 42 }], ["TOOL_CLEAR_FAULT", {}], ["TOOL_FAULT", { fault: false, reason: 0 }], ["TOOL_CLEAR_FAULT", {}], ["ESTOP", { active: true }], ["SPINDLE_COMMAND", { spindle: 0, rpm: 100, enabled: true }], ["ESTOP", { active: false }], ["IO_RECOVER", {}], ]; function run() { const devices = new VirtualDevices(); const timeline = new ReplayTimeline(); const scenarios = []; let seq = 0; const nonfinite = devices.command("SPINDLE_COMMAND", { spindle: 0, rpm: Number.NaN, enabled: true }); scenarios.push({ kind: "NONFINITE_INPUT", code: nonfinite.code, status: nonfinite.status, state_hash: nonfinite.state_hash }); for (const [kind, payload] of commands) { seq += 1; const result = devices.command(kind, payload); timeline.appendEvent(seq, devices.state.tick, kind, payload); scenarios.push({ kind, code: result.code, status: result.status, state_hash: result.state_hash }); } const replay = new VirtualDevices(); for (const event of timeline.events.events) replay.applyEvent(event.kind, event.payload); return { schema: "virtual-device-fault-sample.v1", scenarios, events: timeline.events.cursor, state_hash: devices.hash(), replay_state_hash: replay.hash(), state_hash_equal: devices.hash() === replay.hash(), final: devices.export() }; } const first = run(); const second = run(); assert.equal(first.state_hash_equal, true); assert.equal(first.state_hash, first.replay_state_hash); assert.deepEqual(first, second); assert.equal(first.scenarios.find((row) => row.kind === "TOOL_CHANGE" && row.code === "sim_io_busy")?.status, "blocked"); assert.equal(first.scenarios.find((row) => row.kind === "SPINDLE_COMMAND" && row.code === "sim_io_estop")?.status, "blocked"); assert.equal(first.scenarios.find((row) => row.kind === "TOOL_CLEAR_FAULT" && row.code === "sim_io_fault")?.status, "blocked"); assert.equal(first.scenarios.find((row) => row.kind === "NONFINITE_INPUT")?.code, "sim_io_nonfinite"); console.log(JSON.stringify(first));