RustForge is a modular, easily adoptable Rust test-suite template that scales from basic cargo test workflows to compiler-style coverage.
Most Rust projects eventually build their own test infrastructure —
stitching together cargo test, Criterion, proptest, cargo-fuzz,
trybuild, insta, cargo-llvm-cov, and the CI wiring to run all of it
consistently. RustForge is that infrastructure, already built, already
wired into CI, and verified to actually work end-to-end — a starting
point, not a skeleton you fill in yourself.
- Truly modular — seven independent category crates (
syntax,semantic,performance,fuzz,integration,edge-cases, plus sharedcore-tests); adopt only what you need.cargo test --workspacepulls in zero extra dependencies by default — heavier tooling (Tokio, Criterion,proptest,trybuild,insta) is opt-in per feature flag, see Feature Flags. - Comprehensive by design — syntax and compile-fail tests, ownership/
semantic correctness, Criterion benchmarks with regression guards (plus
statistical baseline comparison),
fuzzing (in-process
proptestand realcargo-fuzztargets, with a corpus management guide), snapshot testing, boundary/ edge-case checks, and cross-category integration tests. Every one of these actually runs in CI, not just in a README example. - Production-grade from day one — multi-toolchain, multi-OS CI; MSRV
verified by a dedicated job, not just claimed;
cargo-denysupply-chain checks; Dependabot for both the main and detachedfuzz/workspaces;#![warn(missing_docs)]enforced as a hard CI error; issue/PR templates and a contributor checklist. See Tooling & Automation for the full list. - Easy to adopt, no lock-in — a template, not a framework. Use it as a
GitHub template repo, copy
crates/into an existing workspace (see the Quickstart above for the one real gotcha we found by actually testing that flow), or take individual crates — most depend only on sharedcore-tests, nothing else. - Scales with you — start with
syntax/semantic/integrationon a small library; grow into fuzzing, property-based testing, and regression-guarded benchmarks as the project's rigor requirements grow.
- Library authors who want test coverage adopters can trust
- Teams building production Rust services who'd rather not assemble this tooling from scratch
- Anyone who'd rather start from a working, CI-verified baseline than bootstrap one
my-test-suite/
├── Cargo.toml
├── crates/
│ ├── core-tests/
│ ├── syntax-tests/
│ ├── semantic-tests/
│ ├── performance-tests/
│ ├── fuzz-tests/
│ ├── integration-tests/
│ └── edge-cases/
├── tests/
├── examples/
├── fuzz/
├── ci/
├── scripts/
└── docs/
- 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.tomlhas a[workspace.package]table withedition,rust-version, andlicense— every crate here inherits those via.workspace = true, andcargo testfails immediately (workspace.package.edition was not defined) without it. See "Common Pitfalls" indocs/adoption.md— this is the #1 thing that trips up merging into an existing project, confirmed by actually testing the merge flow, not just assumed. - Start with core categories (
syntax,semantic,integration). - Run:
cargo test --workspace- Opt into advanced categories (
performance-tests,fuzz-tests,edge-cases) and their feature flags (perf,fuzz,edge) as needed — see Feature Flags below.
core-tests: shared fixtures/helpers for reusable assertions and builders.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.integration-tests: end-to-end behavior tests across categories.edge-cases: boundary-value and robustness checks.
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 |
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/, which is a detached
workspace (see fuzz/README.md) since fuzzing needs
nightly and its own dependency resolution. Build it with:
cd fuzz && cargo +nightly fuzz buildThe 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'sfuzzfeature pinsproptestto the~1.8line specifically to stay within 1.75 (proptest 1.9+ needs rustc 1.82+).syntax-tests'scompile-failfeature pinstrybuildto=1.0.111for the same reason (1.0.112+ needs rustc 1.76+).performance-tests'sperffeature depends oncriterion, whose own dependency chain (clap,regex,plotters, ...) tracks current stable Rust and can exceed 1.75. Use a recent stable toolchain when runningcargo bench.
CI's test job runs on stable/beta/nightly with every feature except
compile-fail (see ci/README.md 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.
- Native
cargo testis first-class. - CI is a 12-job pipeline:
fmt+clippy+tests across a stable/beta/nightly × ubuntu/windows/macos/linux-arm64 matrix, a stable-onlynextestjob, a stable-onlytrybuildjob, a stable-onlyloomjob (concurrency-permutation testing, seedocs/adding-tests.md), a nightlyfuzz-buildjob (build + short smoke run per target on every push/PR, plus a longer campaign on the daily schedule — seedocs/fuzzing.md), a nightlycoveragejob (--doctestsincluded, so///examples count too — needs nightly for rustdoc's unstable--persist-doctests), a nightlyudepsjob (informational, unused-dependency check), an MSRV job, a stable-onlyhackjob (per-crate feature-powerset testing via cargo-hack), a nightlyminimal-versionsjob (tests against the lowest dependency versions eachCargo.tomlconstraint allows, not just the newest resolvable ones), acargo-denysupply-chain job, and a stable-onlydocsjob. Seeci/README.mdfor what each one does and why it's scoped the way it is. justfile—just check,just test-all,just bench,just fuzz-run <target>,just coverage,just doc, and more; runjust --listfor the full set.scripts/check.shandscripts/coverage.sh(which thecheck/coveragerecipes call) work standalone too, nojustrequired. Seescripts/README.md.- Runnable examples live under each crate's
examples/directory, e.g.cargo run -p core-tests --example fixture_walkthrough. Seeexamples/README.md. - 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 runcargo test --workspace. - Dependency hygiene:
deny.toml(licenses/advisories/bans/sources, checked in CI) and.github/dependabot.yml(weekly update PRs for both the main workspace and the detachedfuzz/workspace).
Recommended defaults:
- Coverage:
scripts/coverage.shorjust coverage(installs guidance included); or manually:rustup toolchain install nightly --component llvm-tools-preview && cargo install cargo-llvm-cov --locked, thencargo +nightly llvm-cov --workspace --all-features --doctests --html(nightly is needed for--doctests). Also runs in CI as a downloadable artifact — see thecoveragejob. - 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 replacescargo test. - Performance regressions:
just bench-baselinethenjust bench-comparefor a statistically-grounded before/after comparison — seedocs/performance-regression-testing.md. - Snapshot testing:
cargo insta reviewforsyntax-tests'snapshotfeature — see "Snapshot test" indocs/adding-tests.md. - Fuzzing beyond the CI smoke-run: corpus/crash minimization, coverage,
reading ASan output — see
docs/fuzzing.md. - CI artifacts: logs, reproducers, and coverage reports on failures
- Foundation: keep workspace + shared helpers.
- Categories: grow syntax/semantic coverage first.
- Automation: enforce CI and coverage gates.
- Advanced: add fuzz/property/perf regression suites.
- Polish: expand docs/examples and maintain contributor checklist.
See docs/adoption.md for incremental rollout guidance.
See CONTRIBUTING.md for the contributor checklist and
guidance on adding new test categories.
Dual-licensed under MIT or Apache-2.0, 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.