Files
FreeCADWasmDev/tools/run_p6_workbench_command_native_smoke.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

54 lines
3.9 KiB
JavaScript

#!/usr/bin/env node
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { createRequire } from "node:module";
import { fileURLToPath, pathToFileURL } from "node:url";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const build = path.resolve(process.argv[2] ?? path.join(root, "freecad-source/build-web/configure/bin"));
const matrixPath = path.join(root, "docs/p6/workbench-command-matrix.json");
const matrix = JSON.parse(fs.readFileSync(matrixPath, "utf8"));
const modulePath = path.join(build, "FreeCADWebWorkbenchCommandProbe.js");
globalThis.__dirname = `${build}${path.sep}`;
globalThis.require = createRequire(import.meta.url);
process.chdir(build);
const factory = (await import(pathToFileURL(modulePath))).default;
const kernel = await factory({ wasmBinary: fs.readFileSync(path.join(build, "FreeCADWebWorkbenchCommandProbe.wasm")), locateFile: (file) => path.join(build, file), print: () => {}, printErr: () => {} });
const context = { documentId: "workbench-native-smoke", selection: ["Part:desktop:Std_DlgMacroRecord"], propertyMode: "read-only" };
const request = { cmd: "web.workbenchCommandBatch", args: { context, records: matrix.records } };
const started = Date.now();
const raw = String(kernel.ccall("fc_web_dispatch_json", "string", ["string"], [JSON.stringify(request)]));
const response = JSON.parse(raw);
const records = Array.isArray(response.records) ? response.records : [];
const statuses = Object.fromEntries(["native_handler", "restricted", "not_implemented"].map((status) => [status, records.filter((record) => record.status === status).length]));
const result = {
schema: "freecad-web-p6-workbench-command-native-smoke/v1",
taskId: "FW-P6-FPA-G",
source: "freecad-source",
sourceRevision: response.records?.[0]?.sourceRevision ?? null,
request: { context, recordCount: matrix.records.length, sha256: crypto.createHash("sha256").update(JSON.stringify(request)).digest("hex") },
response: { schema: response.schema, module: response.module, count: response.count, context: response.context, resourcesReleased: response.resourcesReleased, sha256: crypto.createHash("sha256").update(raw).digest("hex") },
statuses,
elapsedMs: Date.now() - started,
sample: records.slice(0, 3).map(({ id, module, command, kind, status, code, inputStateSchema, returnSchema, resourcesReleased }) => ({ id, module, command, kind, status, code, inputStateSchema, returnSchema, resourcesReleased })),
};
const valid = response.ok === true
&& response.schema === "freecad-web-workbench-command-batch/v1"
&& response.module === "FreeCAD"
&& response.source === "freecad-source"
&& response.count === matrix.records.length
&& response.context?.documentId === context.documentId
&& response.context?.selectionCount === context.selection.length
&& response.context?.propertyMode === context.propertyMode
&& response.resourcesReleased === true
&& records.length === matrix.records.length
&& statuses.native_handler === matrix.dispositionCounts.native_handler
&& statuses.restricted === matrix.dispositionCounts.restricted
&& statuses.not_implemented === 0
&& records.every((record) => record.native === true && record.resourcesReleased === true && record.inputStateSchema === "freecad-web-command-input-state/v1" && record.returnSchema === "workbench-command-disposition/v1" && record.errorRecovery?.structuredError === true && record.errorRecovery?.cancelBeforeDispatch === true && record.errorRecovery?.replaySafe === true);
const outputPath = process.env.P6_WORKBENCH_NATIVE_OUTPUT ?? path.join(root, "docs/p6/workbench-command-native-smoke.json");
fs.writeFileSync(outputPath, `${JSON.stringify({ ...result, result: valid ? "pass" : "fail" }, null, 2)}\n`);
console.log(JSON.stringify({ result: valid ? "pass" : "fail", records: records.length, statuses, elapsedMs: result.elapsedMs }));
if (!valid) process.exitCode = 1;