import test from 'node:test' import assert from 'node:assert/strict' import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises' import { join, resolve } from 'node:path' import { tmpdir } from 'node:os' import { inspectWasmStaticArchive } from '../scripts/freecad-naming-sdk-lib.mjs' const root = resolve(new URL('..', import.meta.url).pathname) const arArchive = (member, bytes) => { const field = (value, length) => String(value).padEnd(length, ' ') const header = `${field(`${member}/`, 16)}${field(0, 12)}${field(0, 6)}${field(0, 6)}${field('100644', 8)}${field(bytes.length, 10)}` + '`\n' return Buffer.concat([Buffer.from('!\n'), Buffer.from(header), bytes, ...(bytes.length % 2 ? [Buffer.from('\n')] : [])]) } test('Qt wasm Core build pins the released QtBase source and project Emscripten baseline', async () => { const source = await readFile(resolve(root, 'scripts/build-qt6-wasm-core.sh'), 'utf8') const freecadQt = await readFile(resolve(root, 'scripts/build-qt6-freecad-wasm.sh'), 'utf8') assert.match(source, /QT_VERSION="6\.8\.2"/) assert.match(source, /012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05/) assert.match(source, /Emscripten 3\.1\.69/) assert.match(source, /mirrors\.ustc\.edu\.cn/) assert.match(source, /WEB_FREECAD_OFFLINE/) assert.match(source, /cmake --install "\$\{QT_BUILD_DIR\}\/src\/corelib"/) assert.doesNotMatch(source, /cmake --install[^\n]+\|\| true/) assert.match(freecadQt, /Core Concurrent Network Xml/) assert.match(freecadQt, /feature-thread/) assert.match(freecadQt, /mkspecs\/wasm-emscripten/) assert.match(freecadQt, /inspectWasmStaticArchive/) }) test('FreeCAD source probe pins the exact private source inputs and does not export the production ABI', async () => { const build = await readFile(resolve(root, 'scripts/build-freecad-naming-source-probe.sh'), 'utf8') const smoke = await readFile(resolve(root, 'native/freecad-naming-probe/smoke-test.mjs'), 'utf8') const candidate = await readFile(resolve(root, 'native/freecad-naming-probe/abi-candidate-smoke.ts'), 'utf8') assert.match(build, /0108fd4b4850cc46e625b60e53cea7a7bbe69f8d/) assert.match(build, /73e0e60a9d6ee06851252e2071ebdd58698f8f99733903232529b3a194164435/) assert.match(build, /90173aba5f331ac9453589833f7e5fc63c5c80a35f1600dbc71211606b1c9dbc/) assert.match(build, /fd32f35c9c2a0c21a60fa634ec37ec594d6f331924c5bba7fdbbcb351c3b612c/) assert.match(build, /8f02d27a8b672e9a56764f85e394265b4fcf023aba097f040b03dcb38bc393d2/) assert.match(build, /StringHasher\.cpp/) assert.match(build, /Base\/Handle\.cpp/) assert.match(build, /f5448d9de693e319460d5e3ef52c63a54e0948963e4b92786aac38c77bdcd7a5/) assert.match(build, /fc3223857ca6d2990d2b48f437f75841cdf23e1e79fa18ef18296f40acd3cdc3/) assert.match(build, /e1ceaedb624688ddffa6a834c1b32539e8ba5bbdc0ec31401ea087e6a9c3eb52/) assert.match(build, /MappedElement\.cpp/) assert.match(build, /ElementNamingUtils\.cpp/) assert.match(build, /ElementMap\.cpp/) assert.match(build, /libFreeCADPrivateNamingProbe\.a/) assert.match(build, /emar rcs/) assert.match(build, /git -C "\$\{FREECAD_SOURCE_DIR\}" diff --quiet/) assert.doesNotMatch(build, /public\/native\/freecad-naming-probe/) for (const callback of ['freecadNamingAbiVersion', 'freecadNamingCapabilitiesJson', 'freecadNamingEvidenceJson']) { assert.match(smoke, new RegExp(callback)) } assert.match(smoke, /productionWorkerLinked: false/) assert.match(smoke, /freecadPrivateStringHasherSourceProbe/) assert.match(smoke, /freecadPrivateElementMapSourceProbe/) assert.match(smoke, /archive\.memberCount !== 7/) assert.match(smoke, /productionEligible: false/) assert.match(candidate, /captureFreeCadPrivateNamingEvidence/) assert.match(candidate, /parseElementMap2/) assert.match(candidate, /productionCallbacksExported: false/) assert.match(candidate, /productionWorkerLinked: false/) }) test('private naming boundary checker cross-validates all authoritative status files', async () => { const source = await readFile(resolve(root, 'scripts/check-freecad-private-naming-boundary.mjs'), 'utf8') for (const path of [ 'config/freecad-sketcher-partdesign-abi-contract.json', 'config/compatibility-matrix.json', 'config/freecad-web-exact-parity-plan.json', 'config/freecad-private-naming-source-readiness.json', 'config/freecad-naming-sdk-plan.json', ]) assert.match(source, new RegExp(path.replaceAll('.', '\\.'))) assert.match(source, /shippedWorkerImplementation !== 'freecad-linked'/) assert.match(source, /task\.status !== 'completed'/) assert.match(source, /systemExactEvaluation\?\.exact !== false/) assert.match(source, /production\?\.workerLinked !== true/) assert.match(source, /candidateAbi\?\.scope !== 'isolated-non-production'/) assert.match(source, /callback\.startsWith\('freecadNamingCandidate'\)/) assert.match(source, /productionLinkedComponents/) assert.match(source, /sdkPlan\.productionPublication !== false/) }) test('SDK readiness verifies the complete candidate wasm closure and keeps it pre-production', async () => { const plan = JSON.parse(await readFile(resolve(root, 'config/freecad-naming-sdk-plan.json'), 'utf8')) const readiness = await readFile(resolve(root, 'scripts/check-freecad-naming-sdk-readiness.mjs'), 'utf8') const sdkBuildPlan = await readFile(resolve(root, 'config/freecad-wasm-sdk-build-plan.json'), 'utf8') const sdkBootstrap = await readFile(resolve(root, 'config/freecad-wasm-sdk-bootstrap.cmake'), 'utf8') const sdkCompat = await readFile(resolve(root, 'config/freecad-wasm-sdk-compat.h'), 'utf8') const sdkExecinfo = await readFile(resolve(root, 'config/wasm-compat/execinfo.h'), 'utf8') const sdkToolchain = await readFile(resolve(root, 'config/emscripten-freecad-candidate-toolchain.cmake'), 'utf8') const sdkConfigure = await readFile(resolve(root, 'scripts/configure-freecad-naming-sdk-candidate.mjs'), 'utf8') const sdkBuild = await readFile(resolve(root, 'scripts/build-freecad-naming-sdk-candidate.sh'), 'utf8') const sdkOverlay = await readFile(resolve(root, 'scripts/prepare-freecad-occt8-overlay.sh'), 'utf8') const sdkCheck = await readFile(resolve(root, 'scripts/check-freecad-naming-sdk.mjs'), 'utf8') const sdkManifest = await readFile(resolve(root, 'scripts/generate-freecad-naming-sdk-manifest.mjs'), 'utf8') const bridgeBuild = await readFile(resolve(root, 'scripts/build-freecad-naming-bridge-candidate.sh'), 'utf8') const bridgeSmoke = await readFile(resolve(root, 'native/freecad-naming-bridge/smoke-test.ts'), 'utf8') const bridgeCheck = await readFile(resolve(root, 'scripts/check-freecad-naming-bridge-candidate.mjs'), 'utf8') const workerBuild = await readFile(resolve(root, 'native/occt-history/build.sh'), 'utf8') const workerSmoke = await readFile(resolve(root, 'native/occt-history/freecad-naming-candidate-smoke.ts'), 'utf8') const chromeRun = await readFile(resolve(root, 'scripts/run-chrome-freecad-naming-worker-candidate.mjs'), 'utf8') const chromeCheck = await readFile(resolve(root, 'scripts/check-chrome-freecad-naming-worker-candidate.mjs'), 'utf8') assert.equal(plan.productionPublication, false) assert.deepEqual(plan.libraries.map(({ name }) => name), ['FreeCADBase', 'FreeCADApp', 'Part', 'QtCore', 'Python']) assert.deepEqual(plan.linkDependencies.map(({ name }) => name), ['QtConcurrent', 'QtNetwork', 'QtXml', 'QtBundledPcre2', 'QtBundledZLIB', 'yaml-cpp', 'ICUCommon', 'ICUI18N', 'ICUData', 'XercesC', 'BoostProgramOptions', 'BoostRegex', 'BoostThread', 'BoostDateTime', 'BoostAtomic', 'PythonMpdecimal', 'PythonExpat', 'PythonHaclSha2', 'PythonZlib', 'PythonBzip2', 'PythonSqlite3']) assert.equal(plan.compileOptions.cxxStandard, 'c++20') assert.equal(plan.compileOptions.pthread, true) assert.deepEqual(plan.runtimeAssets.map(({ name }) => name), ['PythonWasmStdlib']) assert.match(readiness, /inspectPlannedLibrary/) assert.match(readiness, /publishToWorker: false/) assert.match(readiness, /inspectPlannedRuntimeAsset/) assert.match(sdkCheck, /inspectWasmStaticArchive/) assert.match(sdkCheck, /hostAdapterSha256/) assert.match(sdkCheck, /forceIncludeSha256/) assert.match(sdkCheck, /PythonWasmStdlib/) assert.match(sdkManifest, /runtimeAssets/) assert.match(sdkManifest, /productionPublication: false/) assert.match(sdkBuildPlan, /candidate-only-freecad-wasm-sdk-build/) assert.match(sdkBuildPlan, /productionPublication": false/) assert.match(sdkBootstrap, /FREECAD_WASM_EMBED_TRANSLATIONS OFF/) assert.match(sdkBootstrap, /function\(qt_add_translation output_variable\)/) assert.match(sdkBootstrap, /add_compile_definitions\(__linux__=1\)/) assert.match(sdkBootstrap, /FREECAD_WASM_OCCT_COMPAT_INCLUDE/) assert.match(sdkBootstrap, /TopTools_ListOfShape\.hxx/) assert.match(sdkBootstrap, /set\(UNIX FALSE\)/) assert.match(sdkToolchain, /Platform\/Emscripten\.cmake/) assert.match(sdkToolchain, /set\(UNIX FALSE\)/) assert.match(sdkToolchain, /CMAKE_CXX_CREATE_SHARED_LIBRARY/) assert.match(sdkBootstrap, /freecad-wasm-sdk-compat\.h/) assert.match(sdkCompat, /#include /) assert.match(sdkCompat, /#include /) assert.match(sdkCompat, /#define systemTimeZone\(\) UTC/) assert.doesNotMatch(sdkExecinfo, /backtrace\s*\(/) assert.match(sdkConfigure, /Qt6_DIR/) assert.match(sdkConfigure, /Python3_INCLUDE_DIRS/) assert.match(sdkConfigure, /FREECAD_WASM_OFFLINE_SYSROOT/) assert.match(sdkConfigure, /src\/Deprecated\/NCollectionAliases/) assert.match(sdkConfigure, /source-occt8/) assert.match(sdkOverlay, /migrate_raise_to_throw\.py/) assert.match(sdkOverlay, /replace_typedefs\.py/) assert.match(sdkOverlay, /collected_typedefs\.json/) assert.match(sdkOverlay, /TopTools_ListIteratorOfListOfShape\.hxx\|TopTools_ListOfShape\.hxx/) assert.match(sdkOverlay, /removed_iterator_headers/) assert.match(sdkOverlay, /e\.DynamicType\(\)->get_type_name\(\)\|e\.ExceptionType\(\)/) assert.match(sdkOverlay, /legacy_exception_rtti/) assert.match(sdkOverlay, /BRepLProp_CurveTool::FirstParameter\(adapt\)\|adapt\.FirstParameter\(\)/) assert.match(sdkOverlay, /legacy_curve_tool/) assert.match(sdkOverlay, /Geom2dLProp_CLProps2d\.hxx>\|#include /) assert.match(sdkOverlay, /legacy_geom2d_lprop/) assert.match(sdkOverlay, /std::vector\{e1, e2, e3, e4\}/) assert.match(sdkOverlay, /ambiguous_shape_mapper_calls/) assert.match(sdkOverlay, /Standard_Failure inherits std::exception/) assert.match(sdkOverlay, /unreachable_occt_exception_fallbacks/) assert.match(sdkOverlay, /worktree add --detach/) assert.match(sdkOverlay, /git -C "\$\{FREECAD_SOURCE_DIR\}" diff --quiet/) assert.match(sdkConfigure, /FreeCADBase|BUILD_PART/) assert.match(sdkConfigure, /freecadNamingEvidenceJson/) assert.match(sdkBuild, /cmake --build "\$\{BUILD_DIR\}" --target Part/) assert.match(sdkBuild, /libFreeCADBase\.a/) assert.match(sdkBuild, /ElementMap\.cpp\.o/) assert.match(sdkBuild, /productionManifestGenerated: false/) assert.match(sdkBuild, /availability: 'available'/) assert.match(bridgeBuild, /libHacl_Hash_SHA2\.a/) assert.match(bridgeBuild, /--preload-file/) assert.match(bridgeBuild, /FREECAD_NAMING_BRIDGE_REPORT/) assert.match(bridgeBuild, /public\/native\/freecad-naming-bridge/) assert.match(bridgeSmoke, /freecad-private-naming-isolated-bridge-pass/) assert.match(bridgeSmoke, /thirdStage/) assert.match(bridgeSmoke, /tamperedHasherRejected/) assert.match(bridgeSmoke, /inconsistentTablesRejected/) assert.match(bridgeSmoke, /productionWorkerLinked: false/) assert.match(bridgeCheck, /thirdStage\?\.stringHasherEntries <= report\.chainedStage\.stringHasherEntries/) assert.match(bridgeCheck, /stale artifact evidence/) assert.match(workerBuild, /OCCT_HISTORY_PUBLISH/) assert.match(workerBuild, /m\.runtimeAssets/) assert.match(workerBuild, /m\.compileOptions\.definitions/) assert.match(workerBuild, /OCCT_CXX_FLAGS\+=" -pthread"/) assert.match(workerSmoke, /booleanHistoryFromStep/) assert.match(workerSmoke, /thirdStage/) assert.match(workerSmoke, /invalidHistoryRejected: true/) assert.match(chromeRun, /crossOriginIsolated/) assert.match(chromeRun, /thirdStage/) assert.match(chromeRun, /productionWorkerLinked: false/) assert.match(chromeCheck, /thirdStage\?\.stringHasherEntries <= report\.chainedStage\.stringHasherEntries/) assert.match(chromeCheck, /stale artifact evidence/) const fixtureDir = await mkdtemp(join(tmpdir(), 'freecad-naming-sdk-')) try { const wasmArchive = join(fixtureDir, 'libwasm.a') const hostArchive = join(fixtureDir, 'libhost.a') await writeFile(wasmArchive, arArchive('wasm.o', Buffer.from([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]))) await writeFile(hostArchive, arArchive('host.o', Buffer.from([0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00]))) const wasm = await inspectWasmStaticArchive(wasmArchive) assert.equal(wasm.target, 'wasm32-emscripten') assert.equal(wasm.wasmObjectCount, 1) await assert.rejects(inspectWasmStaticArchive(hostArchive), /host ELF object/) } finally { await rm(fixtureDir, { recursive: true, force: true }) } }) test('real wasm and offline smoke lanes rebuild and execute the source prerequisite', async () => { const real = await readFile(resolve(root, 'scripts/run-real-verification.mjs'), 'utf8') const offline = await readFile(resolve(root, 'scripts/offline-resource-lib.mjs'), 'utf8') for (const source of [real, offline]) { assert.match(source, /build:freecad-naming-source-probe/) assert.match(source, /test:freecad-naming-source-probe/) assert.match(source, /check:freecad-naming-sdk-readiness/) assert.match(source, /check:freecad-wasm-sdk-build-plan/) } assert.match(real, /build:qt6-wasm-core/) assert.match(real, /probe:freecad-attachment-modes/) assert.match(real, /name\.startsWith\('test:chrome-'\)/) assert.match(real, /requestedPhase === 'execute' \? chromeExecution : chromeChecks/) assert.match(real, /test:freecad-naming-production/) assert.match(real, /test:freecad-isomorphic-provenance/) assert.match(real, /probe:freecad-native-property-semantics/) assert.match(offline, /publish:occt-history/) assert.match(offline, /check:freecad-naming-production/) assert.match(offline, /check:freecad-isomorphic-provenance/) assert.match(offline, /check:freecad-native-property-semantics/) })