vike
DeveloperTesting

Property tests

Randomized suites over the pure cores where golden fixtures only pin examples — the laws they assert, the never-widen discipline, and why a counterexample seed is committed.

Golden fixtures pin examples somebody chose. Property tests pin the laws those examples were meant to illustrate, over inputs nobody chose. proptest is a workspace dev-dependency, pinned in the root manifest with its rationale: randomized inputs over the pure cores — sizing, the pinned round and format wire sites, the risk-gate parity — find edges the golden fixtures miss. It is dev-only, so it never reaches the shipped order-signing binary's embedded SBOM, though it does join the source-lockfile supply-chain tree, which the manifest records as the accepted cost of the workspace's first property framework.

The suites and the laws they hold

crates/vike-model/tests/scalar_props.rs — the grid-rounding primitives every live order's price and quantity flows through. Idempotence is the central law and also the robust statement that the result lies exactly on the step grid: a rounded value is a fixed point of the rounding. It is asserted with exact equality, no tolerance.

crates/vike-bridge-core/tests/format_props.rs — the primary pinned Decimal wire site. Every step in its generator is a terminating decimal, so the internal Decimal division is exact for these inputs, which is what lets every assertion be an exact Decimal comparison with no numeric tolerance. As the header puts it, a failure is therefore a genuine wire bug — a real overshoot or precision leak — never a rounding artifact to be papered over.

crates/vike-analytics/tests/sizing_props.rs — the eight position sizers. Its header records why it exists: Sizer::size had zero direct tests, touched only indirectly by one golden run, making it the largest money-path coverage hole in the workspace.

crates/vike-backtest/tests/riskgate_simbroker_parity.rs — the randomized live-versus-backtest risk parity. Four real money bugs were found on one day in 2026 by manually asking "where is this rule implemented twice?", and not one had been caught by a test. The suite's own framing is that the pinning is the value: an unpinned divergence fails the test, and a newly pinned one is a loud, reviewable diff rather than a silent behaviour change.

crates/vike-exec/tests/order_fsm_props.rs — six laws folded over arbitrary lifecycle-event sequences against the one mutator of order state: terminal absorption, error purity (a refused apply never mutates), fill monotonicity and VWAP boundedness, at most one live-to-terminal transition, the liquidated trap, and the fill-derived restore.

Parser totality suites — crates/bridges/binance/tests/mapper_props.rs and its bybit twin feed the real mappers arbitrary JSON, arbitrary text, and every deterministic mutation of every committed captured fixture. The property is totality: a hostile or truncated frame may decode to nothing, but it must never panic the user-data pump thread and must never fabricate an event flood — bounded by MAX_EVENTS_PER_FRAME. crates/bridges/ctrader/tests/framing_props.rs does the same for the wire framing every inbound byte crosses first, including the length-prefix denial-of-service edge: a claimed four-gibibyte frame must not be allocated up front.

The three rules

A counterexample is a real finding, not a property to relax

The FSM suite states the failure policy for all of them: stop and report with the seed proptest prints; never adjust the subject to satisfy a property without an explicit decision. Widening a tolerance to make a property pass is the same move the parity gate forbids, arriving from a different direction.

Commit the regression seed. The workspace convention, stated in the root manifest beside the dependency itself, is that any generated proptest-regressions/ file is committed, so a CI-found counterexample reproduces on the next run and on every developer's box.

A slack is documented or it is a fudge. scalar_props allows exactly one floating-point epsilon — a half-step bound whose slack covers the multiply's rounding, orders of magnitude below the half-step it guards, so it cannot hide a genuinely off-grid result. Everything else in that file and all of format_props is exact. The sizing suite carries a few-ULP round-trip epsilon on its two cap properties and says so inline.

A domain bound is an argument, not a convenience. scalar_props keeps values and steps inside the real price and tick range so value / step stays under the exact-integer ceiling of f64. Beyond that ceiling the multiple itself is unrepresentable and idempotence would fail as a fundamental floating-point limit rather than a bug — and no venue quotes a 1e-8 tick on a 1e6 price.

The trap a property suite is uniquely prone to

A property over an arm the generator never reaches is vacuously green. The FSM suite answers that with a generator-coverage witness that fails by name when a lifecycle variant goes missing from its event generator. The binance parser suite answers it differently, by mixing real dispatch keys into the generator so it actually reaches the mapper's arms instead of bouncing off the first lookup. Both are the same defence: a randomized suite must prove its randomness arrives somewhere.

Where a property suite may live

Property suites always get their own test binary. crates/vike-backtest's tests/ are grouped into shared binaries to cut link time, and the admission rule in that crate's own notes excludes a file carrying a proptest regression sidecar — along with #![cfg] feature gates, #[ignore]d tests and any process-global mutation — because one binary runs its tests as threads in one process. See testing for the tiers, and adding to the parity suite for the procedure.

On this page