feat: add versioned topology reference migration
This commit is contained in:
@@ -7,6 +7,7 @@ import { createSqliteProjectPersistence, PersistenceWriteQueue, ProjectAutosaveS
|
||||
import { DependencyGraph } from '../src/facade/dependencyGraph'
|
||||
import { evaluateQuantityExpression, quantityFromNumber } from '../src/facade/units'
|
||||
import { createEdgeSubshapeRefs, createSubshapeRefs, createVertexSubshapeRefs, matchSubshapes, signatureForEdge, signatureForFace, signatureForVertex } from '../src/facade/topologyNaming'
|
||||
import { createPersistedTopoRef, migrateTopoRefs, parseTopoRef, resolveTopoRef, serializeTopoRef } from '../src/facade/topologyReferences'
|
||||
import { createSketch, solveSketch } from '../src/facade/sketcher'
|
||||
import { createFacadeGeometryRecomputeExecutor, executeFacadeRecomputeNode, RecomputeCoordinator, type RecomputeGeometryRuntime } from '../src/facade/recomputeEngine'
|
||||
import { inspectFcstdArchive } from '../src/facade/fcstd'
|
||||
@@ -148,11 +149,37 @@ test('topology signatures are independent of transient face indexes and flag amb
|
||||
const duplicate = createSubshapeRefs('shape-b', 2, [square, square])
|
||||
assert.equal(duplicate.refs[0].status, 'ambiguous')
|
||||
assert.deepEqual(duplicate.refs[0].candidates, [duplicate.refs[0].persistentId, duplicate.refs[1].persistentId])
|
||||
assert.notEqual(duplicate.refs[0].persistentId, duplicate.refs[1].persistentId)
|
||||
const matches = matchSubshapes([{ ref: first.refs[0], signature: first.signatures[0] }], [{ ref: duplicate.refs[0], signature: duplicate.signatures[0] }])
|
||||
assert.equal(matches[0].status, 'stable')
|
||||
assert.equal(matches[0].previousId, first.refs[0].persistentId)
|
||||
const deleted = matchSubshapes([{ ref: first.refs[0], signature: first.signatures[0] }, { ref: duplicate.refs[1], signature: duplicate.signatures[1] }], [{ ref: duplicate.refs[0], signature: duplicate.signatures[0] }])
|
||||
assert.equal(matches[0].status, 'ambiguous')
|
||||
const shifted = { ...square, vertexCoord: square.vertexCoord.map((value, index) => index % 3 === 0 ? value + 10 : value) }
|
||||
const previousShifted = createSubshapeRefs('shape-shifted', 1, [shifted])
|
||||
const currentSingle = createSubshapeRefs('shape-current', 2, [square])
|
||||
const deleted = matchSubshapes([{ ref: first.refs[0], signature: first.signatures[0] }, { ref: previousShifted.refs[0], signature: previousShifted.signatures[0] }], [{ ref: currentSingle.refs[0], signature: currentSingle.signatures[0] }])
|
||||
assert.equal(deleted.at(-1)?.status, 'deleted')
|
||||
|
||||
const translated = { ...square, vertexCoord: square.vertexCoord.map((value, index) => index % 3 === 0 ? value + 5 : value) }
|
||||
const moved = createSubshapeRefs('shape-moved', 3, [translated])
|
||||
const movedMatches = matchSubshapes([{ ref: first.refs[0], signature: first.signatures[0] }], [{ ref: moved.refs[0], signature: moved.signatures[0] }])
|
||||
assert.equal(movedMatches[0].status, 'stable')
|
||||
assert.equal(movedMatches[0].previousId, first.refs[0].persistentId)
|
||||
})
|
||||
|
||||
test('versioned TopoRefs serialize without transient indexes and resolve migration states', () => {
|
||||
const face = { vertexCoord: [0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 2, 0], normalCoord: [], triIndexes: [0, 1, 2, 0, 2, 3] }
|
||||
const previous = createSubshapeRefs('shape-old', 4, [face])
|
||||
const record = createPersistedTopoRef('pad', previous.refs[0], 7)
|
||||
const restored = parseTopoRef(serializeTopoRef(record))
|
||||
assert.deepEqual(restored, record)
|
||||
assert.equal(resolveTopoRef(restored, previous.refs).status, 'resolved')
|
||||
assert.throws(() => parseTopoRef(JSON.stringify({ ...record, faceIndex: 1 })), /must not persist transient faceIndex/)
|
||||
|
||||
const split = createSubshapeRefs('shape-new', 5, [face, face])
|
||||
const migration = migrateTopoRefs('pad', [{ ref: previous.refs[0], signature: previous.signatures[0] }], split.refs.map((ref, index) => ({ ref, signature: split.signatures[index] })), 8)
|
||||
assert.equal(migration.counts.ambiguous, 2)
|
||||
assert.equal(migration.counts.deleted, 0)
|
||||
assert.ok(migration.records.every((candidate) => candidate.status === 'ambiguous' && candidate.candidates && candidate.candidates.length >= 2))
|
||||
assert.equal(resolveTopoRef(restored, split.refs).status, 'ambiguous')
|
||||
})
|
||||
|
||||
test('edge and vertex topology signatures are orientation/index independent', () => {
|
||||
|
||||
Reference in New Issue
Block a user