Files
linuxcncWebWASM/web/worker/test_source_do_s7_01.mjs

83 lines
4.2 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
import { ProgramRunner } from "./program-runner.mjs";
import { SimSession, CONTEXT_ID } from "./sim-session.mjs";
import { compareEndpoints, createEndpoint } from "./endpoint-replay.mjs";
const sourcePath = "linuxcnc/tests/interp/do-while-break/test.ngc";
const source = await readFile(new URL(`../../${sourcePath}`, import.meta.url), "utf8");
const wasmBinary = await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url));
async function complete(core, pauseAt = null) {
const runner = new ProgramRunner(core);
assert.equal(runner.load(source, sourcePath).status, "verified");
assert.equal(runner.start().status, "verified");
let steps = 0;
while (runner.status === "running" && steps < 1000) {
runner.step();
steps += 1;
if (pauseAt !== null && steps === pauseAt) {
assert.equal(runner.pause().status, "verified");
const paused = runner.snapshot();
assert.equal(runner.resume().status, "verified");
assert.equal(paused.program_status, "paused");
}
}
assert.equal(runner.status, "completed");
assert.ok(steps < 1000);
assert.equal(runner.namedParameters.get("one_pass"), 1);
assert.equal(runner.namedParameters.get("two_pass"), 1);
assert.equal(runner.namedParameters.get("three_pass"), 1);
const snapshot = runner.snapshot();
runner.destroy();
return { snapshot, steps };
}
const core = await createModule({ wasmBinary });
const normal = await complete(core);
const paused = await complete(core, 5);
assert.equal(normal.snapshot.interpreter_state_hash, paused.snapshot.interpreter_state_hash);
const malformed = new ProgramRunner(core);
assert.equal(malformed.load("O100 ENDDO\nM2\n", "malformed.ngc").code, "program_enddo_without_do");
malformed.destroy();
const tooDeep = new ProgramRunner(core);
const nested = `${Array.from({ length: 33 }, (_, index) => `O${index + 1} DO`).join("\n")}\nM2\n${Array.from({ length: 33 }, (_, index) => `O${33 - index} WHILE [1]`).join("\n")}`;
assert.equal(tooDeep.load(nested, "depth.ngc").code, "program_control_depth");
tooDeep.destroy();
const sessionCore = await createModule({ wasmBinary });
const session = new SimSession(sessionCore, { sessionId: "s7-do-recovery" });
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: "s7-do-recovery" };
let seq = 0;
const send = (kind, operation_id, payload = {}) => {
seq += 1;
const response = session.accept({ ...base, kind, seq, operation_id, payload });
assert.notEqual(response.kind, "ERROR", `${kind}:${response.payload?.code ?? "error"}`);
return response;
};
send("HELLO", "hello"); send("SESSION_ATTACH", "attach");
send("LOAD_WORKSPACE", "workspace", { root_path: "/workspace" });
send("PROGRAM_LOAD", "program", { source, path: sourcePath }); send("PROGRAM_RUN", "run");
send("SIM_STEP", "step-a", { cycles: 5 });
const checkpoint = session.createCheckpoint();
send("SIM_STEP", "step-b", { cycles: 10 });
const continuous = createEndpoint({ session });
assert.equal(session.restoreCheckpoint(checkpoint, session.timeline.export(), (operation) => operation).status, "recovered");
const recovered = createEndpoint({ session });
const parity = compareEndpoints(continuous, recovered);
assert.equal(parity.equal, true, JSON.stringify(parity));
console.log(JSON.stringify({
schema: "linuxcnc-source-do-s7-01-sample.v1",
status: "verified",
context_id: CONTEXT_ID,
source: { path: sourcePath, source_hash: normal.snapshot.source_hash },
normal: { status: normal.snapshot.program_status, steps: normal.steps, named_parameters: { one_pass: 1, two_pass: 1, three_pass: 1 }, interpreter_state_hash: normal.snapshot.interpreter_state_hash },
pause_resume: { status: paused.snapshot.program_status, steps: paused.steps, hash_equal: normal.snapshot.interpreter_state_hash === paused.snapshot.interpreter_state_hash },
errors: { malformed_enddo: "program_enddo_without_do", depth: "program_control_depth" },
recovery: { equal: parity.equal, difference: parity.difference, checkpoint_hash: checkpoint.checkpoint_hash },
boundaries: ["LinuxCNC canonical expected output remains SOURCE_BLOCKED", "G64/G61 remains S7 follow-up", "host/Python/real hardware paths unchanged"],
}));