结论:接入 vendored LinuxCNC tooldata_common.cc 负责刀具表解析与保存,WASM/SDK/OPFS/UI 仅做运行时边界搬运;native、WASM、OPFS 和浏览器 smoke 验证已通过。
260 lines
7.4 KiB
JavaScript
260 lines
7.4 KiB
JavaScript
import { readFileSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
import { dirname, resolve } from "node:path";
|
|
import assert from "node:assert/strict";
|
|
|
|
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) {
|
|
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;
|
|
}
|
|
|
|
assert.equal(
|
|
output.includes(expectedLine),
|
|
true,
|
|
`${fixtureName}: ${expectedLine}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
const rootDir = resolve(__dirname, "../../..");
|
|
const wasmPath = resolve(rootDir, "build/wasm/core/linuxcnc_interp.wasm");
|
|
|
|
const interp = await createLinuxCncInterpSdk({
|
|
wasmBinary: readFileSync(wasmPath),
|
|
print() {},
|
|
printErr(message) {
|
|
console.error(message);
|
|
},
|
|
});
|
|
|
|
for (const fixtureName of INTERP_MDI_FIXTURES) {
|
|
const programText = readFileSync(
|
|
resolve(rootDir, `tests/fixtures/gcode/${fixtureName}.ngc`),
|
|
"utf8",
|
|
);
|
|
const expectedEvents = readFileSync(
|
|
resolve(rootDir, `tests/fixtures/canon/${fixtureName}.events`),
|
|
"utf8",
|
|
).trimEnd();
|
|
|
|
verifyExpectedOutput(fixtureName, interp.runProgram(programText), expectedEvents);
|
|
}
|
|
|
|
const namedParamIniPath = "/work/namedparams.ini";
|
|
interp.writeTextFile(
|
|
namedParamIniPath,
|
|
readFileSync(resolve(rootDir, "tests/fixtures/ini/namedparams.ini"), "utf8"),
|
|
);
|
|
const namedParamProgramText = readFileSync(
|
|
resolve(rootDir, `tests/fixtures/gcode/${INTERP_INI_FIXTURE}.ngc`),
|
|
"utf8",
|
|
);
|
|
const namedParamExpected = readFileSync(
|
|
resolve(rootDir, `tests/fixtures/canon/${INTERP_INI_FIXTURE}.events`),
|
|
"utf8",
|
|
).trimEnd();
|
|
verifyExpectedOutput(
|
|
INTERP_INI_FIXTURE,
|
|
interp.runProgramWithIni(namedParamProgramText, namedParamIniPath),
|
|
namedParamExpected,
|
|
);
|
|
|
|
for (const fixtureName of INTERP_ERROR_FIXTURES) {
|
|
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();
|
|
|
|
verifyExpectedOutput(fixtureName, interp.runProgram(programText), expectedOutput);
|
|
}
|
|
|
|
for (const fixtureName of INTERP_FILE_FIXTURES) {
|
|
const programPath = `/work/${fixtureName}.ngc`;
|
|
const programText = readFileSync(
|
|
resolve(rootDir, `tests/fixtures/gcode/${fixtureName}.ngc`),
|
|
"utf8",
|
|
);
|
|
const expectedEvents = readFileSync(
|
|
resolve(rootDir, `tests/fixtures/canon/${fixtureName}.events`),
|
|
"utf8",
|
|
).trimEnd();
|
|
|
|
interp.writeTextFile(programPath, programText);
|
|
verifyExpectedOutput(fixtureName, interp.runFile(programPath), expectedEvents);
|
|
}
|
|
|
|
const namedParamFilePath = `/work/${INTERP_INI_FIXTURE}.ngc`;
|
|
interp.writeTextFile(namedParamFilePath, namedParamProgramText);
|
|
verifyExpectedOutput(
|
|
"namedparam_semantics_file",
|
|
interp.runFileWithIni(namedParamFilePath, namedParamIniPath),
|
|
namedParamExpected,
|
|
);
|
|
|
|
const positionParamsFilePath = "/work/position_params.ngc";
|
|
interp.writeTextFile(
|
|
positionParamsFilePath,
|
|
readFileSync(
|
|
resolve(rootDir, `tests/fixtures/gcode/${INTERP_POSITION_PARAMS_FILE_FIXTURE}.ngc`),
|
|
"utf8",
|
|
),
|
|
);
|
|
verifyExpectedOutput(
|
|
`${INTERP_POSITION_PARAMS_FILE_FIXTURE}_file`,
|
|
interp.runFile(positionParamsFilePath),
|
|
readFileSync(
|
|
resolve(
|
|
rootDir,
|
|
`tests/fixtures/canon_file/${INTERP_POSITION_PARAMS_FILE_FIXTURE}.events`,
|
|
),
|
|
"utf8",
|
|
).trimEnd(),
|
|
);
|
|
|
|
const parameterFilePath = "/work/rs274ngc.var";
|
|
interp.writeTextFile(
|
|
parameterFilePath,
|
|
[
|
|
"5161 10.5",
|
|
"5162 20.25",
|
|
"5220 1",
|
|
"5221 2.25",
|
|
"5399 44",
|
|
"<_named_param> 123",
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
verifyExpectedOutput(
|
|
"restore_parameters",
|
|
interp.restoreParameters(parameterFilePath),
|
|
[
|
|
"restore_parameters=0",
|
|
"parameter_5161=10.5",
|
|
"parameter_5162=20.25",
|
|
"parameter_5220=1",
|
|
"parameter_5221=2.25",
|
|
"parameter_5399=44",
|
|
].join("\n"),
|
|
);
|
|
verifyExpectedOutput(
|
|
"restore_parameters_missing_file",
|
|
interp.restoreParameters("/work/missing.var"),
|
|
"restore_parameters=0",
|
|
);
|
|
|
|
const outOfOrderParameterFilePath = "/work/out-of-order.var";
|
|
interp.writeTextFile(outOfOrderParameterFilePath, "5220 1\n5161 2\n");
|
|
verifyExpectedOutput(
|
|
"restore_parameters_out_of_order",
|
|
interp.restoreParameters(outOfOrderParameterFilePath),
|
|
[
|
|
"restore_parameters=5",
|
|
"restore_error_text=Parameter file out of order",
|
|
].join("\n"),
|
|
);
|
|
|
|
verifyExpectedOutput(
|
|
"save_parameters",
|
|
interp.saveParameters(parameterFilePath, {
|
|
5161: 12.34,
|
|
5162: 56.78,
|
|
5220: 1.0,
|
|
5221: 9.87,
|
|
5399: 66.6,
|
|
}),
|
|
[
|
|
"save_parameters=0",
|
|
"parameter_5161=12.34",
|
|
"parameter_5162=56.78",
|
|
"parameter_5220=1",
|
|
"parameter_5221=9.87",
|
|
"parameter_5399=66.6",
|
|
].join("\n"),
|
|
);
|
|
const savedParameterFile = interp.readTextFile(parameterFilePath);
|
|
const backupParameterFile = interp.readTextFile(`${parameterFilePath}.bak`);
|
|
assert.equal(savedParameterFile.includes("5161\t12.340000"), true);
|
|
assert.equal(savedParameterFile.includes("5162\t56.780000"), true);
|
|
assert.equal(savedParameterFile.includes("5221\t9.870000"), true);
|
|
assert.equal(savedParameterFile.includes("5399\t66.600000"), true);
|
|
assert.equal(savedParameterFile.includes("_named_param"), false);
|
|
assert.equal(backupParameterFile.includes("5161 10.5"), true);
|
|
|
|
const toolTablePath = "/work/tool.tbl";
|
|
interp.writeTextFile(
|
|
toolTablePath,
|
|
[
|
|
"T2 P7 Z3.125 D1.5 I12 J34 Q4 ;finish tool",
|
|
"T5 P9 X1 Y2 Z3 ;rough tool",
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
verifyExpectedOutput(
|
|
"load_tool_table",
|
|
interp.loadToolTable(toolTablePath),
|
|
[
|
|
"tooldata_load=0",
|
|
"tooldata_last_index=2",
|
|
"tool_0.toolno=-1",
|
|
"tool_1.toolno=2",
|
|
"tool_1.pocketno=7",
|
|
"tool_1.z=3.125",
|
|
"tool_1.diameter=1.5",
|
|
"tool_1.frontangle=12",
|
|
"tool_1.backangle=34",
|
|
"tool_1.orientation=4",
|
|
"tool_1.comment=finish tool",
|
|
"tool_2.toolno=5",
|
|
"tool_2.pocketno=9",
|
|
"tool_2.z=3",
|
|
"tool_2.comment=rough tool",
|
|
"tool_index_for_tool_2=1",
|
|
].join("\n"),
|
|
);
|
|
verifyExpectedOutput(
|
|
"save_tool_table",
|
|
interp.saveToolTable(toolTablePath),
|
|
[
|
|
"tooldata_save=0",
|
|
"tool_1.toolno=2",
|
|
"tool_2.toolno=5",
|
|
].join("\n"),
|
|
);
|
|
const savedToolTable = interp.readTextFile(toolTablePath);
|
|
assert.equal(savedToolTable.includes("T2"), true);
|
|
assert.equal(savedToolTable.includes("P7"), true);
|
|
assert.equal(savedToolTable.includes("D+1.500000"), true);
|
|
assert.equal(savedToolTable.includes("Z+3.125000"), true);
|
|
assert.equal(savedToolTable.includes("I+12.000000"), true);
|
|
assert.equal(savedToolTable.includes("J+34.000000"), true);
|
|
assert.equal(savedToolTable.includes("Q4"), true);
|
|
assert.equal(savedToolTable.includes(";finish tool"), true);
|
|
assert.equal(savedToolTable.includes("T5"), true);
|
|
assert.equal(savedToolTable.includes("P9"), true);
|
|
assert.equal(savedToolTable.includes(";rough tool"), true);
|
|
console.log("interp_wasm_node_smoke=ok");
|