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

3 lines
4.6 KiB
JavaScript

import assert from "node:assert/strict"; import crypto from "node:crypto"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { execFileSync } from "node:child_process"; import { Worker } from "node:worker_threads"; 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 out = fs.mkdtempSync(path.join(os.tmpdir(), "freecad-p6-reverseengineering-save-facade-")); execFileSync(path.join(root, "web/node_modules/.bin/tsc"), ["--target", "ES2022", "--module", "ESNext", "--moduleResolution", "Bundler", "--strict", "--skipLibCheck", "--outDir", out, "--declaration", "false", "--noEmit", "false", "web/src/facade-envelope.ts", "web/src/reverseengineering-save-facade.ts"], { cwd: root, stdio: "inherit" }); const facade = await import(pathToFileURL(path.join(out, "reverseengineering-save-facade.js"))); const envelope = await import(pathToFileURL(path.join(out, "facade-envelope.js"))); const worker = new Worker(path.join(root, "tools/reverseengineering-save-facade-smoke-worker.mjs"), { workerData: { buildDirectory: build, facadePath: pathToFileURL(path.join(out, "reverseengineering-save-facade.js")).href, envelopePath: pathToFileURL(path.join(out, "facade-envelope.js")).href } }); const receive = () => new Promise((resolve, reject) => { const f = value => { worker.off("error", reject); resolve(value); }; worker.once("message", f); worker.once("error", reject); }); const ready = await receive(); const successRequest = facade.createReverseEngineeringSaveRequest("rev-save-success-1"); worker.postMessage(successRequest); const success = await receive(); worker.postMessage(facade.createReverseEngineeringSaveRequest("rev-save-error-1", { ...facade.REVERSEENGINEERING_SAVE_FIXTURE, path: "/tmp/ReverseEngineeringInvalid.txt" })); const expectedError = await receive(); worker.postMessage(successRequest); const duplicate = await receive(); const cancelRequest = facade.createReverseEngineeringSaveRequest("rev-save-cancel-1"); const cancelledPromise = new Promise((resolve, reject) => { const f = value => { if (value.requestId === cancelRequest.requestId) { worker.off("error", reject); resolve(value); } }; worker.on("message", f); worker.once("error", reject); }); worker.postMessage(cancelRequest); worker.postMessage(envelope.createCancel("rev-save-cancel-control", cancelRequest.requestId, "reverseengineering-save")); const cancelled = await cancelledPromise; worker.postMessage(facade.createReverseEngineeringSaveRequest("rev-save-after-cancel-1")); const after = await receive(); await worker.terminate(); assert.equal(ready.kind, "ready"); assert.equal(success.kind, "result"); assert.equal(success.result.objectType, "Part::Feature"); assert.equal(success.result.objectCount, 1); assert.equal(success.result.roundTrip, true); assert.equal(expectedError.error.code, "invalid_path"); assert.equal(duplicate.error.code, "duplicate_request"); assert.equal(cancelled.error.code, "cancelled"); assert.equal(after.kind, "result"); assert.deepEqual(after.result, success.result); const trace = { ready, success, expectedError, duplicate, cancelled, after }; const report = { schema: "freecad-web-p6-reverseengineering-action-04-facade/v1", taskId: "FW-P6-REV-ACT-04-E", module: "ReverseEngineering", action: facade.REVERSEENGINEERING_SAVE_COMMAND, result: "pass", envelopeSchema: envelope.FACADE_SCHEMA, typedSchema: facade.REVERSEENGINEERING_SAVE_SCHEMA, fixture: facade.REVERSEENGINEERING_SAVE_FIXTURE, trace, traceSha256: crypto.createHash("sha256").update(JSON.stringify(trace)).digest("hex"), sequencing: { requestCount: 6, responseCount: 6, maxActive: 1, cancelAccepted: true }, schemaChecks: { noNativePointers: !JSON.stringify(trace).match(/pointer|native/i) }, artifacts: { kernel: "docs/p6/reverseengineering-action-04-kernel.json", recovery: "docs/p6/reverseengineering-action-04-recovery.json", worker: "web/src/reverseengineering-save.worker.ts" }, boundaries: ["The typed facade exposes Part::Feature persistence metadata only; no native pointers cross the Worker boundary."] }; fs.writeFileSync(path.join(root, "docs/p6/reverseengineering-action-04-facade.json"), `${JSON.stringify(report, null, 2)}\n`); fs.writeFileSync(path.join(root, "docs/freecad-p6-reverseengineering-action-04-e-facade.log"), `${JSON.stringify({ result: report.result, requests: 6, maxActive: 1, cancel: cancelled.error.code })}\n`); console.log(JSON.stringify({ result: report.result, requests: 6, maxActive: 1, cancel: cancelled.error.code }));