补充 Node WASM 文件路径错误覆盖

结论:Node WASM 解释器 smoke 现在通过 Interp::open/read/execute 文件路径 ABI 验证现有负向 G-code fixture 的 LinuxCNC 错误输出。
This commit is contained in:
2026-06-08 10:38:01 +08:00
parent 3766b99e70
commit a0205a056b
2 changed files with 74 additions and 1 deletions

View File

@@ -93,7 +93,10 @@ Emscripten filesystem through the SDK and runs them through LinuxCNC
file execution path. The same Node smoke writes LinuxCNC-format parameter
files into the Emscripten filesystem and validates vendored
`Interp::restore_parameters()` and `Interp::save_parameters()`, including the
saved parameter values and `.bak` backup file boundary.
saved parameter values and `.bak` backup file boundary. It also writes the
negative G-code fixtures into the Emscripten filesystem and verifies their
LinuxCNC-produced error text through the `Interp::open()`/`read()`/`execute()`
file path.
The OPFS host-boundary script validates the JavaScript file-service adapter
with a Node mock of the browser File System Access handles. It covers nested
@@ -260,6 +263,9 @@ path additionally covers the same canonical-event fixture group, plus
`position_params` uses a dedicated file-path expectation under
`tests/fixtures/canon_file/` because LinuxCNC file execution advances the
post-execute position parameters differently than the line-by-line MDI smoke.
The same Node WASM file-path smoke also covers the negative fixture group and
checks the LinuxCNC file-execution error text plus absent canonical motion
constraints where applicable.
The Node WASM interpreter smoke also covers LinuxCNC parameter-file
restore/save behavior through the exported C ABI, including out-of-order file
rejection, missing-file success, required numeric parameter writeback, removal
@@ -356,6 +362,19 @@ Node WASM file-path coverage currently includes:
- `position_params` through the dedicated `canon_file/` expectation
- `namedparam_semantics` through the INI-aware file ABI
Node WASM file-path negative coverage currently includes every fixture under
`tests/fixtures/gcode_errors/`:
- `g1_zero_feed`
- `arc_radius_mismatch`
- `arc_zero_radius`
- `cutter_comp_plane_change`
- `g53_incremental`
- `namedparam_readonly`
- `numbered_param_readonly`
- `tool_length_offset_not_found`
- `tool_not_found`
Browser interpreter `Interp::execute()` coverage currently includes:
- `minimal_linear`

View File

@@ -34,6 +34,45 @@ function verifyExpectedOutput(fixtureName, output, expectedText) {
}
}
function verifyExpectedFileError(fixtureName, output, expectedText) {
assert.equal(
output.includes("file_open=0"),
true,
`${fixtureName}: file open`,
);
const expectedLines = expectedText.split("\n").filter(Boolean);
for (const expectedLine of expectedLines) {
if (expectedLine.startsWith("absent=")) {
const forbidden = expectedLine.slice("absent=".length);
assert.equal(
output.includes(forbidden),
false,
`${fixtureName}: unexpected ${forbidden}`,
);
continue;
}
if (expectedLine.startsWith("error_text=")) {
const message = expectedLine.slice("error_text=".length);
assert.equal(
output.includes(`file_error_text=${message}`),
true,
`${fixtureName}: ${message}`,
);
continue;
}
if (expectedLine.startsWith("canon_event=")) {
assert.equal(
output.includes(expectedLine),
true,
`${fixtureName}: ${expectedLine}`,
);
}
}
}
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const rootDir = resolve(__dirname, "../../..");
@@ -92,6 +131,21 @@ for (const fixtureName of INTERP_ERROR_FIXTURES) {
verifyExpectedOutput(fixtureName, interp.runProgram(programText), expectedOutput);
}
for (const fixtureName of INTERP_ERROR_FIXTURES) {
const programPath = `/work/${fixtureName}-error.ngc`;
const programText = readFileSync(
resolve(rootDir, `tests/fixtures/gcode_errors/${fixtureName}.ngc`),
"utf8",
);
const expectedOutput = readFileSync(
resolve(rootDir, `tests/fixtures/canon_errors/${fixtureName}.expected`),
"utf8",
).trimEnd();
interp.writeTextFile(programPath, programText);
verifyExpectedFileError(fixtureName, interp.runFile(programPath), expectedOutput);
}
for (const fixtureName of INTERP_FILE_FIXTURES) {
const programPath = `/work/${fixtureName}.ngc`;
const programText = readFileSync(