test: add reproducible FreeCAD golden oracle
This commit is contained in:
63
scripts/run-freecad-golden.mjs
Normal file
63
scripts/run-freecad-golden.mjs
Normal file
@@ -0,0 +1,63 @@
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { loadGoldenManifest, compareGoldenResult } from './freecad-golden-contract.mjs'
|
||||
|
||||
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
||||
const args = new Set(process.argv.slice(2))
|
||||
const scenarioArgument = process.argv.slice(2).find((argument) => argument.startsWith('--scenario='))
|
||||
const requestedScenario = scenarioArgument?.slice('--scenario='.length)
|
||||
const jsonOutput = args.has('--json')
|
||||
const allowMissing = args.has('--allow-missing')
|
||||
const manifest = await loadGoldenManifest(resolve(root, 'fixtures/freecad-golden/manifest.json'))
|
||||
const driver = resolve(root, manifest.driver)
|
||||
|
||||
const localOracle = resolve(root, '.cache/freecad/install-native/bin/FreeCADCmd')
|
||||
const candidates = process.env.FREECAD_CMD
|
||||
? [process.env.FREECAD_CMD]
|
||||
: [localOracle, 'FreeCADCmd', 'freecadcmd']
|
||||
let command = null
|
||||
for (const candidate of candidates) {
|
||||
const probe = spawnSync(candidate, ['--version'], { encoding: 'utf8', timeout: 15000 })
|
||||
if (!probe.error || probe.error.code !== 'ENOENT') { command = candidate; break }
|
||||
}
|
||||
if (!command) {
|
||||
const message = `FreeCADCmd 1.1.1 is unavailable. Set FREECAD_CMD to the locked desktop oracle executable.`
|
||||
if (allowMissing) { console.log(message); process.exit(0) }
|
||||
console.error(message)
|
||||
process.exit(2)
|
||||
}
|
||||
|
||||
const scenarios = requestedScenario ? manifest.scenarios.filter((entry) => entry.id === requestedScenario) : manifest.scenarios
|
||||
if (scenarios.length === 0) { console.error(`Unknown golden scenario: ${requestedScenario}`); process.exit(2) }
|
||||
const reports = []
|
||||
for (const entry of scenarios) {
|
||||
const execution = spawnSync(command, [driver], {
|
||||
cwd: root,
|
||||
encoding: 'utf8',
|
||||
timeout: 120000,
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
env: { ...process.env, FREECAD_GOLDEN_SCENARIO: entry.file },
|
||||
})
|
||||
const output = `${execution.stdout || ''}\n${execution.stderr || ''}`
|
||||
const resultLine = output.split(/\r?\n/).find((line) => line.startsWith('FREECAD_GOLDEN_RESULT='))
|
||||
if (execution.error || execution.status !== 0 || !resultLine) {
|
||||
reports.push({ id: entry.id, passed: false, differences: [`FreeCADCmd execution failed with status ${execution.status}: ${execution.error?.message || output.trim()}`] })
|
||||
continue
|
||||
}
|
||||
let actual
|
||||
try { actual = JSON.parse(resultLine.slice('FREECAD_GOLDEN_RESULT='.length)) }
|
||||
catch (error) { reports.push({ id: entry.id, passed: false, differences: [`Invalid result JSON: ${error.message}`] }); continue }
|
||||
const differences = []
|
||||
if (actual.fixtureId !== entry.id) differences.push(`fixtureId: expected ${entry.id}, received ${actual.fixtureId}`)
|
||||
if (actual.freecadVersion !== '1.1.1') differences.push(`freecadVersion: expected 1.1.1, received ${actual.freecadVersion}`)
|
||||
differences.push(...compareGoldenResult(entry.scenario, actual))
|
||||
reports.push({ id: entry.id, passed: differences.length === 0, differences, actual })
|
||||
}
|
||||
|
||||
if (jsonOutput) console.log(JSON.stringify({ schemaVersion: 1, baselineId: manifest.baselineId, command, reports }, null, 2))
|
||||
else for (const report of reports) {
|
||||
console.log(`${report.passed ? 'PASS' : 'FAIL'} ${report.id}`)
|
||||
report.differences.forEach((difference) => console.log(` ${difference}`))
|
||||
}
|
||||
if (reports.some((report) => !report.passed)) process.exit(1)
|
||||
Reference in New Issue
Block a user