import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import createModule from '../../build-wasm/linuxcnc-sim-core.js'; import { loadSimulationCase, toWorkerConfiguration } from '../workspace/sim-case-loader.mjs'; import { SimSession, CONTEXT_ID } from './sim-session.mjs'; import { programMachineMismatch } from '../workspace/program-machine-compatibility.mjs'; for (const [coordinates, forbidden] of [['XYZAC','B'], ['XYZBC','A']]) { for (const value of ['0','-12','[1+2]','#1',' #']) assert.match(programMachineMismatch(`G1X2${forbidden}${value}\nM2`,coordinates,'renamed.ngc'),/不匹配/); for (const source of ['(A10 B20)\nG1X1 ; A30 B40\nM2','#=2\nG1X#\nM2','G1X[ABS[-1]+ATAN[1]/[2]]\nM2','O sub\nG1X1\nO endsub']) assert.equal(programMachineMismatch(source,coordinates,'generic.ngc'),''); } const fetchImpl=async(url)=>{try{const body=await readFile(new URL(`../../${String(url).replace(/^\//,'')}`,import.meta.url));return{ok:true,text:async()=>body.toString()};}catch{return{ok:false,text:async()=>''};}}; const core=await createModule({wasmBinary:await readFile(new URL('../../build-wasm/linuxcnc-sim-core.wasm',import.meta.url))}); const session=new SimSession(core,{sessionId:'compatibility'});let seq=0; const send=(kind,payload={})=>session.accept({schema_version:1,context_id:CONTEXT_ID,session_id:session.sessionId,kind,seq:++seq,operation_id:`compat-${seq}`,payload}); send('HELLO');send('SESSION_ATTACH');const rows=[]; for(const coordinates of ['XYZAC','XYZBC']){ const bundle=await loadSimulationCase({path:`linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/${coordinates.toLowerCase()}-trt.ini`,fetchImpl}); assert.equal(send('LOAD_WORKSPACE',{root_path:'/workspace',configuration:toWorkerConfiguration(bundle)}).kind,'COMMAND_RESULT'); const own=coordinates[3],other=own==='A'?'B':'A'; assert.equal(send('PROGRAM_LOAD',{source:`G21 G90\nG1 X1 ${own}5 C3 F120\nM2\n`,path:'compatible.ngc'}).kind,'COMMAND_RESULT'); const previous=session.xyzacProgram.source; for(const source of [`G1${other}0 F120\nM2\n`,`G1${other}#1 F120\nM2\n`]){ const rejected=send('PROGRAM_LOAD',{source,path:'renamed.ngc'});assert.equal(rejected.kind,'ERROR');assert.match(rejected.payload.gate_reason,/不匹配/);assert.equal(session.xyzacProgram.source,previous); } // Simulate a legacy/recovered taskfile bypassing the loading gate. session.xyzacProgram.source=`G1 ${other}10 F120\nM2\n`;session.xyzacProgram.executionSource=session.xyzacProgram.source; for(const kind of ['PROGRAM_RUN','PROGRAM_STEP','PROGRAM_RESUME']){const rejected=send(kind);assert.equal(rejected.kind,'ERROR');assert.match(rejected.payload.gate_reason,/不匹配/);} session.xyzacProgram.source=previous;session.xyzacProgram.executionSource=previous; assert.equal(send('PROGRAM_LOAD',{source:'(A and B mentioned in comments)\nG21 G90\nG1 X1 F120\nM2\n',path:'generic.ngc'}).kind,'COMMAND_RESULT'); rows.push({coordinates,load_rejected:true,legacy_execution_rejected:true,generic_allowed:true}); } console.log(JSON.stringify({report_id:'TRT-PROGRAM-COMPAT-WORKER',status:'verified',rows}));