Files
wasm-simulator/web/test-browser-wasm-smoke-opfs-parameter-sections.js

256 lines
12 KiB
JavaScript

export async function runBrowserOpfsParameterSections(context, simulator) {
const {
expectErrorContaining,
expectEvent,
expectIncludes,
expectMissingOpfsFile,
expectMissingWasmPath,
expectNoEvent,
expectText,
expectWasmFilesMissing,
near,
removeWasmPathIfExists,
runSection,
withSmokeSimulator,
} = context;
await runSection("opfs parameter save", async () => {
await simulator.parseWithParameterFile(
"G21 G90\nG0 X1\nG28.1\nM30\n",
"parameters/rs274ngc.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
const opfsParameterFile = new TextDecoder().decode(
await simulator.fs.opfs.readFile("parameters/rs274ngc.var"),
);
expectIncludes(opfsParameterFile, "5161\t1.000000", "LinuxCNC parameter file was not persisted into OPFS");
});
await runSection("opfs parameter restore in new instance", async () => {
await withSmokeSimulator(async (restoredWorkspaceSimulator) => {
// LinuxCNC source basis: rs274ngc_pre.cc restore_parameters()
// loads persisted numbered parameters before interpreting blocks.
const restoredWorkspaceEvents = await restoredWorkspaceSimulator.parseWithParameterFile(
"G21 G90\nF100\nO10 if [#5161 EQ 1]\nG1 X8\nO10 endif\n",
"parameters/rs274ngc.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
expectEvent(restoredWorkspaceEvents, (event) => event.type === "linear-feed" && near(event.end.x, 8),
"LinuxCNC OPFS parameter file was not restored across WASM simulator instances");
});
});
await runSection("opfs parameter temporary cleanup", async () => {
await simulator.fs.opfs.writeFile("parameters/rs274ngc.var.new", "stale temporary parameter file\n");
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters() writes
// filename + ".new", then renames it over the parameter file.
simulator.fs.module.FS.writeFile("rs274ngc.var.new", "stale wasm temporary parameter file\n");
const restoredParameterEvents = await simulator.parseWithParameterFile(
"G21 G90\nF100\nO10 if [#5161 EQ 1]\nG1 X9\nO10 endif\n",
"parameters/rs274ngc.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
expectEvent(restoredParameterEvents, (event) => event.type === "linear-feed" && near(event.end.x, 9),
"LinuxCNC parameter file was not restored from OPFS");
await expectMissingOpfsFile(
() => simulator.fs.opfs.readFile("parameters/rs274ngc.var.new"),
"stale LinuxCNC temporary parameter file remained in OPFS",
);
expectMissingWasmPath(
() => simulator.fs.module.FS.readFile("rs274ngc.var.new"),
"stale LinuxCNC temporary parameter file remained in WASM FS",
);
});
await runSection("opfs parameter backup bridge", async () => {
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
// attempts link(filename, filename + ".bak") but treats link
// failure as non-fatal. The browser bridge must persist a backup
// when the WASM filesystem exposes one.
simulator.fs.module.FS.writeFile("rs274ngc.var", "5161\t2.000000\n");
simulator.fs.module.FS.writeFile("rs274ngc.var.bak", "5161\t1.000000\n");
await simulator.fs.opfs.persistParameterFile("parameters/backup-bridge.var");
const opfsParameterBackup = new TextDecoder().decode(
await simulator.fs.opfs.readFile("parameters/backup-bridge.var.bak"),
);
expectIncludes(opfsParameterBackup, "5161\t1.000000",
"LinuxCNC parameter backup file was not bridged into OPFS");
});
await runSection("opfs parameter stale backup cleanup", async () => {
removeWasmPathIfExists(simulator, "rs274ngc.var.bak");
removeWasmPathIfExists(simulator, "/rs274ngc.var.bak");
await simulator.parseWithParameterFile(
"G21 G90\nM30\n",
"parameters/rs274ngc.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
await expectMissingOpfsFile(
() => simulator.fs.opfs.readFile("parameters/rs274ngc.var.bak"),
"stale LinuxCNC parameter backup file remained in OPFS",
);
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
// unlinks stale backup files before replacing the parameter file.
await simulator.fs.opfs.removeFile("parameters/missing-cleanup/rs274ngc.var.bak");
});
await runSection("opfs program file with parameter persistence", async () => {
await simulator.fs.opfs.writeFile("programs/parameter-file-smoke.ngc", "G21 G90\nF100\nG0 X1\nG28.1\nM30\n");
const fileParameterEvents = await simulator.parseFileWithParameterFile(
"programs/parameter-file-smoke.ngc",
"parameters/rs274ngc.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
expectEvent(fileParameterEvents, (event) => event.type === "program-end",
"OPFS program file with LinuxCNC parameter persistence did not parse");
});
await runSection("opfs missing parameter file creation", async () => {
await simulator.fs.opfs.writeFile("parameters/missing-main.var.bak", "stale backup without main file\n");
await simulator.fs.opfs.writeFile("parameters/missing-main.var.new", "stale temporary without main file\n");
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters() unlinks
// filename + RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX before linking,
// then renames filename + ".new" over the parameter file.
simulator.fs.module.FS.writeFile("rs274ngc.var.bak", "stale wasm backup without main file\n");
simulator.fs.module.FS.writeFile("rs274ngc.var.new", "stale wasm temporary without main file\n");
await simulator.parseWithParameterFile(
"G21 G90\nM30\n",
"parameters/missing-main.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
const missingMainParameterFile = new TextDecoder().decode(
await simulator.fs.opfs.readFile("parameters/missing-main.var"),
);
expectIncludes(missingMainParameterFile, "5220\t1.000000",
"LinuxCNC missing parameter file was not created through OPFS");
expectIncludes(missingMainParameterFile, "5161\t0.000000",
"LinuxCNC missing parameter file did not include required G28 parameter");
const missingMainRestoreEvents = await simulator.parseWithParameterFile(
"G21 G90\nF100\nO10 if [#5220 EQ 1]\nG1 X6\nO10 endif\n",
"parameters/missing-main.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
expectEvent(missingMainRestoreEvents, (event) => event.type === "linear-feed" && near(event.end.x, 6),
"LinuxCNC-created missing OPFS parameter file was not restored on the next parse");
await expectMissingOpfsFile(
() => simulator.fs.opfs.readFile("parameters/missing-main.var.bak"),
"stale LinuxCNC missing-parameter backup remained in OPFS",
);
expectMissingWasmPath(
() => simulator.fs.module.FS.readFile("rs274ngc.var.bak"),
"stale LinuxCNC missing-parameter backup remained in WASM FS",
);
await expectMissingOpfsFile(
() => simulator.fs.opfs.readFile("parameters/missing-main.var.new"),
"stale LinuxCNC missing-parameter temporary file remained in OPFS",
);
expectMissingWasmPath(
() => simulator.fs.module.FS.readFile("rs274ngc.var.new"),
"stale LinuxCNC missing-parameter temporary file remained in WASM FS",
);
});
await runSection("opfs invalid parameter restore failures", async () => {
await simulator.fs.opfs.writeFile("parameters/out-of-order.var", "5162\t1.000000\n5161\t1.000000\n");
await expectErrorContaining(
() => simulator.parseWithParameterFile(
"G21 G90\nM30\n",
"parameters/out-of-order.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
),
"Parameter file out of order",
"LinuxCNC accepted an out-of-order OPFS parameter file",
);
const outOfOrderParameterFile = new TextDecoder().decode(
await simulator.fs.opfs.readFile("parameters/out-of-order.var"),
);
expectText(outOfOrderParameterFile, "5162\t1.000000\n5161\t1.000000\n",
"LinuxCNC persisted an out-of-order OPFS parameter file after restore failure");
expectMissingWasmPath(
() => simulator.fs.module.FS.readFile("rs274ngc.var"),
"LinuxCNC out-of-order parameter file remained in WASM FS after restore failure",
);
await simulator.fs.opfs.writeFile("parameters/out-of-range.var", "0\t1.000000\n");
await expectErrorContaining(
() => simulator.parseWithParameterFile(
"G21 G90\nM30\n",
"parameters/out-of-range.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
),
"Parameter number out of range",
"LinuxCNC accepted an out-of-range OPFS parameter file",
);
const outOfRangeParameterFile = new TextDecoder().decode(
await simulator.fs.opfs.readFile("parameters/out-of-range.var"),
);
expectText(outOfRangeParameterFile, "0\t1.000000\n",
"LinuxCNC persisted an out-of-range OPFS parameter file after restore failure");
expectMissingWasmPath(
() => simulator.fs.module.FS.readFile("rs274ngc.var"),
"LinuxCNC out-of-range parameter file remained in WASM FS after restore failure",
);
await simulator.fs.opfs.writeFile("parameters/failed-parse.var", "1\t0.000000\n");
await expectErrorContaining(
() => simulator.parseWithParameterFile(
"G21 G90\nG28.1\n#0 = 1\n",
"parameters/failed-parse.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
),
"",
"LinuxCNC accepted a failing parse that should not persist parameters",
);
const failedParseParameterFile = new TextDecoder().decode(
await simulator.fs.opfs.readFile("parameters/failed-parse.var"),
);
if (failedParseParameterFile.includes("5161\t1.000000")) {
throw new Error("LinuxCNC persisted failed parse parameter updates into OPFS");
}
});
await runSection("opfs stale parameter state cleanup", async () => {
await simulator.fs.opfs.writeFile("parameters/stale-state.var", "5161\t1.000000\n");
const staleStateEvents = await simulator.parseWithParameterFile(
"G21 G90\nF100\nO10 if [#5161 EQ 1]\nG1 X9\nO10 endif\n",
"parameters/stale-state.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
expectEvent(staleStateEvents, (event) => event.type === "linear-feed" && near(event.end.x, 9),
"LinuxCNC did not honor the loaded OPFS parameter state");
await simulator.fs.opfs.removeFile("parameters/stale-state.var");
const missingStateEvents = await simulator.parseWithParameterFile(
"G21 G90\nF100\nO10 if [#5161 EQ 1]\nG1 X9\nO10 endif\n",
"parameters/stale-state.var",
"linuxcnc",
{ backend: "linuxcnc-rs274" },
);
expectNoEvent(missingStateEvents, (event) => event.type === "linear-feed" && near(event.end.x, 9),
"LinuxCNC stale OPFS parameter state was not cleared when the file was missing");
// LinuxCNC source basis: rs274ngc_pre.cc restore_parameters()
// treats a missing parameter file as OK; the browser OPFS bridge
// must not leave stale default parameter files in the WASM mirror.
simulator.fs.module.FS.writeFile("rs274ngc.var", "5161\t1.000000\n");
simulator.fs.module.FS.writeFile("rs274ngc.var.new", "stale temporary parameter file\n");
simulator.fs.module.FS.writeFile("rs274ngc.var.bak", "stale backup parameter file\n");
const missingLoad = await simulator.fs.opfs.loadParameterFile("parameters/load-missing.var");
if (missingLoad !== null) {
throw new Error("missing OPFS parameter file did not return null");
}
expectWasmFilesMissing(
simulator.fs.module.FS,
["rs274ngc.var", "rs274ngc.var.new", "rs274ngc.var.bak"],
(parameterPath) => `missing OPFS parameter load left stale WASM file ${parameterPath}`,
);
});
}