Files
FreeCADWasmDev/tools/run_p6_measure_object_family_probe.mjs
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

48 lines
4.7 KiB
JavaScript

#!/usr/bin/env node
import crypto from "node:crypto";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { createRequire } from "node:module";
import { pathToFileURL } from "node:url";
const root = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
const build = path.join(root, "freecad-source/build-web/configure/bin");
const stagedBuild = fs.mkdtempSync(path.join(os.tmpdir(), "freecad-measure-object-family-native-"));
for (const entry of fs.readdirSync(build).filter((name) => name.startsWith("FreeCADWebMeasureKernelProbe."))) {
fs.copyFileSync(path.join(build, entry), path.join(stagedBuild, entry));
}
const matrix = JSON.parse(fs.readFileSync(path.join(root, "docs/p6/object-contract-matrix.json"), "utf8"));
const records = matrix.records.filter((record) => record.module === "Measure").map(({ id, name }) => ({ id, name }));
globalThis.__dirname = `${stagedBuild}${path.sep}`;
globalThis.require = createRequire(import.meta.url);
const loader = await import(pathToFileURL(path.join(stagedBuild, "FreeCADWebMeasureKernelProbe.js")));
const kernel = await loader.default({ wasmBinary: fs.readFileSync(path.join(build, "FreeCADWebMeasureKernelProbe.wasm")) });
const dispatch = (request) => JSON.parse(String(kernel.ccall("fc_web_dispatch_json", "string", ["string"], [JSON.stringify(request)])));
const request = { cmd: "measure.objectFamily", args: { records } };
const first = dispatch(request);
const second = dispatch(request);
if (first.ok !== true || first.schema !== "freecad-web-measure/object-family/v1" || first.module !== "Measure" || first.source !== "freecad-source" || first.count !== records.length || first.resourcesReleased !== true || !Array.isArray(first.records) || first.records.length !== records.length) throw new Error(`native Measure object family dispatch failed: ${JSON.stringify(first)}`);
if (JSON.stringify(first) !== JSON.stringify(second)) throw new Error("Measure object family dispatch replay changed the native result");
const expectedDocumentTypes = records.filter((record) => record.name !== "Measure::Measurement");
const passed = first.records.filter((record) => record.status === "passed");
if (passed.length < expectedDocumentTypes.length || first.records.some((record) => record.status === "blocked")) throw new Error(`Measure object family has blocked records: ${JSON.stringify(first.records)}`);
const report = {
schema: "freecad-web-p6-measure-object-family/v1",
taskId: "FW-P6-FPA-Y",
result: "pass",
route: { command: "measure.objectFamily", native: "freecad-source/src/WebAssembly/FreeCADCoreProbe/MeasureKernelProbe.cpp:fc_web_dispatch_json", facade: "web/src/measure-object-family-facade.ts", worker: "web/src/measure.worker.ts" },
source: { probe: "FreeCADWebMeasureKernelProbe", wasm: "freecad-source/build-web/configure/bin/FreeCADWebMeasureKernelProbe.wasm", wasmSha256: crypto.createHash("sha256").update(fs.readFileSync(path.join(build, "FreeCADWebMeasureKernelProbe.wasm"))).digest("hex") },
request,
requestSha256: crypto.createHash("sha256").update(JSON.stringify(request)).digest("hex"),
response: first,
responseSha256: crypto.createHash("sha256").update(JSON.stringify(first)).digest("hex"),
replay: { equal: true, responseSha256: crypto.createHash("sha256").update(JSON.stringify(second)).digest("hex") },
boundaries: ["Measure::Measurement is a registered native service class rather than an App::DocumentObject and remains passed_boundary.", "Document-object records are created and recomputed from the FreeCAD Measure module with Part geometry fixtures."]
};
fs.writeFileSync(path.join(root, "docs/p6/measure-object-family-gate.json"), `${JSON.stringify({ schema: "freecad-web-p6-measure-object-family-gate/v1", taskId: "FW-P6-FPA-D", result: report.result, coverage: { inventoryRecords: records.length, terminalRecords: first.records.length, counts: { passed: first.passed, passed_boundary: first.passedBoundary, blocked: first.blocked } }, records: first.records.map((record) => ({ id: record.id, status: record.status, detail: { code: record.code, message: record.message }, gate: "docs/p6/measure-object-family-kernel.json" })), source: { probe: report.source, route: report.route }, boundaries: report.boundaries }, null, 2)}\n`, "utf8");
fs.writeFileSync(path.join(root, "docs/p6/measure-object-family-kernel.json"), `${JSON.stringify(report, null, 2)}\n`, "utf8");
fs.writeFileSync(path.join(root, "docs/freecad-p6-measure-object-family.log"), `${JSON.stringify({ result: report.result, counts: first.counts, replayEqual: true, responseSha256: report.responseSha256 })}\n`, "utf8");
console.log(JSON.stringify({ result: report.result, counts: first.counts, replayEqual: true, responseSha256: report.responseSha256 }));
process.exit(0);