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"; 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); }, }); const fixtureNames = [ "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( 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/namedparam_semantics.ngc"), "utf8", ); const namedParamExpected = readFileSync( resolve(rootDir, "tests/fixtures/canon/namedparam_semantics.events"), "utf8", ).trimEnd(); verifyExpectedOutput( "namedparam_semantics", interp.runProgramWithIni(namedParamProgramText, namedParamIniPath), namedParamExpected, ); const errorFixtureNames = [ "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( 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); } const fileFixtureNames = [ "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 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/namedparam_semantics.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/position_params.ngc"), "utf8"), ); verifyExpectedOutput( "position_params_file", interp.runFile(positionParamsFilePath), readFileSync( resolve(rootDir, "tests/fixtures/canon_file/position_params.events"), "utf8", ).trimEnd(), ); console.log("interp_wasm_node_smoke=ok");