65 lines
3.4 KiB
JavaScript
65 lines
3.4 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 manifestArgument = process.argv.slice(2).find((argument) => argument.startsWith('--manifest='))
|
|
const requestedScenario = scenarioArgument?.slice('--scenario='.length)
|
|
const jsonOutput = args.has('--json')
|
|
const allowMissing = args.has('--allow-missing')
|
|
const manifest = await loadGoldenManifest(resolve(root, manifestArgument?.slice('--manifest='.length) || '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)
|