Repository navigation
Home
- Quickstart (Plug-and-Play)
Use this repo as a template, or copy `Cargo.toml` + `crates/` into your existing workspace.
If merging into an existing workspace, make sure its root `Cargo.toml` has a `[workspace.package]` table with `edition`, `rust-version`, and `license` — every crate here inherits those via `.workspace = true`, and `cargo test` fails immediately (`workspace.package.edition was not defined`) without it.
> Common Pitfalls — this is the #1 thing that trips up merging into an existing project, confirmed by actually testing the merge flow, not just assumed. See *Common Pitfalls* in `docs/adoption.md` [blocked].
Start with core categories (syntax, semantic, integration). Run:
cargo test --workspaceOpt into advanced categories (`performance-tests`, `fuzz-tests`, `edge-cases`) and their feature flags (`perf`, `fuzz`, `edge`) as needed — see Feature Flags below.
- Module Responsibilities
- core-tests: shared fixtures/helpers for reusable assertions, builders, and differential testing (`assert_impls_agree`). - syntax-tests: parser/syntax-facing tests — compile-fail/pass (trybuild) and snapshot (insta) tests included. - semantic-tests: ownership, borrowing, traits, and async semantics. - performance-tests: benchmark/perf guard entry points. - fuzz-tests: fuzz harness-friendly entry points, plus property-based differential testing (`fuzz` feature). - integration-tests: end-to-end behavior tests across categories. - edge-cases: boundary-value and robustness checks.
- Feature Flags
Optional, dependency-pulling tooling is gated behind Cargo features so `cargo test --workspace` stays fast by default. Opt in per crate or with `--all-features`:
| Crate | Feature | Adds | What it unlocks |
| --- | --- | --- | --- |
| core-tests | async | tokio | async fixture helpers (`async_support::default_user_fixture_async`, concurrent fixture loading) |
| core-tests | no_std | — | core-only helper module (`no_std_support`), compiled under a genuinely `#![no_std]` crate in `tests/no_std_check.rs` |
| semantic-tests | async | tokio | an async ownership test (`cargo test -p semantic-tests --features async`) |
| performance-tests | perf | criterion | `cargo bench -p performance-tests --features perf` |
| fuzz-tests | fuzz | proptest | property tests (`cargo test -p fuzz-tests --features fuzz`) |
| edge-cases | edge | — | checked-arithmetic boundary helpers (`overflow_checks`) guarding `usize` under/overflow |
| syntax-tests | compile-fail | trybuild | UI/compile-fail tests (`cargo test -p syntax-tests --features compile-fail`) — CI-pinned to stable only, see `ci/README.md` [blocked] |
| syntax-tests | snapshot | insta | struct-shaped snapshot tests (`cargo test -p syntax-tests --features snapshot`); update with `cargo insta review` |
The real cargo-fuzz scaffold lives in `fuzz/` [blocked], which is a detached workspace (see `fuzz/README.md` [blocked]) since fuzzing needs nightly and its own dependency resolution. Build it with:
cd fuzz && cargo +nightly fuzz build- MSRV
The workspace declares `rust-version = 1.75` — that's the floor for the default build of every crate (no extra features). Optional features that pull in actively-developed ecosystem tooling can need a newer toolchain independently of this template, since those crates set their own MSRV:
- `fuzz-tests`'s `fuzz` feature pins proptest to the `1.8` line specifically to stay within 1.75 (proptest 1.9+ needs rustc 1.82+). - `syntax-tests`'s `compile-fail` feature pins trybuild to `=1.0.111` for the same reason (1.0.112+ needs rustc 1.76+). - `performance-tests`'s `perf` feature depends on criterion, whose own dependency chain (clap, regex, plotters, ...) tracks current stable Rust and can exceed 1.75. Use a recent stable toolchain when running `cargo bench`.
CI's test job runs on stable/beta/nightly with every feature except `compile-fail` (see `ci/README.md` [blocked] for why), so it will surface any future MSRV drift on those toolchains. A dedicated `msrv` job verifies the default build against Rust 1.75 itself, rather than just asserting the promise in docs.
- Tooling & Automation
Native `cargo test` is first-class. CI is a 15-job pipeline: fmt+clippy+tests across a stable/beta/nightly × ubuntu/windows/macos/linux-arm64 matrix, a stable-only nextest job (JSON event stream, uploaded as an artifact — see `docs/machine-readable-outputs.md` [blocked]), a stable-only trybuild job, a stable-only loom job (concurrency-permutation testing, see `docs/adding-tests.md` [blocked]), a nightly miri job (interprets the suite to detect undefined behavior and data races — see `docs/best-practices.md` [blocked]), a nightly fuzz-build job (build + short smoke run per target on every push/PR, plus a longer campaign on the daily schedule — see `docs/fuzzing.md` [blocked]), a nightly coverage job (`--doctests` included, so `/` examples count too — needs nightly for rustdoc's unstable `--persist-doctests`; LCOV artifact too), a nightly udeps job (informational, unused-dependency check), an MSRV job, a stable-only hack job (per-crate feature-powerset testing via cargo-hack), a nightly minimal-versions job (tests against the lowest dependency versions each Cargo.toml constraint allows, not just the newest resolvable ones), a cargo-deny supply-chain job (SARIF uploaded to code scanning), and a stable-only docs job. A stable-only adoption job additionally verifies the template's core promise end-to-end — both adoption paths from `docs/adoption.md` [blocked] (cargo generate output, and `crates/` copied into a synthetic host workspace) are actually run and tested, so *easy to adopt* is a CI-checked claim, not a README one. A stable-only reports job emits clippy JSON + SARIF for machine consumption. See `ci/README.md` [blocked] for what each one does and why it's scoped the way it is.
`justfile` [blocked] — `just check`, `just test-all`, `just bench`, `just fuzz-run <target>`, `just coverage`, `just doc`, `just miri`, `just adopt-test`, `just eval <path>` (evaluate an external implementation against the fixed harness — see `docs/evaluation-harness.md` [blocked]), the machine-readable report recipes (`just test-json`, `just coverage-lcov`, `just clippy-json`, `just deny-json`, `just mutants-list-json` / `just mutants-json`), the scoped mutation recipes (`just mutants-crate`, `mutants-file`, `mutants-diff`), and more; run `just --list` for the full set. `scripts/check.sh` and `scripts/coverage.sh` (which the check/coverage recipes call) work standalone too, no just required. See `scripts/README.md` [blocked].
Runnable examples live under each crate's `examples/` directory, e.g. `cargo run -p core-tests --example fixture_walkthrough`. See `examples/README.md` [blocked].
Optional ecosystem tools are layered in incrementally behind the features above (criterion, proptest, trybuild, cargo-fuzz, tokio) or as standalone dev tools (cargo-nextest, cargo-llvm-cov, cargo-deny, just) — each one is opt-in and documented where it's used, not a hard requirement to run `cargo test --workspace`.
Dependency hygiene: `deny.toml` [blocked] (licenses/advisories/bans/sources, checked in CI) and `.github/dependabot.yml` [blocked] (weekly update PRs for both the main workspace and the detached `fuzz/` workspace).
- Coverage, Reporting, and Debugging
Recommended defaults:
- Coverage: `scripts/coverage.sh` or `just coverage` (installs guidance included); or manually: `rustup toolchain install nightly --component llvm-tools-preview && cargo install cargo-llvm-cov --locked`, then `cargo +nightly llvm-cov --workspace --all-features --doctests --html` (nightly is needed for `--doctests`). Also runs in CI as a downloadable artifact — see the coverage job. - Test output: `cargo test -- --nocapture` - Alternative runner: `cargo nextest run --workspace` (install: `cargo install cargo-nextest --locked`) — faster on larger suites, one process per test; doesn't run doc-tests, so it complements rather than replaces `cargo test`. - Performance regressions: `just bench-baseline` then `just bench-compare` for a statistically-grounded before/after comparison — see `docs/performance-regression-testing.md` [blocked]. - Optional quality signals (opt-in, informational — install the tool once, never gates anything): `just bloat` / `just bloat-json` (cargo-bloat — code size per function/crate; needs a binary target, e.g. `just bloat --bin tally` from examples/cli-starter), `just size` (release-build the example binary and report its size; in an adopted workspace, compare your own `target/release/<bin>` across commits), and `just timings` (cargo's built-in compile-time report in `target/cargo-timings/`). - Snapshot testing: `cargo insta review` for syntax-tests' snapshot feature — see *Snapshot test* in `docs/adding-tests.md` [blocked]. - Fuzzing beyond the CI smoke-run: corpus/crash minimization, coverage, reading ASan output — see `docs/fuzzing.md` [blocked]. - CI artifacts: logs, reproducers, and coverage reports on failures
- Adoption Roadmap
1. Foundation: keep workspace + shared helpers. 2. Categories: grow syntax/semantic coverage first. 3. Automation: enforce CI and coverage gates. 4. Advanced: add fuzz/property/perf regression suites. 5. Polish: expand docs/examples and maintain contributor checklist.
See `docs/adoption.md` for incremental rollout guidance.
- Contributing
See CONTRIBUTING.md [blocked] for the contributor checklist and guidance on adding new test categories.
- License
Dual-licensed under MIT [blocked] or Apache-2.0 [blocked], at your option — the convention most of the Rust ecosystem uses. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion, as defined in the Apache-2.0 license, shall be dual-licensed as above without any additional terms or conditions.