Testing
Unit tests, proptest-based Jacobian verification, and quick bench tests.
Testing
The solver includes a comprehensive test suite covering unit tests, property-based tests, and quick benchmarks.
Unit Tests
Located in src/tests.rs, the unit tests cover:
- All 47+ constraint types with concrete geometric configurations
- Each test calls
sys.solve()followed bycheck_constraints_satisfied() - Tests verify convergence, residual bounds, and geometric correctness
- Edge cases: degenerate configurations, overconstrained systems, near-singular Jacobians
# Run all unit tests cargo test # Run a specific test cargo test test_distance_constraint # Run with output cargo test -- --nocapture
Proptest-Based Jacobian Verification
The property-based test suite in src/proptest_jacobian.rs is the primary guarantee of Jacobian correctness.
Strategy
For each constraint type, the proptest framework:
- Generates 50 random configurations with random entity positions and constraint parameters
- Computes the analytical Jacobian using the hand-derived partial derivatives
- Computes the numerical Jacobian using central differences:
∂r/∂x ≈ (r(x+h) − r(x−h)) / 2h - Compares the two matrices element-by-element
Tolerances
| Metric | Tolerance |
|---|---|
| Absolute difference | < 1e-4 |
| Relative difference | < 1e-2 |
The relative tolerance is generous to accommodate the inherent inaccuracy of finite differences, while the absolute tolerance catches gross errors.
Coverage
All 47+ constraint types are covered:
- Point constraints: Distance, Horizontal, Vertical, PointOnLine, PointOnCircle, Coincident, Midpoint, etc.
- Line constraints: Horizontal, Vertical, Perpendicular, Parallel, Angle, EqualLength
- Circle/Arc constraints: TangentLineCircle, TangentCircleCircle, Radius, EqualRadius, Concentric
- Ellipse constraints: TangentLineEllipse, EqualMinorAxes, EqualMajorAxes
- Hyperbola/Parabola constraints: TangentLineHyperbola, PointOnHyperbola, etc.
Near-Degenerate Case Filtering
Random generation occasionally produces near-degenerate cases (e.g., two points nearly coincident for a distance constraint). These are filtered out:
proptest! {
#[test]
fn proptest_distance_jacobian(a in -100.0..100.0, b in -100.0..100.0, d in 0.1..100.0) {
// Skip if points are too close (numerical instability)
prop_assume!(d > 0.1);
// ... compare Jacobians
}
}
Quick Bench Test
benchmarks/quick_bench.rs provides fast wall-clock benchmarks for development:
cargo test --test quick_bench
Unlike Criterion benchmarks, these run in seconds and give approximate timing data. Useful for quick regression checks during development.
Running Tests
# All tests (unit + proptest) cargo test # Only unit tests (skip proptests) cargo test --lib # Only proptests cargo test proptest # Quick bench cargo test --test quick_bench # Verbose output cargo test -- --nocapture
Proptest Regression File
When a proptest fails, the failing seed is recorded in:
proptest-regressions/proptest_jacobian.txt
This file allows deterministic replay of failing cases. To replay:
PROPTEST_CASES=1 cargo test proptest_jacobian
The regression file is committed to version control to ensure CI always tests previously-failing seeds.