Cargo Commands
22 min read
Cargo is the command you will type hundreds of times a day. It is Rust’s build tool, test runner, formatter front-end, linter front-end, documentation generator, and package manager — all behind one consistent CLI. This file is your reference for the everyday commands and the difference between cargo new and cargo init.
Quick Overview
Section titled “Quick Overview”Where a Node.js project juggles npm, tsc, jest, prettier, eslint, and typedoc, Rust uses a single tool: Cargo. The same handful of subcommands work in every Rust project with zero configuration, because the conventions (where source lives, how tests are written, how the binary is named) are baked into the language and toolchain. This page focuses on the commands themselves; the Cargo.toml manifest and dependency management live in sibling files.
TypeScript/JavaScript Example
Section titled “TypeScript/JavaScript Example”A typical Node.js/TypeScript project wires up its workflow through package.json scripts, each delegating to a different tool you installed separately:
{ "name": "user-service", "version": "1.0.0", "scripts": { "build": "tsc", "start": "node dist/index.js", "dev": "tsx src/index.ts", "test": "vitest run", "lint": "eslint .", "format": "prettier --write .", "docs": "typedoc" }, "devDependencies": { "typescript": "^5.6.0", "tsx": "^4.19.0", "vitest": "^2.1.0", "eslint": "^9.0.0", "prettier": "^3.3.0", "typedoc": "^0.26.0" }}A new contributor has to read package.json to learn that “run the app” is npm run dev, “test” is npm test, and “format” is npm run format. Every project invents its own script names.
npm install # Install dependenciesnpm run dev # Run in watch modenpm test # Run testsnpm run lint # Lintnpm run format # Formatnpm run build # Compile to dist/Rust Equivalent
Section titled “Rust Equivalent”In Rust, the same workflow uses standard Cargo subcommands that are identical across every project. There is no scripts table to define or memorize:
# Create a new binary project (the equivalent of `npm init` + scaffolding)cargo new user-servicecd user-service
# Add dependencies (writes to Cargo.toml, like `npm install <pkg>`)cargo add serde --features derivecargo add --dev assert_cmd # a dev-only dependency
cargo check # Type-check without producing a binary (fastest feedback loop)cargo run # Build + run the binarycargo test # Run all tests (unit, integration, and doctests)cargo clippy # Lint (the eslint equivalent)cargo fmt # Format (the prettier equivalent)cargo doc --open # Generate HTML docs and open them (the typedoc equivalent)cargo build --release # Optimized production buildTip: Because these commands are universal, you can clone any Rust project and immediately know that
cargo runruns it,cargo testtests it, andcargo build --releaseproduces the optimized artifact. No per-project script archaeology required.
Detailed Explanation
Section titled “Detailed Explanation”cargo new — scaffold a brand-new project
Section titled “cargo new — scaffold a brand-new project”cargo new <name> creates a new directory, lays out the standard structure, and initializes a Git repository. Here is the real output and resulting tree:
$ cargo new hello Creating binary (application) `hello` packagenote: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.htmlhello├── .git/├── .gitignore # contains just `/target`├── Cargo.toml # the manifest (like package.json)└── src/ └── main.rs # entry point with a `fn main` that prints "Hello, world!"By default you get a binary (executable) crate. Pass --lib for a library crate, which produces src/lib.rs instead of src/main.rs:
cargo new my_app # binary -> src/main.rscargo new my_lib --lib # library -> src/lib.rsThe edition field in the generated Cargo.toml is filled in for you with the newest edition your toolchain supports — on a current stable toolchain that is "2024" (the latest stable edition). You never pick an edition by hand for a new project.
Note: The crate name in
Cargo.tomlfollows Rust’ssnake_caseconvention. If you writecargo new my-service, the directory ismy-servicebut the crate name becomesmy_service(hyphens are not valid in Rust identifiers). This is unlike npm, where@scope/my-serviceis a perfectly normal package name.
cargo init — adopt an existing directory
Section titled “cargo init — adopt an existing directory”cargo init does the same scaffolding as cargo new, but in the current (already-existing) directory instead of creating a new one. This is the analog of running npm init inside a folder you already have:
$ mkdir existing_app && cd existing_app$ cargo init Creating binary (application) packagenote: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.htmlexisting_app/├── .git/├── .gitignore├── Cargo.toml└── src/ └── main.rscargo init is what you reach for when you have a directory with, say, a README.md and a .git already (perhaps from git clone) and you want to turn it into a Cargo project without nesting another folder inside it. Like cargo new, it accepts --lib.
Note:
cargo initwill not clobber an existingsrc/main.rsorCargo.toml; it only adds what is missing. If the directory is already a Git repo, it skips Git initialization rather than re-running it.
cargo check — fastest feedback
Section titled “cargo check — fastest feedback”cargo check runs the full compiler front-end — parsing, type checking, borrow checking — but stops before code generation and linking. It catches every type error and borrow error without spending time producing a runnable binary, so it is dramatically faster than a full build. Use it as your inner loop; it is the closest thing to tsc --noEmit.
$ cargo check Checking greeter v0.1.0 (/path/to/greeter) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11scargo build — compile to an artifact
Section titled “cargo build — compile to an artifact”cargo build compiles your crate and all its dependencies into an actual binary (or .rlib for a library). Debug builds land in target/debug/; release builds in target/release/.
$ cargo build Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.21s
$ cargo build --release Compiling args_demo v0.1.0 (/path/to/args_demo) Finished `release` profile [optimized] target(s) in 0.17sThe default debug profile compiles fast and includes debug info but does little optimization. The --release profile turns on optimizations (opt-level = 3 by default), producing a much faster binary at the cost of a slower compile. Use debug while developing, --release for benchmarks and production. Profile configuration is covered in Cargo.toml.
cargo run — build and execute
Section titled “cargo run — build and execute”cargo run builds the binary (if needed) and then runs it. If nothing changed since the last build, it skips straight to running:
$ cargo run Compiling args_demo v0.1.0 (/path/to/args_demo) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.21s Running `target/debug/args_demo`No arguments given.To pass arguments to your program (rather than to Cargo), put them after a -- separator. Everything before -- is a Cargo flag; everything after goes to your binary’s std::env::args():
$ cargo run -- alice bob Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s Running `target/debug/args_demo alice bob`You passed 2 argument(s): ["alice", "bob"]This -- convention matches npm run <script> -- <args> in spirit. The --release flag goes before --, because it is a Cargo flag:
cargo run --release -- --config prod.tomlIf your project has more than one binary, Cargo cannot guess which to run and tells you so:
$ cargo runerror: `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key.available binaries: seed, toolboxPick one with --bin:
$ cargo run --bin seed Compiling toolbox v0.1.0 (/path/to/toolbox) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.14s Running `target/debug/seed`seeding database...cargo test — run every kind of test
Section titled “cargo test — run every kind of test”cargo test compiles your code in test mode and runs all #[test] functions, integration tests in tests/, and doctests (the runnable examples in your /// doc comments). No test runner to install or configure. For a library crate with three unit tests:
$ cargo test Compiling calc v0.1.0 (/path/to/calc) Finished `test` profile [unoptimized + debuginfo] target(s) in 0.16s Running unittests src/lib.rs (target/debug/deps/calc-9612d1c07b9ca2bd)
running 3 teststest tests::test_add ... oktest tests::test_multiply ... oktest tests::test_add_negative ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests calc
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sYou can run a subset by passing a substring filter — every test whose full path contains it runs:
$ cargo test add Running unittests src/lib.rs (target/debug/deps/calc-9612d1c07b9ca2bd)
running 2 teststest tests::test_add_negative ... oktest tests::test_add ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00sNotice the 1 filtered out: test_multiply did not match the add filter. To see println! output from passing tests (Cargo captures it by default), pass -- --nocapture (everything after -- goes to the test harness, not Cargo). Testing gets a whole section of its own — see Section 13: Testing.
cargo fmt — format code
Section titled “cargo fmt — format code”cargo fmt runs rustfmt over your whole crate, rewriting files in place to the canonical Rust style. It is the prettier --write equivalent, but the style is community-standard and essentially non-configurable, which ends bikeshedding. To check formatting without modifying files (for CI), use --check:
$ cargo fmt --checkDiff in /path/to/fmt_demo/src/main.rs:1: fn main() {-let name="world";+ let name = "world"; println!("Hello, {name}!"); }cargo fmt --check exits with a non-zero status (1) when reformatting is needed, which is exactly what you want in a CI gate.
cargo clippy — lint
Section titled “cargo clippy — lint”cargo clippy is Rust’s linter, the eslint equivalent, with hundreds of built-in lints that catch bugs, non-idiomatic code, and performance footguns. Given this code:
fn main() { let ready = true; if ready == true { println!("Starting up..."); }}Clippy produces a real, actionable warning:
$ cargo clippy Checking lint_demo v0.1.0 (/path/to/lint_demo)warning: equality checks against true are unnecessary --> src/main.rs:3:8 |3 | if ready == true { | ^^^^^^^^^^^^^ help: try simplifying it as shown: `ready` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison = note: `#[warn(clippy::bool_comparison)]` on by default
warning: `lint_demo` (bin "lint_demo") generated 1 warning (run `cargo clippy --fix --bin "lint_demo"` to apply 1 suggestion) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.09sIn CI you typically promote warnings to errors with -- -D warnings, which makes any lint fail the build:
$ cargo clippy -- -D warnings... = note: `-D clippy::bool-comparison` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
error: could not compile `lint_demo` (bin "lint_demo") due to 1 previous errorMany lints carry machine-applicable fixes; cargo clippy --fix rewrites your code to apply them automatically.
cargo doc — generate documentation
Section titled “cargo doc — generate documentation”cargo doc builds HTML documentation from your /// doc comments. --open launches it in your browser; --no-deps skips documenting your dependencies (faster, and usually what you want locally):
$ cargo doc --no-deps Documenting docgen v0.1.0 (/path/to/docgen) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s Generated /path/to/docgen/target/doc/docgen/index.htmlThe generated docs include cross-linked types, source links, and rendered examples — the same machinery that produces docs.rs. Crucially, the examples in your doc comments are tested by cargo test, so your documentation cannot silently rot.
cargo add — manage dependencies from the CLI
Section titled “cargo add — manage dependencies from the CLI”cargo add <crate> resolves the latest compatible version, writes it into Cargo.toml, and updates Cargo.lock. It is the npm install <pkg> equivalent and has been built into Cargo since 1.62 — you do not need to install cargo-edit first, despite what older tutorials claim.
$ cargo add serde --features derive Adding serde v1.0.228 to dependencies Features: + derive + serde_derive + std - alloc - rc - unstable Locking 7 packages to latest Rust 1.96.0 compatible versionsThe resulting Cargo.toml:
[dependencies]serde = { version = "1.0.228", features = ["derive"] }Add to [dev-dependencies] with --dev:
$ cargo add --dev criterion Adding criterion v0.8.2 to dev-dependenciesThe full story of version requirements, feature flags, and git/path dependencies lives in Dependencies and Dev Dependencies.
Discovering commands
Section titled “Discovering commands”cargo --list prints every available subcommand, including aliases (b = build, c = check, r = run, d = doc) and any third-party subcommands you have installed:
$ cargo --listInstalled Commands: add Add dependencies to a Cargo.toml manifest file b alias: build bench Execute all benchmarks of a local package build Compile a local package and all of its dependencies c alias: check check Check a local package and all of its dependencies for errors clean Remove artifacts that cargo has generated in the past clippy Checks a package to catch common mistakes and improve your Rust code. ... new Create a new cargo package at <path> ... run Run a binary or example of the local packageKey Differences
Section titled “Key Differences”| Task | Node.js / TypeScript | Rust (Cargo) |
|---|---|---|
| Scaffold new project | npm init -y + manual src/, tsconfig.json | cargo new <name> (one command) |
| Initialize in current dir | npm init | cargo init |
| Install a dependency | npm install <pkg> | cargo add <crate> |
| Install a dev dependency | npm install -D <pkg> | cargo add --dev <crate> |
| Type-check only | tsc --noEmit | cargo check |
| Build | tsc / webpack / vite build | cargo build (debug) / cargo build --release |
| Run | node dist/index.js / tsx src/index.ts | cargo run |
| Test | jest / vitest (separate install) | cargo test (built in) |
| Format | prettier --write . (separate install) | cargo fmt |
| Lint | eslint . (separate install) | cargo clippy |
| Docs | typedoc (separate install) | cargo doc |
| Pass args to program | npm start -- <args> | cargo run -- <args> |
Conventions over configuration
Section titled “Conventions over configuration”The biggest mental shift is that Cargo commands are universal. In Node.js, “test” might be jest, vitest, mocha, npm test, or npm run test:unit — it depends entirely on what each project’s package.json declares. In Rust, cargo test always means the same thing because the entry point (src/main.rs or src/lib.rs), the test attribute (#[test]), and the build profiles are part of the toolchain, not per-project config.
check vs build — a tool TypeScript doesn’t separate
Section titled “check vs build — a tool TypeScript doesn’t separate”cargo check has no everyday TypeScript equivalent that most developers use. It skips code generation entirely, so it is the right command for “does my code compile?” while you iterate. Reach for cargo build only when you actually need the artifact, and cargo run when you want to execute it. This three-way split (check / build / run) is finer-grained than the typical tsc → node two-step.
One lockfile philosophy difference
Section titled “One lockfile philosophy difference”cargo add and cargo build write Cargo.lock, analogous to package-lock.json. The convention differs from npm’s “always commit it”: you commit Cargo.lock for binaries (reproducible deployments) but conventionally omit it for libraries (so downstream users resolve their own compatible versions). See Cargo.toml for details.
Common Pitfalls
Section titled “Common Pitfalls”Pitfall 1: Forgetting the -- separator
Section titled “Pitfall 1: Forgetting the -- separator”A TypeScript developer used to node dist/index.js --port 8080 may write:
cargo run --port 8080Cargo interprets --port as one of its own flags and errors out (cargo run has no --port option). The fix is to separate your program’s arguments with --:
cargo run -- --port 8080Everything after -- is handed to your binary untouched.
Pitfall 2: Running cargo run in a library crate
Section titled “Pitfall 2: Running cargo run in a library crate”If you create a project with cargo new my_lib --lib, there is no binary to run, and cargo run fails:
$ cargo runerror: a bin target must be available for `cargo run`Libraries are consumed by other crates and tested with cargo test; they are not executed directly. If you want a runnable entry point, add a src/main.rs (or a src/bin/*.rs) so the crate also produces a binary.
Pitfall 3: Assuming cargo new runs in the current directory
Section titled “Pitfall 3: Assuming cargo new runs in the current directory”cargo new my_app creates a new subdirectory called my_app. If you have already cd’d into the folder you want to use, cargo new my_app nests ./my_app/my_app/. Use cargo init to scaffold in place:
mkdir my_app && cd my_appcargo init # initializes the current directory# cargo new my_app # would create my_app/my_appPitfall 4: Expecting cargo build to be the inner loop
Section titled “Pitfall 4: Expecting cargo build to be the inner loop”Coming from tsc, you might run cargo build constantly. It works, but it spends time on code generation and linking you do not need while merely checking for errors. cargo check is several times faster for that purpose. Save cargo build/cargo run for when you actually need to execute the result.
Pitfall 5: Thinking cargo add needs cargo-edit
Section titled “Pitfall 5: Thinking cargo add needs cargo-edit”Older blog posts and Stack Overflow answers say “first cargo install cargo-edit, then cargo add.” That has not been necessary since Cargo 1.62 (June 2022). cargo add and cargo remove ship with Cargo. (cargo-edit still provides extras like cargo upgrade, but not the basic add/remove.)
Best Practices
Section titled “Best Practices”- Use
cargo checkas your default inner loop. Switch tocargo runonly when you need to see the program execute. Pair it with an editor running rust-analyzer for instant feedback. - Gate CI on formatting and lints. Run
cargo fmt --checkandcargo clippy -- -D warningsin CI so that unformatted or lint-dirty code cannot merge. Both exit non-zero on failure, which CI systems treat as a failed step. - Build
--releaseonly when it matters. Release builds are slow to compile. Use them for production artifacts, benchmarks, and performance testing — not for routine development. - Prefer
cargo addover hand-editingCargo.tomlfor adding dependencies: it picks a current version, sorts features, and updatesCargo.lockin one step. Hand-edit only when you need something unusual. - Learn the one-letter aliases (
cargo c,cargo b,cargo r,cargo tis not built in butcargo testis short anyway) to shave keystrokes, but write the full names in scripts and docs for clarity. - Reach for
cargo new --libwhen starting reusable code, andcargo new(binary) for applications. You can always add asrc/lib.rslater to make a binary crate also expose a library.
Tip: A clean pre-commit/CI sequence for a Rust project is:
cargo fmt --check && cargo clippy -- -D warnings && cargo test. It mirrors theprettier --check && eslint && vitest runyou’d run in a TypeScript repo, but with zero tooling to install.
Real-World Example
Section titled “Real-World Example”Here is the complete lifecycle of a small library crate, slugify, from scaffolding through the full quality-gate sequence you’d run locally and in CI. Every command below produces the real output shown.
1. Scaffold a library crate:
$ cargo new slugify --lib Creating library `slugify` packagenote: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html2. Write the library (src/lib.rs):
//! Turn arbitrary titles into URL-friendly slugs.
/// Converts a title into a lowercase, hyphen-separated slug.////// # Examples////// ```/// use slugify::slugify;/// assert_eq!(slugify("Hello, World!"), "hello-world");/// ```pub fn slugify(title: &str) -> String { title .chars() .map(|c| { if c.is_alphanumeric() { c.to_ascii_lowercase() } else { ' ' } }) .collect::<String>() .split_whitespace() .collect::<Vec<_>>() .join("-")}
#[cfg(test)]mod tests { use super::*;
#[test] fn collapses_whitespace_and_punctuation() { assert_eq!(slugify(" Rust for TS devs! "), "rust-for-ts-devs"); }
#[test] fn lowercases() { assert_eq!(slugify("CamelCase"), "camelcase"); }}3. Run the quality gate (fmt, clippy, test) — the same commands you’d put in CI:
$ cargo fmt --check # exits 0: already formatted$ cargo clippy -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s$ cargo testrunning 2 teststest result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00srunning 1 testtest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sNote the two test groups: the first 2 passed is the unit tests in the tests module; the second 1 passed is the doctest from the # Examples block in the doc comment. The example in your docs is verified to be correct, for free.
4. Generate the docs:
$ cargo doc --no-deps --open # builds HTML and opens it in the browserFor a production-flavored CI configuration, this maps directly onto a GitHub Actions job:
jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: cargo fmt --check - run: cargo clippy -- -D warnings - run: cargo testThis is the same set of standard commands working unchanged, which is exactly the point: no per-project script names to invent.
Further Reading
Section titled “Further Reading”Official Documentation
Section titled “Official Documentation”- The Cargo Book — the complete reference
- Cargo Commands Index — every subcommand documented
cargo new/cargo init- Clippy lint list — searchable catalog of every lint
- rustfmt configuration — the formatter’s (rarely needed) options
Related Sections in This Guide
Section titled “Related Sections in This Guide”- Understanding Cargo — the gentle introduction in Section 01
- Hello World — your first
cargo run - Cargo.toml — the manifest, profiles, and
Cargo.lock - Dependencies — semver requirements, features, git/path deps
- Dev Dependencies —
[dev-dependencies]and[build-dependencies] - Workspaces — running Cargo commands across a monorepo
- Feature Flags — building with
--features - Publishing —
cargo publishand crates.io - Section 13: Testing — everything
cargo testcan do
Exercises
Section titled “Exercises”Exercise 1: Scaffold and run
Section titled “Exercise 1: Scaffold and run”Difficulty: Easy
Objective: Get comfortable with cargo new and the -- argument separator.
Instructions:
- Create a new binary project named
greeterwith one command. - Edit
src/main.rsso it reads command-line arguments and printsHello, <name>!for each name passed, orHello, world!if none are given. - Run it with no arguments, then run it with
cargo run -- Ada Graceand confirm both names print.
Solution
cargo new greetercd greeteruse std::env;
fn main() { let names: Vec<String> = env::args().skip(1).collect(); if names.is_empty() { println!("Hello, world!"); } else { for name in names { println!("Hello, {name}!"); } }}$ cargo run Running `target/debug/greeter`Hello, world!
$ cargo run -- Ada Grace Running `target/debug/greeter Ada Grace`Hello, Ada!Hello, Grace!env::args() yields the program name as the first element, so .skip(1) drops it. The -- separator is what makes Ada and Grace reach your program instead of being parsed as Cargo flags.
Exercise 2: init an existing directory and add a dependency
Section titled “Exercise 2: init an existing directory and add a dependency”Difficulty: Medium
Objective: Practice cargo init (vs cargo new) and cargo add.
Instructions:
- Create an empty directory
diceandcdinto it. - Turn it into a Cargo binary project in place (do not create a nested folder).
- Add the
randcrate as a dependency from the command line. - Make
mainprint a random dice roll between 1 and 6 inclusive, then run it.
Solution
mkdir dicecd dicecargo init # initializes the CURRENT directorycargo add rand # writes rand to [dependencies] and updates Cargo.lockuse rand::RngExt;
fn main() { let roll = rand::rng().random_range(1..=6); println!("You rolled a {roll}");}$ cargo run Compiling dice v0.1.0 (/path/to/dice) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.9s Running `target/debug/dice`You rolled a 4Note: This uses current rand 0.10 idioms:
rand::rng()(not the old 0.8thread_rng()) andrandom_range()via theRngExttrait (not the oldgen_range()). In rand 0.10 the range-sampling method lives onRngExt, so you importrand::RngExtrather thanrand::Rng. Usingcargo initinstead ofcargo new dicekeeps everything in the directory you already created rather than nestingdice/dice/.
Exercise 3: A full quality gate on a library
Section titled “Exercise 3: A full quality gate on a library”Difficulty: Medium
Objective: Run the same fmt / clippy / test sequence used in CI, and use the cargo test filter.
Instructions:
- Create a library crate named
mathkit. - Add two public functions,
is_even(n: i64) -> boolandfactorial(n: u64) -> u64, each with a unit test, plus one doctest example onfactorial. - Run
cargo fmt --check, thencargo clippy -- -D warnings, thencargo test. Fix anything the first two report. - Run only the factorial-related tests using a
cargo testfilter, and confirm the even-number test is reported as filtered out.
Solution
cargo new mathkit --libcd mathkit/// Returns `true` if `n` is even.pub fn is_even(n: i64) -> bool { n % 2 == 0}
/// Computes `n!` (factorial).////// # Examples////// ```/// use mathkit::factorial;/// assert_eq!(factorial(5), 120);/// ```pub fn factorial(n: u64) -> u64 { (1..=n).product()}
#[cfg(test)]mod tests { use super::*;
#[test] fn test_is_even() { assert!(is_even(4)); assert!(!is_even(7)); }
#[test] fn test_factorial() { assert_eq!(factorial(0), 1); assert_eq!(factorial(4), 24); }}Run the gate:
$ cargo fmt --check # exits 0 if formatted$ cargo clippy -- -D warnings # exits 0 if no lints$ cargo testrunning 2 teststest tests::test_is_even ... oktest tests::test_factorial ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s... Doc-tests mathkitrunning 1 testtest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sFilter to just the factorial tests:
$ cargo test factorialrunning 1 testtest tests::test_factorial ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00sThe 1 filtered out confirms test_is_even was skipped because its name does not contain factorial. The doctest on factorial runs as part of cargo test, so the example in the documentation is guaranteed correct.