Files
Web_FreeCAD_Bitbybit/tests/freecadPrivateNamingBoundary.test.mjs
wangdequan f64b78865c
Some checks failed
real-verification / chrome (push) Has been cancelled
real-verification / freecad-oracle (push) Has been cancelled
real-verification / wasm (push) Has been cancelled
feat: complete production naming and reference lifecycle gates
2026-08-14 10:10:30 -04:00

225 lines
14 KiB
JavaScript

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('!<arch>\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 <TopTools_ListOfShape\.hxx>/)
assert.match(sdkCompat, /#include <TopTools_HSequenceOfShape\.hxx>/)
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 <GeomLProp_CLProps\.hxx>/)
assert.match(sdkOverlay, /legacy_geom2d_lprop/)
assert.match(sdkOverlay, /std::vector<TopoShape>\{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/)
})