Files
Web_FreeCAD_Bitbybit/scripts/run-freecad-golden.mjs

64 lines
3.3 KiB
JavaScript

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)