7 releases (stable)

2.2.0 Oct 28, 2025
2.1.0 Aug 31, 2025
2.0.1 Jul 19, 2025
2.0.0 Jun 20, 2024
1.0.0 May 29, 2020

#43 in Testing

Download history 21208/week @ 2025-12-25 25128/week @ 2026-01-01 33449/week @ 2026-01-08 32367/week @ 2026-01-15 34137/week @ 2026-01-22 32294/week @ 2026-01-29 40155/week @ 2026-02-05 36131/week @ 2026-02-12 38205/week @ 2026-02-19 42181/week @ 2026-02-26 44715/week @ 2026-03-05 34850/week @ 2026-03-12 30630/week @ 2026-03-19 43920/week @ 2026-03-26 40304/week @ 2026-04-02 54952/week @ 2026-04-09

176,546 downloads per month
Used in 581 crates (20 directly)

MIT/Apache

13KB
176 lines

cov-mark

Verify that your tests exercise the conditions you think they are exercising

fn safe_divide(dividend: u32, divisor: u32) -> u32 {
    if divisor == 0 {
        cov_mark::hit!(save_divide_zero);
        return 0;
    }
    dividend / divisor
}

#[test]
fn test_safe_divide_by_zero() {
    cov_mark::check!(save_divide_zero);
    assert_eq!(safe_divide(92, 0), 0);
}

See the docs for details


lib.rs:

cov-mark

This library at its core provides two macros, hit! and check!, which can be used to verify that a certain test exercises a certain code path.

Here's a short example:

fn parse_date(s: &str) -> Option<(u32, u32, u32)> {
    if 10 != s.len() {
        // By using `cov_mark::hit!`
        // we signal which test exercises this code.
        cov_mark::hit!(short_date);
        return None;
    }

    if "-" != &s[4..5] || "-" != &s[7..8] {
        cov_mark::hit!(bad_dashes);
        return None;
    }
    // ...
}

#[test]
fn test_parse_date() {
    {
        // `cov_mark::check!` creates a guard object
        // that verifies that by the end of the scope we've
        // executed the corresponding `cov_mark::hit`.
        cov_mark::check!(short_date);
        assert!(parse_date("92").is_none());
    }

//  This will fail. Although the test looks like
//  it exercises the second condition, it does not.
//  The call to `check!` call catches this bug in the test.
//  {
//      cov_mark::check!(bad_dashes);
//      assert!(parse_date("27.2.2013").is_none());
//  }

    {
        cov_mark::check!(bad_dashes);
        assert!(parse_date("27.02.2013").is_none());
    }
}

Here's why coverage marks are useful:

  • Verifying that something doesn't happen for the right reason.
  • Finding the test that exercises the code (grep for check!(mark_name)).
  • Finding the code that the test is supposed to check (grep for hit!(mark_name)).
  • Making sure that code and tests don't diverge during refactorings.
  • (If used pervasively) Verifying that each branch has a corresponding test.

Limitations

  • Names of marks must be globally unique.

Implementation Details

Each coverage mark is an AtomicUsize counter. hit! increments this counter, check! returns a guard object which checks that the mark was incremented. Each counter is stored as a thread-local, allowing for accurate per-thread counting.

Porting existing tests to cov-mark

When incrementally outfitting a set of tests with markers, survey may be useful.

No runtime deps

Features