import test from 'node:test' import assert from 'node:assert/strict' import { createCamJob } from '../src/facade/cam' import { CAM_PIPELINE_ORDER, camoticsSourceEvidence, prepareCamPipeline, submitCamPipelineToLinuxcnc } from '../src/facade/camPipeline' import { OPEN_CAM_LIB_ARTIFACT_SHA256, OPEN_CAM_LIB_SOURCE_REVISION, type OpenCamLibDropCutterInput } from '../src/facade/camNativeSimulation' const job = () => { const cam = createCamJob('pipeline', 'CAD/OCL/CAMotics/LinuxCNC') cam.addTool({ id: 'T1', name: 'end mill', diameter: 2, length: 20 }) cam.addOperation({ id: 'profile', kind: 'profile', toolId: 'T1', depth: 1, feed: 100 }) cam.generatePath('profile') return cam } const openCamLibRunner = async (input: OpenCamLibDropCutterInput) => ({ backend: 'upstream-opencamlib-wasm' as const, sourceRevision: OPEN_CAM_LIB_SOURCE_REVISION, artifactSha256: OPEN_CAM_LIB_ARTIFACT_SHA256, algorithm: 'path-drop-cutter' as const, triangleCount: input.triangles.length, points: input.path.map((point) => [...point] as [number, number, number]), }) test('pipeline evidence pins CAMotics source and canonical LinuxCNC policy', () => { assert.deepEqual(CAM_PIPELINE_ORDER, ['CAD', 'OCL', 'CAMotics', 'GCODE', 'LinuxCNC WASM']) const evidence = camoticsSourceEvidence() assert.equal(evidence.backend, 'camotics-source') assert.equal(evidence.generator, 'camotics-source-stage') assert.equal(evidence.workspaceNativeCli, 'verified-sidecar') assert.equal(evidence.browserNativeExecutable, false) assert.equal(evidence.parserAuthority, 'linuxcnc-wasm') assert.equal(evidence.camoticsParsesCanonicalGcode, false) assert.equal(evidence.sourceRevision.length, 40) }) test('LinuxCNC WASM cannot be called before the OCL and G-code stages are prepared', async () => { const prepared = await prepareCamPipeline(job(), 'profile', { openCamLib: { runner: openCamLibRunner } }) assert.equal(prepared.stage, 'GCODE') assert.equal(prepared.openCamLib.backend, 'upstream-opencamlib-wasm') assert.equal(prepared.openCamLib.inputPoints, 5) assert.equal(prepared.openCamLib.outputPoints, 5) const submitted = await submitCamPipelineToLinuxcnc(prepared, { submit: async (program) => ({ backend: 'linuxcnc-wasm', status: 'dry-run', programSha256: String(program.length) }), }) assert.equal(submitted.stage, 'LinuxCNC WASM') assert.equal(submitted.linuxcnc?.status, 'dry-run') assert.match(submitted.gcode, /G90/) assert.match(submitted.camoticsMotionGcode, /G1 X/) }) test('pipeline rejects non-LinuxCNC posts before any machine submission', async () => { await assert.rejects(() => prepareCamPipeline(job(), 'profile', { postprocessor: 'grbl', openCamLib: { runner: openCamLibRunner } }), /requires the linuxcnc postprocessor/) }) test('pipeline rejects an unpinned OCL result instead of bypassing the native stage', async () => { await assert.rejects(() => prepareCamPipeline(job(), 'profile', { openCamLib: { runner: async (input) => ({ ...await openCamLibRunner(input), sourceRevision: '0'.repeat(40) }) } }), /pinned upstream WASM identity/) })