按规划继续工作

结论:解释器 Node WASM 与浏览器 smoke 已统一使用共享 fixture 矩阵,聚合 host/WASM/browser 验证通过。
This commit is contained in:
2026-06-08 07:28:50 +08:00
parent 706fd1e775
commit e5697970df
4 changed files with 133 additions and 123 deletions

View File

@@ -236,6 +236,12 @@ machine-session validation remain future work.
## WASM/Browser Fixture Matrix ## WASM/Browser Fixture Matrix
The executable fixture lists for Node WASM and browser interpreter smoke tests
are centralized in `tests/fixtures/interp-fixture-matrix.mjs`. Additions to the
matrix must continue to route execution through the SDK and exported C ABI
backed by vendored LinuxCNC interpreter code; the matrix is only a test
coverage list, not a CNC behavior implementation.
Node WASM `Interp::execute()` coverage currently includes: Node WASM `Interp::execute()` coverage currently includes:
- `minimal_linear` - `minimal_linear`

View File

@@ -8,6 +8,13 @@
<pre id="status">running</pre> <pre id="status">running</pre>
<script type="module"> <script type="module">
import { createLinuxCncInterpSdk } from "../../runtime/sdk/src/index.js"; import { createLinuxCncInterpSdk } from "../../runtime/sdk/src/index.js";
import {
INTERP_BROWSER_FILE_FIXTURES,
INTERP_BROWSER_MDI_FIXTURES,
INTERP_ERROR_FIXTURES,
INTERP_INI_FIXTURE,
INTERP_POSITION_PARAMS_FILE_FIXTURE,
} from "../fixtures/interp-fixture-matrix.mjs";
const status = document.getElementById("status"); const status = document.getElementById("status");
@@ -49,47 +56,13 @@
}, },
}); });
for (const fixtureName of [ for (const fixtureName of INTERP_BROWSER_MDI_FIXTURES) {
"minimal_linear",
"arc_semantics",
"length_units",
"modal_incremental",
"plane_selection",
"coordinate_offsets",
"g53_machine_coordinates",
"feed_control_modes",
"canned_cycles",
"numbered_params",
"comment_logging",
"tool_semantics",
"tool_table_setup",
"probe_semantics",
"spindle_orient",
"cutter_comp_motion",
"threading_sync",
"nurbs_g5_semantics",
"nurbs_g6_semantics",
"state_tag_motion",
"canon_runtime_edges",
"tool_reload",
"program_end_modal_reset",
]) {
const programText = await fetchText(`../fixtures/gcode/${fixtureName}.ngc`); const programText = await fetchText(`../fixtures/gcode/${fixtureName}.ngc`);
const expectedText = await fetchText(`../fixtures/canon/${fixtureName}.events`); const expectedText = await fetchText(`../fixtures/canon/${fixtureName}.events`);
verifyExpectedOutput(fixtureName, interp.runProgram(programText), expectedText.trimEnd()); verifyExpectedOutput(fixtureName, interp.runProgram(programText), expectedText.trimEnd());
} }
for (const errorFixtureName of [ for (const errorFixtureName of INTERP_ERROR_FIXTURES) {
"g1_zero_feed",
"arc_radius_mismatch",
"arc_zero_radius",
"g53_incremental",
"cutter_comp_plane_change",
"namedparam_readonly",
"numbered_param_readonly",
"tool_length_offset_not_found",
"tool_not_found",
]) {
verifyExpectedOutput( verifyExpectedOutput(
errorFixtureName, errorFixtureName,
interp.runProgram(await fetchText(`../fixtures/gcode_errors/${errorFixtureName}.ngc`)), interp.runProgram(await fetchText(`../fixtures/gcode_errors/${errorFixtureName}.ngc`)),
@@ -97,16 +70,22 @@
); );
} }
const positionParamsText = await fetchText("../fixtures/gcode/position_params.ngc"); const positionParamsText = await fetchText(
const positionParamsPath = "/work/position_params.ngc"; `../fixtures/gcode/${INTERP_POSITION_PARAMS_FILE_FIXTURE}.ngc`,
);
const positionParamsPath = `/work/${INTERP_POSITION_PARAMS_FILE_FIXTURE}.ngc`;
interp.writeTextFile(positionParamsPath, positionParamsText); interp.writeTextFile(positionParamsPath, positionParamsText);
verifyExpectedOutput( verifyExpectedOutput(
"position_params_file", `${INTERP_POSITION_PARAMS_FILE_FIXTURE}_file`,
interp.runFile(positionParamsPath), interp.runFile(positionParamsPath),
(await fetchText("../fixtures/canon_file/position_params.events")).trimEnd(), (
await fetchText(
`../fixtures/canon_file/${INTERP_POSITION_PARAMS_FILE_FIXTURE}.events`,
)
).trimEnd(),
); );
for (const fileFixtureName of ["file_open_reset", "percent_file_finish", "oword_subroutine"]) { for (const fileFixtureName of INTERP_BROWSER_FILE_FIXTURES) {
const programPath = `/work/${fileFixtureName}.ngc`; const programPath = `/work/${fileFixtureName}.ngc`;
interp.writeTextFile(programPath, await fetchText(`../fixtures/gcode/${fileFixtureName}.ngc`)); interp.writeTextFile(programPath, await fetchText(`../fixtures/gcode/${fileFixtureName}.ngc`));
verifyExpectedOutput( verifyExpectedOutput(
@@ -118,15 +97,15 @@
const namedParamIniPath = "/work/namedparams.ini"; const namedParamIniPath = "/work/namedparams.ini";
interp.writeTextFile(namedParamIniPath, await fetchText("../fixtures/ini/namedparams.ini")); interp.writeTextFile(namedParamIniPath, await fetchText("../fixtures/ini/namedparams.ini"));
const namedParamPath = "/work/namedparam_semantics.ngc"; const namedParamPath = `/work/${INTERP_INI_FIXTURE}.ngc`;
interp.writeTextFile( interp.writeTextFile(
namedParamPath, namedParamPath,
await fetchText("../fixtures/gcode/namedparam_semantics.ngc"), await fetchText(`../fixtures/gcode/${INTERP_INI_FIXTURE}.ngc`),
); );
verifyExpectedOutput( verifyExpectedOutput(
"namedparam_semantics_file", `${INTERP_INI_FIXTURE}_file`,
interp.runFileWithIni(namedParamPath, namedParamIniPath), interp.runFileWithIni(namedParamPath, namedParamIniPath),
(await fetchText("../fixtures/canon/namedparam_semantics.events")).trimEnd(), (await fetchText(`../fixtures/canon/${INTERP_INI_FIXTURE}.events`)).trimEnd(),
); );
status.textContent = "browser_interp_smoke=ok"; status.textContent = "browser_interp_smoke=ok";

View File

@@ -0,0 +1,80 @@
export const INTERP_MDI_FIXTURES = [
"minimal_linear",
"arc_semantics",
"length_units",
"modal_incremental",
"plane_selection",
"coordinate_offsets",
"g53_machine_coordinates",
"feed_control_modes",
"position_params",
"probe_semantics",
"spindle_orient",
"comment_logging",
"numbered_params",
"tool_semantics",
"tool_table_setup",
"tool_reload",
"canned_cycles",
"cutter_comp_motion",
"threading_sync",
"nurbs_g5_semantics",
"nurbs_g6_semantics",
"state_tag_motion",
"canon_runtime_edges",
"program_end_modal_reset",
];
export const INTERP_BROWSER_MDI_FIXTURES = INTERP_MDI_FIXTURES.filter(
(fixtureName) => fixtureName !== "position_params",
);
export const INTERP_ERROR_FIXTURES = [
"g1_zero_feed",
"arc_radius_mismatch",
"arc_zero_radius",
"cutter_comp_plane_change",
"g53_incremental",
"namedparam_readonly",
"numbered_param_readonly",
"tool_not_found",
"tool_length_offset_not_found",
];
export const INTERP_FILE_FIXTURES = [
"minimal_linear",
"arc_semantics",
"length_units",
"modal_incremental",
"plane_selection",
"coordinate_offsets",
"g53_machine_coordinates",
"feed_control_modes",
"probe_semantics",
"spindle_orient",
"comment_logging",
"numbered_params",
"tool_semantics",
"tool_table_setup",
"tool_reload",
"canned_cycles",
"cutter_comp_motion",
"threading_sync",
"nurbs_g5_semantics",
"nurbs_g6_semantics",
"state_tag_motion",
"canon_runtime_edges",
"program_end_modal_reset",
"file_open_reset",
"percent_file_finish",
"oword_subroutine",
];
export const INTERP_BROWSER_FILE_FIXTURES = [
"file_open_reset",
"percent_file_finish",
"oword_subroutine",
];
export const INTERP_INI_FIXTURE = "namedparam_semantics";
export const INTERP_POSITION_PARAMS_FILE_FIXTURE = "position_params";

View File

@@ -4,6 +4,13 @@ import { dirname, resolve } from "node:path";
import assert from "node:assert/strict"; import assert from "node:assert/strict";
import { createLinuxCncInterpSdk } from "../../../runtime/sdk/src/index.js"; import { createLinuxCncInterpSdk } from "../../../runtime/sdk/src/index.js";
import {
INTERP_ERROR_FIXTURES,
INTERP_FILE_FIXTURES,
INTERP_INI_FIXTURE,
INTERP_MDI_FIXTURES,
INTERP_POSITION_PARAMS_FILE_FIXTURE,
} from "../../fixtures/interp-fixture-matrix.mjs";
function verifyExpectedOutput(fixtureName, output, expectedText) { function verifyExpectedOutput(fixtureName, output, expectedText) {
const expectedLines = expectedText.split("\n").filter(Boolean); const expectedLines = expectedText.split("\n").filter(Boolean);
@@ -40,34 +47,7 @@ const interp = await createLinuxCncInterpSdk({
}, },
}); });
const fixtureNames = [ for (const fixtureName of INTERP_MDI_FIXTURES) {
"minimal_linear",
"arc_semantics",
"length_units",
"modal_incremental",
"plane_selection",
"coordinate_offsets",
"g53_machine_coordinates",
"feed_control_modes",
"position_params",
"probe_semantics",
"spindle_orient",
"comment_logging",
"numbered_params",
"tool_semantics",
"tool_table_setup",
"tool_reload",
"canned_cycles",
"cutter_comp_motion",
"threading_sync",
"nurbs_g5_semantics",
"nurbs_g6_semantics",
"state_tag_motion",
"canon_runtime_edges",
"program_end_modal_reset",
];
for (const fixtureName of fixtureNames) {
const programText = readFileSync( const programText = readFileSync(
resolve(rootDir, `tests/fixtures/gcode/${fixtureName}.ngc`), resolve(rootDir, `tests/fixtures/gcode/${fixtureName}.ngc`),
"utf8", "utf8",
@@ -86,32 +66,20 @@ interp.writeTextFile(
readFileSync(resolve(rootDir, "tests/fixtures/ini/namedparams.ini"), "utf8"), readFileSync(resolve(rootDir, "tests/fixtures/ini/namedparams.ini"), "utf8"),
); );
const namedParamProgramText = readFileSync( const namedParamProgramText = readFileSync(
resolve(rootDir, "tests/fixtures/gcode/namedparam_semantics.ngc"), resolve(rootDir, `tests/fixtures/gcode/${INTERP_INI_FIXTURE}.ngc`),
"utf8", "utf8",
); );
const namedParamExpected = readFileSync( const namedParamExpected = readFileSync(
resolve(rootDir, "tests/fixtures/canon/namedparam_semantics.events"), resolve(rootDir, `tests/fixtures/canon/${INTERP_INI_FIXTURE}.events`),
"utf8", "utf8",
).trimEnd(); ).trimEnd();
verifyExpectedOutput( verifyExpectedOutput(
"namedparam_semantics", INTERP_INI_FIXTURE,
interp.runProgramWithIni(namedParamProgramText, namedParamIniPath), interp.runProgramWithIni(namedParamProgramText, namedParamIniPath),
namedParamExpected, namedParamExpected,
); );
const errorFixtureNames = [ for (const fixtureName of INTERP_ERROR_FIXTURES) {
"g1_zero_feed",
"arc_radius_mismatch",
"arc_zero_radius",
"cutter_comp_plane_change",
"g53_incremental",
"namedparam_readonly",
"numbered_param_readonly",
"tool_not_found",
"tool_length_offset_not_found",
];
for (const fixtureName of errorFixtureNames) {
const programText = readFileSync( const programText = readFileSync(
resolve(rootDir, `tests/fixtures/gcode_errors/${fixtureName}.ngc`), resolve(rootDir, `tests/fixtures/gcode_errors/${fixtureName}.ngc`),
"utf8", "utf8",
@@ -124,36 +92,7 @@ for (const fixtureName of errorFixtureNames) {
verifyExpectedOutput(fixtureName, interp.runProgram(programText), expectedOutput); verifyExpectedOutput(fixtureName, interp.runProgram(programText), expectedOutput);
} }
const fileFixtureNames = [ for (const fixtureName of INTERP_FILE_FIXTURES) {
"minimal_linear",
"arc_semantics",
"length_units",
"modal_incremental",
"plane_selection",
"coordinate_offsets",
"g53_machine_coordinates",
"feed_control_modes",
"probe_semantics",
"spindle_orient",
"comment_logging",
"numbered_params",
"tool_semantics",
"tool_table_setup",
"tool_reload",
"canned_cycles",
"cutter_comp_motion",
"threading_sync",
"nurbs_g5_semantics",
"nurbs_g6_semantics",
"state_tag_motion",
"canon_runtime_edges",
"program_end_modal_reset",
"file_open_reset",
"percent_file_finish",
"oword_subroutine",
];
for (const fixtureName of fileFixtureNames) {
const programPath = `/work/${fixtureName}.ngc`; const programPath = `/work/${fixtureName}.ngc`;
const programText = readFileSync( const programText = readFileSync(
resolve(rootDir, `tests/fixtures/gcode/${fixtureName}.ngc`), resolve(rootDir, `tests/fixtures/gcode/${fixtureName}.ngc`),
@@ -168,7 +107,7 @@ for (const fixtureName of fileFixtureNames) {
verifyExpectedOutput(fixtureName, interp.runFile(programPath), expectedEvents); verifyExpectedOutput(fixtureName, interp.runFile(programPath), expectedEvents);
} }
const namedParamFilePath = "/work/namedparam_semantics.ngc"; const namedParamFilePath = `/work/${INTERP_INI_FIXTURE}.ngc`;
interp.writeTextFile(namedParamFilePath, namedParamProgramText); interp.writeTextFile(namedParamFilePath, namedParamProgramText);
verifyExpectedOutput( verifyExpectedOutput(
"namedparam_semantics_file", "namedparam_semantics_file",
@@ -179,13 +118,19 @@ verifyExpectedOutput(
const positionParamsFilePath = "/work/position_params.ngc"; const positionParamsFilePath = "/work/position_params.ngc";
interp.writeTextFile( interp.writeTextFile(
positionParamsFilePath, positionParamsFilePath,
readFileSync(resolve(rootDir, "tests/fixtures/gcode/position_params.ngc"), "utf8"), readFileSync(
resolve(rootDir, `tests/fixtures/gcode/${INTERP_POSITION_PARAMS_FILE_FIXTURE}.ngc`),
"utf8",
),
); );
verifyExpectedOutput( verifyExpectedOutput(
"position_params_file", `${INTERP_POSITION_PARAMS_FILE_FIXTURE}_file`,
interp.runFile(positionParamsFilePath), interp.runFile(positionParamsFilePath),
readFileSync( readFileSync(
resolve(rootDir, "tests/fixtures/canon_file/position_params.events"), resolve(
rootDir,
`tests/fixtures/canon_file/${INTERP_POSITION_PARAMS_FILE_FIXTURE}.events`,
),
"utf8", "utf8",
).trimEnd(), ).trimEnd(),
); );