v1.1.0: pooled runtime, 959 tests, production hardening (0 squash)
This commit is contained in:
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* Tests for relation-specific proof generation.
|
||||
*
|
||||
* Verifies that generateProof produces rich, relation-specific failedPredicate
|
||||
* details instead of generic left/right metric comparisons.
|
||||
*/
|
||||
|
||||
import { describe, it, beforeEach } from 'node:test'
|
||||
import assert from 'node:assert'
|
||||
|
||||
import {
|
||||
generateProof,
|
||||
resetProofCounter,
|
||||
} from './proofs.js'
|
||||
|
||||
import type {
|
||||
ClauseResult,
|
||||
ClauseDescriptor,
|
||||
GeometryWorld,
|
||||
} from './registry.js'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mock World
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const world: GeometryWorld = {
|
||||
sceneId: 'scene_1',
|
||||
snapshotId: 'snap_1',
|
||||
env: {
|
||||
viewportWidth: 1280,
|
||||
viewportHeight: 800,
|
||||
deviceScaleFactor: 1,
|
||||
colorScheme: 'light',
|
||||
pointer: 'fine',
|
||||
hover: false,
|
||||
reducedMotion: false,
|
||||
locale: 'en',
|
||||
writingMode: 'horizontal-tb',
|
||||
},
|
||||
strings: { values: [] },
|
||||
subjects: {
|
||||
ids: [1, 2],
|
||||
domNodeId: [10, 20],
|
||||
subjectKind: [1, 1],
|
||||
primaryBoxId: [100, 200],
|
||||
firstFragmentId: [0, 0],
|
||||
fragmentCount: [0, 0],
|
||||
},
|
||||
dom: {
|
||||
nodeId: [10, 20],
|
||||
parentNodeId: [0, 0],
|
||||
childCount: [0, 0],
|
||||
tagNameStringId: [0, 0],
|
||||
},
|
||||
boxes: {
|
||||
boxId: [100, 200],
|
||||
subjectId: [1, 2],
|
||||
frameId: [1, 1],
|
||||
borderLeft: [0, 110],
|
||||
borderTop: [0, 50],
|
||||
borderRight: [100, 210],
|
||||
borderBottom: [40, 90],
|
||||
paddingLeft: [0, 0],
|
||||
paddingTop: [0, 0],
|
||||
paddingRight: [0, 0],
|
||||
paddingBottom: [0, 0],
|
||||
contentLeft: [0, 0],
|
||||
contentTop: [0, 0],
|
||||
contentRight: [0, 0],
|
||||
contentBottom: [0, 0],
|
||||
},
|
||||
visualBoxes: {
|
||||
boxId: [], subjectId: [], frameId: [],
|
||||
borderLeft: [], borderTop: [], borderRight: [], borderBottom: [],
|
||||
paddingLeft: [], paddingTop: [], paddingRight: [], paddingBottom: [],
|
||||
contentLeft: [], contentTop: [], contentRight: [], contentBottom: [],
|
||||
},
|
||||
transforms: {
|
||||
transformId: [], subjectId: [], matrixStart: [], matrixLength: [],
|
||||
originX: [], originY: [],
|
||||
},
|
||||
matrices: { values: [] },
|
||||
rects: { rectId: [], left: [], top: [], right: [], bottom: [] },
|
||||
topology: {
|
||||
containingBlockOf: [0, 0],
|
||||
nearestPositionedAncestorOf: [0, 0],
|
||||
scrollContainerOf: [0, 0],
|
||||
stackingContextOf: [0, 0],
|
||||
formattingContextOf: [0, 0],
|
||||
clippingRootOf: [0, 0],
|
||||
paintOrderBucket: [0, 0],
|
||||
paintOrderIndex: [0, 0],
|
||||
},
|
||||
scroll: {
|
||||
containerId: [],
|
||||
scrollLeft: [],
|
||||
scrollTop: [],
|
||||
scrollWidth: [],
|
||||
scrollHeight: [],
|
||||
clientWidth: [],
|
||||
clientHeight: [],
|
||||
},
|
||||
clipping: {
|
||||
clipNodeId: [],
|
||||
subjectId: [],
|
||||
clipKind: [],
|
||||
clipLeft: [],
|
||||
clipTop: [],
|
||||
clipRight: [],
|
||||
clipBottom: [],
|
||||
parentClipNodeId: [],
|
||||
},
|
||||
visibility: {
|
||||
subjectId: [],
|
||||
isRendered: [],
|
||||
isVisible: [],
|
||||
visibleArea: [],
|
||||
clippedArea: [],
|
||||
},
|
||||
}
|
||||
|
||||
function makeClause(kind: string): ClauseDescriptor {
|
||||
return {
|
||||
clauseId: 'clause_1',
|
||||
clauseKind: kind,
|
||||
version: 1,
|
||||
subjectRef: 1,
|
||||
referenceRef: 2,
|
||||
}
|
||||
}
|
||||
|
||||
function makeResult(status: 'pass' | 'fail' | 'error', metrics?: Record<string, number>): ClauseResult {
|
||||
return {
|
||||
clauseId: 'clause_1',
|
||||
status,
|
||||
truth: status === 'error' ? 'indeterminate' : 'determinate',
|
||||
metrics,
|
||||
witness: { subjectId: 1, referenceId: 2 },
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Setup
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
beforeEach(() => {
|
||||
resetProofCounter()
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Relation-Specific Proof Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('relation-specific proofs', () => {
|
||||
it('leftOf proof includes measured gap and expected bounds', () => {
|
||||
const clause = makeClause('relation.leftOf')
|
||||
const result = makeResult('fail', {
|
||||
observedGap: -5,
|
||||
minGap: 0,
|
||||
maxGap: Infinity,
|
||||
subjectLeft: 0,
|
||||
subjectTop: 0,
|
||||
subjectRight: 100,
|
||||
subjectBottom: 40,
|
||||
refLeft: 90,
|
||||
refTop: 50,
|
||||
refRight: 190,
|
||||
refBottom: 90,
|
||||
})
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.strictEqual(proof.outcome, 'fail')
|
||||
assert.ok(proof.failedPredicate)
|
||||
assert.strictEqual(proof.failedPredicate!.relationKind, 'leftOf')
|
||||
assert.strictEqual(proof.failedPredicate!.measuredGap, -5)
|
||||
assert.strictEqual(proof.failedPredicate!.expectedMinGap, 0)
|
||||
assert.ok(proof.failedPredicate!.subjectRect)
|
||||
assert.strictEqual(proof.failedPredicate!.subjectRect!.right, 100)
|
||||
assert.ok(proof.failedPredicate!.referenceRect)
|
||||
assert.strictEqual(proof.failedPredicate!.referenceRect!.left, 90)
|
||||
})
|
||||
|
||||
it('above proof includes vertical gap and positions', () => {
|
||||
const clause = makeClause('relation.above')
|
||||
const result = makeResult('fail', {
|
||||
observedGap: -3,
|
||||
minGap: 0,
|
||||
maxGap: Infinity,
|
||||
subjectLeft: 0,
|
||||
subjectTop: 0,
|
||||
subjectRight: 100,
|
||||
subjectBottom: 40,
|
||||
refLeft: 0,
|
||||
refTop: 35,
|
||||
refRight: 100,
|
||||
refBottom: 75,
|
||||
})
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.strictEqual(proof.failedPredicate!.relationKind, 'above')
|
||||
assert.strictEqual(proof.failedPredicate!.measuredGap, -3)
|
||||
assert.ok(proof.failedPredicate!.subjectRect)
|
||||
assert.ok(proof.failedPredicate!.referenceRect)
|
||||
})
|
||||
|
||||
it('inside proof includes overflow edges', () => {
|
||||
const clause = makeClause('relation.inside')
|
||||
const result = makeResult('fail', {
|
||||
overflowLeft: 10,
|
||||
overflowTop: 0,
|
||||
overflowRight: -5,
|
||||
overflowBottom: 0,
|
||||
subjectLeft: 10,
|
||||
subjectTop: 0,
|
||||
subjectRight: 105,
|
||||
subjectBottom: 40,
|
||||
refLeft: 0,
|
||||
refTop: 0,
|
||||
refRight: 100,
|
||||
refBottom: 40,
|
||||
})
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.strictEqual(proof.failedPredicate!.relationKind, 'inside')
|
||||
assert.ok(proof.failedPredicate!.overflowEdges)
|
||||
assert.strictEqual(proof.failedPredicate!.overflowEdges!.left, 10)
|
||||
assert.strictEqual(proof.failedPredicate!.overflowEdges!.right, -5)
|
||||
assert.ok(proof.failedPredicate!.subjectRect)
|
||||
assert.ok(proof.failedPredicate!.referenceRect)
|
||||
})
|
||||
|
||||
it('atLeast proof includes measured vs expected dimensions', () => {
|
||||
const clause = makeClause('size.atLeast')
|
||||
const result = makeResult('fail', {
|
||||
observed: 80,
|
||||
min: 100,
|
||||
})
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.strictEqual(proof.failedPredicate!.relationKind, 'atLeast')
|
||||
assert.strictEqual(proof.failedPredicate!.measuredValue, 80)
|
||||
assert.strictEqual(proof.failedPredicate!.expectedMin, 100)
|
||||
})
|
||||
|
||||
it('atMost proof includes measured vs expected dimensions', () => {
|
||||
const clause = makeClause('size.atMost')
|
||||
const result = makeResult('fail', {
|
||||
observed: 120,
|
||||
max: 100,
|
||||
})
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.strictEqual(proof.failedPredicate!.relationKind, 'atMost')
|
||||
assert.strictEqual(proof.failedPredicate!.measuredValue, 120)
|
||||
assert.strictEqual(proof.failedPredicate!.expectedMax, 100)
|
||||
})
|
||||
|
||||
it('alignedWith proof includes delta and tolerance', () => {
|
||||
const clause = makeClause('alignment.alignedWith')
|
||||
const result = makeResult('fail', {
|
||||
delta: 5,
|
||||
tolerance: 1,
|
||||
})
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.strictEqual(proof.failedPredicate!.relationKind, 'alignedWith')
|
||||
assert.strictEqual(proof.failedPredicate!.measuredValue, 5)
|
||||
assert.strictEqual(proof.failedPredicate!.expectedMax, 1)
|
||||
})
|
||||
|
||||
it('centeredWithin proof includes deltaX, deltaY and tolerance', () => {
|
||||
const clause = makeClause('alignment.centeredWithin')
|
||||
const result = makeResult('fail', {
|
||||
deltaX: 3,
|
||||
deltaY: 4,
|
||||
tolerance: 2,
|
||||
})
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.strictEqual(proof.failedPredicate!.relationKind, 'centeredWithin')
|
||||
assert.strictEqual(proof.failedPredicate!.measuredValue, 3)
|
||||
assert.strictEqual(proof.failedPredicate!.expectedMax, 2)
|
||||
})
|
||||
|
||||
it('omits failedPredicate on pass', () => {
|
||||
const clause = makeClause('relation.leftOf')
|
||||
const result = makeResult('pass', { observedGap: 10, minGap: 0 })
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.strictEqual(proof.outcome, 'pass')
|
||||
assert.strictEqual(proof.failedPredicate, undefined)
|
||||
})
|
||||
|
||||
it('falls back to generic synthesis for unknown relation kinds', () => {
|
||||
const clause = makeClause('relation.unknownRelation')
|
||||
const result = makeResult('fail', { foo: 10, bar: 20 })
|
||||
|
||||
const proof = generateProof(result, clause, world)
|
||||
|
||||
assert.ok(proof.failedPredicate)
|
||||
assert.strictEqual(proof.failedPredicate!.relationKind, 'unknownRelation')
|
||||
assert.strictEqual(proof.failedPredicate!.op, '<')
|
||||
assert.strictEqual(proof.failedPredicate!.left, 10)
|
||||
assert.strictEqual(proof.failedPredicate!.right, 20)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user