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
176,546 downloads per month
Used in 581 crates
(20 directly)
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.