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");