cargo-stern4rust 0.1.0

Cargo subcommand that fails the build when a Rust workspace breaks a house coding rule, such as AAA test structure or one struct per file
Documentation

stern4rust

A cargo subcommand that holds a Rust workspace to its house coding rules and names every file that breaks one.

It is in the same family as cargo-crap4rust, cargo-twin4rust and cargo-iceberg4rust, and shares their character: it measures what it can state precisely, it is opinionated about what good looks like, and it fails the build rather than warning.

The rules it checks are conventions, not correctness. rustc and clippy already own correctness. These are the things a reviewer would otherwise have to say by hand, every time, forever — and the ones that quietly stop being true across a codebase the moment nobody is checking.

Status: scaffold. The packaging, CLI and test harness are in place and the crate publishes. No rule is implemented yet, so a run reports that and exits 0.

Install

cargo install cargo-stern4rust

Use

cargo stern4rust
cargo stern4rust --package my-crate
cargo stern4rust --manifest-path path/to/Cargo.toml --package a --package b
flag meaning
--manifest-path <PATH> workspace manifest to analyse; defaults to the one in the current directory
--package <NAME> restrict to these packages; repeatable. Omit to take the manifest's own package

The rules

Each rule is independent, names itself in the report, and can be pointed at a whole workspace or one package. The set is open — these are the first two.

AAA structure in tests

A test reads as three movements: set the world up, do the one thing, check what happened. When the marker comments are missing, the boundary between them stops being visible, and a test that quietly asserts in its arrange section or acts twice looks exactly like one that does not.

#[test]
fn poll_with_an_empty_queue_returns_nothing() {
    // Arrange
    let queue = Queue::new();

    // Act
    let polled = queue.poll();

    // Assert
    assert!(polled.is_none());
}

Two contractions are part of the rule rather than exceptions to it:

  • // Arrange & Act when there is nothing to set up separately
  • // Act & Assert when the call and the check are one expression

At most one struct with an impl block per file

A file holds one behaviour-bearing type. Plain data declarations sitting beside it are fine; a second type that carries methods is a second subject, and a file with two subjects has no name that describes it.

This is what keeps a mirrored test file meaningful — src/foo.rs answering to tests/foo_tests.rs only says something when foo.rs has one subject to test.

Output

Clean:

stern4rust report

All rules are satisfied.

Broken:

stern4rust report

file                          line  rule              offence
----------------------------  ----  ----------------  ----------------------------------
src/peer_registry.rs            41  one-struct-file   second struct with an impl block
tests/peer_registry_tests.rs    18  aaa-structure     no Act section
tests/peer_registry_tests.rs    57  aaa-structure     Assert before Act

summary: files_scanned=42 offences=3 rules_broken=2

Exit codes

The family shares one contract, so a wrapper script can tell the two apart:

code meaning
0 every rule satisfied
1 the tool could not run — bad manifest, unknown package, unreadable source
2 at least one rule was broken

Only 2 is a finding. A script that treats every non-zero code the same cannot distinguish "your code has a problem" from "I could not look at your code", which is the difference between a real failure and a broken CI step.

Licence

MIT — see LICENSE.