Files
FreeCADWasmDev/tools/test_ifc_source_roundtrip.mjs

51 lines
2.9 KiB
JavaScript

import fs from 'node:fs';
import assert from 'node:assert/strict';
import { loadWasmProbe } from './wasm-probe-runtime.mjs';
let kernel;
const directory = `docs/current/ifc-source-roundtrip-diagnostics/${new Date().toISOString().replace(/[:.]/g,'-')}`;
fs.mkdirSync(directory, { recursive: true });
try {
({ kernel } = await loadWasmProbe('web/public/kernel', 'FreeCADWebBimRuntimeProbe'));
const fixture = fs.readFileSync('freecad-source/build-web/ifcopenshell-native/fixtures/ColumnPSetsOfSets.ifc');
const reply = JSON.parse(kernel.ccall('fc_web_bim_test_python', 'string', ['string'], [`
import FreeCAD as App, IfcOpenShellNative, json, base64
with open('/tmp/source.ifc','wb') as stream: stream.write(base64.b64decode('${fixture.toString('base64')}'))
d=App.newDocument('SourceRoundtrip')
IfcOpenShellNative.insert('/tmp/source.ifc',d.Name)
IfcOpenShellNative.exportDocument(d.Name,'/tmp/output.ifc')
result=json.dumps({'sourcePath':d.getObject('IfcSource').OriginalIFC,
'input':open('/tmp/source.ifc').read(),'output':open('/tmp/output.ifc').read()})
`]));
if (reply.ok === false) throw Error(reply.error);
fs.writeFileSync(`${directory}/source.ifc`, reply.input);
fs.writeFileSync(`${directory}/output.ifc`, reply.output);
const actual = JSON.parse(kernel.ccall('fc_web_bim_test_python', 'string', ['string'], [`
import FreeCAD as App, IfcOpenShellNative, json
d=App.getDocument('SourceRoundtrip')
r=App.newDocument('SourceRoundtripRead')
IfcOpenShellNative.insert('/tmp/output.ifc',r.Name)
def snapshot(doc):
return sorted([(o.IfcGlobalId,o.Shape.Volume,o.Shape.isValid(),len(o.Shape.Solids)) for o in doc.Objects if o.isDerivedFrom('Part::Feature')])
result=json.dumps({'source':snapshot(d),'restored':snapshot(r)})
`]));
console.log(JSON.stringify({ sourcePath: reply.sourcePath, inputLength: reply.input.length, outputLength: reply.output.length, directory, actual }));
if (actual.ok === false) throw Error(actual.error);
assert.ok(actual.source.length>0);
assert.equal(actual.source.length,actual.restored.length);
for(const [index,source] of actual.source.entries()) {
const restored=actual.restored[index];
assert.equal(restored[0],source[0],'IFC identity changed');
assert.ok(source[2]&&restored[2]&&source[3]>0&&restored[3]>0,'IFC roundtrip must preserve valid solids');
assert.equal(restored[3],source[3],'IFC solid count changed');
assert.ok(Number.isFinite(restored[1])&&Number.isFinite(source[1])&&Math.abs(restored[1]-source[1])<=1e-6,'IFC volume changed beyond 1e-6 mm^3');
}
fs.writeFileSync(`${directory}/result.json`,JSON.stringify({status:'passed',actual,volumeAbsoluteTolerance:1e-6},null,2)+'\n');
} catch(error) {
fs.writeFileSync(`${directory}/failure.json`,JSON.stringify({status:'failed',error:String(error.stack??error)},null,2)+'\n');
console.error(String(error));process.exitCode=1;
} finally {
kernel?.PThread?.terminateAllThreads?.();
}
process.exit(process.exitCode??0);