60 lines
5.9 KiB
JavaScript
60 lines
5.9 KiB
JavaScript
import { isDeepStrictEqual } from 'node:util'
|
|
import { readFile } from 'node:fs/promises'
|
|
import { resolve } from 'node:path'
|
|
|
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
|
const report = JSON.parse(await readFile(resolve(root, 'config/freecad-property-direction-success.json'), 'utf8'))
|
|
const fail = (message) => { throw new Error(`FreeCAD PropertyDirection success check failed: ${message}`) }
|
|
if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-direction-success' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyDirection') fail('baseline is invalid')
|
|
if (report.caseCount !== 2 || !Array.isArray(report.cases) || report.cases.length !== 2 || new Set(report.cases.map(({ objectTypeId }) => objectTypeId)).size !== 2) fail('native success case inventory is incomplete')
|
|
|
|
const values = {
|
|
axisZTuple: [0, 0, 1],
|
|
integerTuple: [1, 1, 2],
|
|
nonUnitFloatTuple: [0.25, -0.5, 1.5],
|
|
vectorObject: [-0.125, 0.25, 1],
|
|
nearAxisTuple: [1e-9, -1e-9, 1],
|
|
largeFiniteTuple: [1e6, -2e6, 3e6],
|
|
}
|
|
const requested = Object.fromEntries(Object.entries(values).map(([phase, value]) => [phase, { inputKind: phase === 'vectorObject' ? 'Base.Vector' : 'tuple', value }]))
|
|
const expectedHosts = {
|
|
'Part::Mirroring': {
|
|
objectName: 'DirectionMirror',
|
|
propertyName: 'Normal',
|
|
objectSet: [{ name: 'MirrorSource', typeId: 'Part::Box' }, { name: 'DirectionMirror', typeId: 'Part::Mirroring' }],
|
|
shape: { shapeType: 'Solid', solids: 1, faces: 6, edges: 12, vertices: 8, area: 52, volume: 24 },
|
|
afterSetMustExecute: true,
|
|
},
|
|
'Part::ProjectOnSurface': {
|
|
objectName: 'DirectionProjection',
|
|
propertyName: 'Direction',
|
|
objectSet: [{ name: 'ProjectionSupport', typeId: 'Part::Feature' }, { name: 'ProjectionWire', typeId: 'Part::Feature' }, { name: 'DirectionProjection', typeId: 'Part::ProjectOnSurface' }],
|
|
shape: { shapeType: 'Compound', solids: 0, faces: 0, edges: 4, vertices: 4, area: 0, volume: 0 },
|
|
afterSetMustExecute: false,
|
|
},
|
|
}
|
|
for (const [typeId, expected] of Object.entries(expectedHosts)) {
|
|
const entry = report.cases.find(({ objectTypeId }) => objectTypeId === typeId)
|
|
if (entry?.objectName !== expected.objectName || entry.propertyName !== expected.propertyName || entry.mode !== 'direct-native-property-setter-with-valid-host-geometry' || !isDeepStrictEqual(entry.defaultValue, [0, 0, 1]) || !isDeepStrictEqual(entry.requested, requested)) fail(`${typeId} setter contract is invalid`)
|
|
if (typeId === 'Part::Mirroring') {
|
|
if (entry.setup?.kind !== 'box-mirror' || entry.setup.source?.typeId !== 'Part::Box' || !isDeepStrictEqual(entry.setup.source.dimensions, [2, 3, 4]) || !isDeepStrictEqual(entry.setup.base, [0, 0, 0]) || entry.setup.mirrorPlane !== null) fail('Mirroring setup is incomplete')
|
|
} else if (entry.setup?.kind !== 'wire-to-planar-face' || entry.setup.support?.typeId !== 'Part::Feature' || !isDeepStrictEqual(entry.setup.support.subElements, ['Face1']) || entry.setup.projection?.typeId !== 'Part::Feature' || !isDeepStrictEqual(entry.setup.projection.subElements, ['Wire1']) || entry.setup.projection.z !== -5 || entry.setup.mode !== 'Edges') fail('ProjectOnSurface setup is incomplete')
|
|
|
|
const defaultSnapshot = entry.phases?.default?.afterRecompute
|
|
const restoredSnapshot = entry.phases?.restored?.afterRecompute
|
|
if (!isDeepStrictEqual(defaultSnapshot?.value, [0, 0, 1]) || !isDeepStrictEqual(restoredSnapshot?.value, [0, 0, 1]) || defaultSnapshot.shape?.brepSha256 !== restoredSnapshot.shape?.brepSha256 || !isDeepStrictEqual(defaultSnapshot.shape?.bounds, restoredSnapshot.shape?.bounds)) fail(`${typeId} default restore is not exact`)
|
|
for (const [phase, value] of Object.entries({ default: [0, 0, 1], ...values, restored: [0, 0, 1] })) {
|
|
const snapshots = entry.phases?.[phase]
|
|
const snapshot = snapshots?.afterRecompute
|
|
if (!snapshot || !isDeepStrictEqual(snapshot.value, value) || snapshot.propertyTypeId !== 'App::PropertyDirection' || !isDeepStrictEqual(snapshot.propertyStatus, []) || !isDeepStrictEqual(snapshot.editorMode, []) || !isDeepStrictEqual(snapshot.objectState, ['Up-to-date']) || snapshot.statusString !== 'Valid' || snapshot.mustExecute !== false || snapshot.recomputeResult !== true || !isDeepStrictEqual(snapshot.objectSet, expected.objectSet)) fail(`${typeId} ${phase} native semantics changed`)
|
|
const shape = snapshot.shape
|
|
if (shape?.applicable !== true || shape.isNull !== false || shape.valid !== true || shape.shapeType !== expected.shape.shapeType || shape.solids !== expected.shape.solids || shape.faces !== expected.shape.faces || shape.edges !== expected.shape.edges || shape.vertices !== expected.shape.vertices || shape.area !== expected.shape.area || shape.volume !== expected.shape.volume || typeof shape.brepSha256 !== 'string' || shape.brepSha256.length !== 64 || !Array.isArray(shape.bounds) || shape.bounds.length !== 6) fail(`${typeId} ${phase} Shape evidence changed`)
|
|
if (phase !== 'default') {
|
|
const afterSet = snapshots.afterSet
|
|
if (!afterSet || !isDeepStrictEqual(afterSet.value, value) || !isDeepStrictEqual(afterSet.objectState, ['Touched']) || afterSet.statusString !== 'Touched' || afterSet.mustExecute !== expected.afterSetMustExecute) fail(`${typeId} ${phase} setter touch evidence changed`)
|
|
}
|
|
}
|
|
for (const phase of ['integerTuple', 'nonUnitFloatTuple', 'vectorObject', 'nearAxisTuple', 'largeFiniteTuple']) if (entry.phases[phase].afterRecompute.shape.brepSha256 === defaultSnapshot.shape.brepSha256) fail(`${typeId} ${phase} did not produce a distinct Shape`)
|
|
}
|
|
console.log(JSON.stringify({ status: 'freecad-property-direction-success-pass', cases: report.caseCount, acceptedInputs: Object.keys(values), noPropertyNormalization: true, shapes: Object.fromEntries(Object.entries(expectedHosts).map(([typeId, value]) => [typeId, value.shape])) }, null, 2))
|