Files
Web_FreeCAD_Bitbybit/tests/freecadCamPathOracle.test.mjs

108 lines
6.3 KiB
JavaScript

import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import test from 'node:test'
const report = JSON.parse(await readFile(new URL('../config/freecad-cam-path-oracle.json', import.meta.url), 'utf8'))
const commandGcode = (object) => object.commands.map((command) => command.gcode)
const objectByName = (objects, name) => objects.find((object) => object.name === name)
test('native Profile oracle is a locked FreeCAD algorithm result', () => {
assert.equal(report.profileAlgorithm.operationTypeId, 'Path::FeaturePython')
assert.equal(report.profileAlgorithm.pathPropertyType, 'Path::PropertyPath')
assert.equal(report.profileAlgorithm.commandCount, 32)
assert.equal(report.profileAlgorithm.cuttingCommandCount, 20)
assert.equal(report.profileAlgorithm.normalizationToleranceMm, 0.01)
assert.equal(report.profileAlgorithm.commandSha256, '5fcc36e3fc3c022599096f4110c890401f285b5878030de7c481786470a7a455')
assert.deepEqual(report.profileAlgorithm.variants.map((variant) => ({ id: variant.id, useComp: variant.useComp, hash: variant.commandSha256 })), [
{ id: 'outside-cw-tool-comp', useComp: true, hash: '5fcc36e3fc3c022599096f4110c890401f285b5878030de7c481786470a7a455' },
{ id: 'outside-cw-no-comp', useComp: false, hash: 'c4c8bc58c4b21bc7be8796ff5d074fbe02656e31a26cc91ee65a67537a7d240a' },
])
})
test('native Helix oracle locks all four cut-direction combinations', () => {
assert.equal(report.helixAlgorithm.fixture, 'Mod/CAM/CAMTests/test_holes00.fcstd')
assert.equal(report.helixAlgorithm.baseSubElementCount, 9)
assert.equal(report.helixAlgorithm.toolDiameterMm, 0.9)
assert.deepEqual(report.helixAlgorithm.scenarios.map((scenario) => ({
id: scenario.id,
direction: scenario.direction,
arcs: scenario.arcNames,
arcCount: scenario.arcCommandCount,
hash: scenario.commandSha256,
})), [
{ id: 'inside-conventional', direction: 'CW', arcs: ['G2'], arcCount: 1260, hash: '6499583c26dbf01694abc0a98fdbeb9d240cce0f73d32634284ddfa132030e0b' },
{ id: 'outside-climb', direction: 'CW', arcs: ['G2'], arcCount: 1260, hash: '37ee85fe360bfa82235f1b7aefce31cb7150900bb8d6f08751741fce6df18626' },
{ id: 'inside-climb', direction: 'CCW', arcs: ['G3'], arcCount: 1260, hash: 'f2fd26ca11be5efb037f809fb65949d24956f6ce330f87d152d2674770a27bd8' },
{ id: 'outside-conventional', direction: 'CCW', arcs: ['G3'], arcCount: 1260, hash: '0220f90245a74a50c1a54cb501439d14e7370d9d9d34fcc89dccdaff345688b7' },
])
})
test('Path Feature and FeaturePython survive native save-open-mutate-save-open', () => {
for (const name of ['NativePath', 'PythonPath']) {
const before = objectByName(report.fcstdRoundTrip.sourceBeforeClose, name)
const reopened = objectByName(report.fcstdRoundTrip.sourceReopened, name)
const mutated = objectByName(report.fcstdRoundTrip.mutatedReopened, name)
assert.deepEqual(commandGcode(reopened), commandGcode(before))
assert.deepEqual(commandGcode(mutated).slice(0, 5), commandGcode(before))
assert.equal(mutated.commandCount, 6)
assert.equal(mutated.commands.at(-1).name, name === 'NativePath' ? 'M5' : 'M2')
}
})
test('Web byte-transparent proxy reopens natively without changing Path commands', () => {
assert.equal(report.fcstdRoundTrip.webTransparentPreservation.byteExact, true)
assert.equal(report.fcstdRoundTrip.webTransparentPreservation.nativeReopenVerified, true)
for (const name of ['NativePath', 'PythonPath']) {
const native = objectByName(report.fcstdRoundTrip.sourceReopened, name)
const webPreserved = objectByName(report.fcstdRoundTrip.webTransparentPreservation.objects, name)
assert.deepEqual(commandGcode(webPreserved), commandGcode(native))
}
assert.equal(report.claims.webEditablePathPropertyCodec, 'verified-native-path-feature')
assert.equal(report.boundary.exactParityClaim, false)
})
test('Web Path::PropertyPath edit is reopened by FreeCAD while FeaturePython stays blocked', () => {
const editable = report.fcstdRoundTrip.webEditablePathProperty
assert.equal(editable.objectName, 'NativePath')
assert.equal(editable.sourceCommandCount, 5)
assert.equal(editable.editedCommandCount, 6)
assert.deepEqual(editable.lastCommand, { name: 'M3', parameters: { S: 12000 } })
assert.equal(editable.nativeReopenVerified, true)
assert.equal(editable.featurePythonExecutionBlocked, true)
})
test('FeaturePython Path::PropertyPath resource editing is explicit and non-executing', () => {
const editable = report.fcstdRoundTrip.webEditableFeaturePythonPathProperty
assert.equal(editable.objectName, 'PythonPath')
assert.equal(editable.sourceCommandCount, 5)
assert.equal(editable.editedCommandCount, 6)
assert.deepEqual(editable.lastCommand, { name: 'M2', parameters: {} })
assert.equal(editable.nativeReopenVerified, true)
assert.equal(editable.scriptExecution, 'blocked')
assert.equal(editable.optInRequired, true)
assert.equal(report.claims.webEditableFeaturePythonPathResourceCodec, 'verified-safe-resource-only-opt-in')
})
test('Qt oracle records live CAM actions from the active workbench', () => {
assert.equal(report.qtDynamicOracle.activeWorkbench, 'CAMWorkbench')
assert.ok(report.qtDynamicOracle.camCommandCount >= 50)
assert.ok(report.qtDynamicOracle.requiredCommands.every((command) => (
command.selectedModel.registered
&& command.selectedModel.actionCount >= 1
&& command.selectedModel.text.length > 0
&& command.selectedModel.iconPresent
)))
assert.ok(report.qtDynamicOracle.requiredCommands.some((command) => command.selectionChangesEnabledState))
})
test('Qt oracle records CAM Task panel open, focus fields, and OK/Cancel close semantics', () => {
const lifecycles = report.qtDynamicOracle.taskLifecycles
assert.equal(report.qtDynamicOracle.taskLifecycleVerified, true)
assert.ok(lifecycles.length >= 3)
assert.ok(lifecycles.every((lifecycle) => lifecycle.dialogOpened && lifecycle.dialogClosed && lifecycle.buttonClicked))
assert.ok(lifecycles.every((lifecycle) => lifecycle.active.buttonBoxCount === 1 && lifecycle.active.fieldCount >= 10))
assert.ok(lifecycles.every((lifecycle) => lifecycle.active.buttonTexts.some((button) => button.text === 'OK') && lifecycle.active.buttonTexts.some((button) => button.text === 'Cancel')))
assert.deepEqual(new Set(lifecycles.map((lifecycle) => lifecycle.action)), new Set(['accept', 'cancel']))
})