Testing and verification
Testing rules cover risk-based validation, doctests, feature matrices, deterministic tests, parser samples, command construction, dependency floors, and regressions.
Checks, examples, doctests, feature matrices, and regressions.
22 rules
Check important feature combinationsExercise default, disabled-default, all-feature, and important feature-pair builds. Feature flags change APIs and compile paths, so use a risk-based matrix instead of every combo.Check maintainer commands in CIPut documented maintainer commands, or intentionally stronger equivalents, in CI. This keeps local instructions honest while leaving slow or credentialed checks to special jobs.Check MSRV and platformsRun checks for declared Rust versions and supported platforms when they are promised. Compatibility claims are public contracts, so skip matrices only when no such claim exists.Choose validation by riskMatch the amount and kind of validation to the changed surface and failure cost. Cheap checks come first, but risky or uncertain behavior needs targeted evidence.Cover async routing edge casesTest late replies, unrelated input, timeouts, and unmatched async responses. These cases protect request correlation and cleanup without relying on wall-clock luck.Cover local logic with unit testsUse unit tests for small local logic such as parsing helpers and policy branches. They give fast precise feedback, while boundary behavior still needs higher-level tests.Cover navigation boundariesExercise first, last, empty, oversized, and repeated-navigation states in tests. Boundary cases catch cursor and scrolling bugs that polished manual demos often miss.Cover policy outcomesTest allowed, denied, redacted, fallback, and unsupported policy outcomes. Policy value lives at decision boundaries, so assert caller-visible behavior instead of internals.Cover public boundaries with integration testsUse integration tests to prove public module, crate, or adapter boundaries. They catch composition failures unit tests miss, while local logic can stay unit-tested.Cover public examples with doctestsCompile public documentation examples as doctests when they do not need fragile state. Executable examples catch stale guidance, reserving no-run or ignored examples for real limits.Fuzz parsers, formatters, and state machinesUse fuzzing or property tests for input-heavy parsers, formatters, and state machines. Large input spaces hide failures, so keep long fuzzing outside PR gates unless it is stable.Keep drift claims alignedTie support claims, fixtures, examples, docs, and API paths to executable drift checks. Stable claims need evidence, but wording-only changes should not break broad tests.Keep slow checks out of PR CIKeep long fuzzing, exhaustive matrices, and noisy benchmarks out of required PR CI. Fast gates preserve review flow, while heavier checks belong in release or scheduled validation.Match evidence to surfaceValidate the actual changed surface, such as rendered docs, API behavior, or byte output. The narrowest relevant proof is more persuasive than unrelated broad test success.Prefer deterministic testsPrefer tests controlled by fixed inputs, clocks, ordering, and local state. Deterministic failures are reproducible, while real integration checks should be isolated by cost.Prove command construction and displayTest both executable command shape and displayed command text when users rely on them. Quoting, redaction, ordering, and platform formatting can fail even when a local happy path works.Prove contracts not triviaWrite tests around observable contracts instead of private helper trivia. This preserves refactoring freedom unless the detail is itself the promised behavior, such as a stable user-facing output contract.Run docs as a first-class gateTreat documentation checks as real validation for examples, links, commands, and claims. Prose-only edits may need less proof, but API-facing docs should fail before stale guidance ships.Run fast format and lint gates earlyRun cheap format and lint gates early in the feedback loop. They remove mechanical failures quickly, but they do not replace validation of risky behavior.Use realistic parser samplesTest parsers with representative input, malformed cases, and safe degradation examples. Real samples catch compatibility failures, but fixtures should be minimized and scrubbed.Validate declared minimum dependency versionsCheck that declared minimum dependency versions still build the supported behavior. Lockfile tests can hide newer API usage, so use targeted minimal-version checks when needed.Write regression tests for bug fixesAdd a test that fails before the bug fix and protects the repaired contract. Skip only when reproduction is impractical, and then record the closest trustworthy validation.