Measure test modules in coverage, excluding only failure lines
Excluding whole #[cfg(test)] modules was overly broad: coverage is
also what proves the tests themselves run. Test code is measured
again, with two line patterns excluded that a passing suite can
never execute — panic! lines (test-failure diagnostics; the clippy
panic lint keeps panic! out of library code) and a lone ')?;'
closing a multi-line fallible call, whose only LLVM region is the
never-taken error branch. The remaining once-uncovered test lines
now genuinely run: predicate matches with dead '_ => false' arms
became matches! one-liners, the LCS window destructure became a
let-else, and the trees_with recursion base case is asserted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01565B66CMh3HTjm3124SLpB
diff --git a/bin/coverage b/bin/coverage
index fd5e027..0955b3d 100755
--- a/bin/coverage
+++ b/bin/coverage
@@ -5,10 +5,14 @@
# normal build artifacts never mix — mixing causes phantom uncovered
# lines. Override the gate with COVERAGE_THRESHOLD (defaults to 100).
#
-# `#[cfg(test)]` modules are excluded from measurement (they sit at
-# the tail of each file, so the unterminated excl-start runs to EOF):
-# their panic! arms and `?` branches never run in a passing suite and
-# would force a lowered gate for lines that are not library code.
+# Test modules are measured too — that is what proves the tests
+# themselves run. Two line patterns are excluded because a passing
+# suite can never execute them: `panic!` lines (test-failure
+# diagnostics; the clippy panic lint keeps panic! out of library
+# code), and a lone `)?;` closing a multi-line fallible call (LLVM
+# attributes only the `?` error-branch region to that line, so it
+# reads uncovered exactly when the call never fails — the same
+# region on a single-line call is invisible to line coverage).
#
# Scaffolded into a project as bin/coverage; the `coverage` justfile
# recipe runs it. See the rust skill's coverage.md and scaffolding.md.
@@ -37,8 +41,8 @@ main() {
--ignore-not-existing \
--keep-only 'src/**' \
--ignore 'src/bin/**' \
- --excl-line 'cov-excl-line|unreachable!' \
- --excl-start 'cov-excl-start|#\[cfg\(test\)\]' \
+ --excl-line 'cov-excl-line|unreachable!|panic!|^\s*\)\?;$' \
+ --excl-start 'cov-excl-start' \
--excl-stop 'cov-excl-stop')
# Per-file breakdown: walk the covdir tree, printing leaf files only.
diff --git a/src/check.rs b/src/check.rs
index 1fb5432..6c310fa 100644
--- a/src/check.rs
+++ b/src/check.rs
@@ -287,9 +287,9 @@ mod tests {
);
// The 9 itself is among the witnesses.
let m = parse_json("[1, 9]")?;
- let witnesses_nine = report.violations.iter().any(|v| match v {
- Violation::ExtraInsertion { span, .. } => m.source_slice(span.clone()) == Some("9"),
- _ => false,
+ let witnesses_nine = report.violations.iter().any(|v| {
+ matches!(v, Violation::ExtraInsertion { span, .. }
+ if m.source_slice(span.clone()) == Some("9"))
});
assert!(witnesses_nine);
Ok(())
@@ -381,9 +381,9 @@ mod tests {
)));
// The witness is A's new label.
let a = parse_json("[2]")?;
- assert!(report.violations.iter().any(|v| match v {
- Violation::MissedRelabel { span, .. } => a.source_slice(span.clone()) == Some("2"),
- _ => false,
+ assert!(report.violations.iter().any(|v| {
+ matches!(v, Violation::MissedRelabel { span, .. }
+ if a.source_slice(span.clone()) == Some("2"))
}));
// The merge that lands the rename passes.
let report = check_json("[1]", "[2]", "[1]", "[2]")?;
@@ -434,9 +434,9 @@ mod tests {
let report = check_json("[1]", "[1]", "[1]", "[9]")?;
assert!(!report.violations.is_empty());
let m = parse_json("[9]")?;
- assert!(report.violations.iter().any(|v| match v {
- Violation::ExtraRelabel { span, .. } => m.source_slice(span.clone()) == Some("9"),
- _ => false,
+ assert!(report.violations.iter().any(|v| {
+ matches!(v, Violation::ExtraRelabel { span, .. }
+ if m.source_slice(span.clone()) == Some("9"))
}));
Ok(())
}
@@ -560,15 +560,10 @@ mod tests {
r#"{"a": 1, "b": 2, "d": 4}"#,
)?;
assert!(!report.violations.is_empty());
- assert!(report.violations.iter().any(|v| match v {
- Violation::ExtraInsertion { span, .. } => {
- let m = parse_json(r#"{"a": 1, "b": 2, "d": 4}"#);
- m.is_ok_and(|m| {
- m.source_slice(span.clone())
- .is_some_and(|s| s.contains("4"))
- })
- }
- _ => false,
+ let m = parse_json(r#"{"a": 1, "b": 2, "d": 4}"#)?;
+ assert!(report.violations.iter().any(|v| {
+ matches!(v, Violation::ExtraInsertion { span, .. }
+ if m.source_slice(span.clone()).is_some_and(|s| s.contains("4")))
}));
Ok(())
}
@@ -579,12 +574,10 @@ mod tests {
// element (and its comma) both branches kept flags the comma
// too — the exemption must not reach it.
let report = check_json("[1, 2]", "[1, 2]", "[1, 2]", "[1]")?;
- let flags_comma = report.violations.iter().any(|v| match v {
- Violation::ExtraDeletion { span, .. } => {
- let o = parse_json("[1, 2]");
- o.is_ok_and(|o| o.source_slice(span.clone()) == Some(","))
- }
- _ => false,
+ let o = parse_json("[1, 2]")?;
+ let flags_comma = report.violations.iter().any(|v| {
+ matches!(v, Violation::ExtraDeletion { span, .. }
+ if o.source_slice(span.clone()) == Some(","))
});
assert!(flags_comma, "{:?}", report.violations);
Ok(())
diff --git a/src/diff.rs b/src/diff.rs
index 1ee5f91..a91a76b 100644
--- a/src/diff.rs
+++ b/src/diff.rs
@@ -1141,9 +1141,9 @@ mod tests {
let m = diff(&o, &a);
let script = edits(&o, &a, &m);
assert_eq!(script.len(), 1);
- let relabels_comment = script.iter().any(|e| match e {
- Edit::Relabel(s, d) => o.label(*s) == Some("// old") && a.label(*d) == Some("// new"),
- _ => false,
+ let relabels_comment = script.iter().any(|e| {
+ matches!(e, Edit::Relabel(s, d)
+ if o.label(*s) == Some("// old") && a.label(*d) == Some("// new"))
});
assert!(relabels_comment, "{script:?}");
Ok(())
@@ -1169,10 +1169,9 @@ mod tests {
// The number 2 and its separating comma arrive as inserts;
// nothing is deleted or relabeled.
assert!(script.iter().all(|e| matches!(e, Edit::Insert(_))));
- let inserted_number = script.iter().any(|e| match e {
- Edit::Insert(n) => a.label(*n) == Some("2"),
- _ => false,
- });
+ let inserted_number = script
+ .iter()
+ .any(|e| matches!(e, Edit::Insert(n) if a.label(*n) == Some("2")));
assert!(inserted_number);
let reversed = edits(&a, &o, &diff(&a, &o));
@@ -1316,9 +1315,10 @@ mod tests {
assert_eq!(xs.get(*i), ys.get(*j), "LCS({xs:?}, {ys:?})");
}
for window in pairs.windows(2) {
- if let [(i1, j1), (i2, j2)] = window {
- assert!(i1 < i2 && j1 < j2, "LCS({xs:?}, {ys:?}) crosses: {pairs:?}");
- }
+ let [(i1, j1), (i2, j2)] = window else {
+ unreachable!("windows(2) yields pairs");
+ };
+ assert!(i1 < i2 && j1 < j2, "LCS({xs:?}, {ys:?}) crosses: {pairs:?}");
}
}
}
diff --git a/src/merge.rs b/src/merge.rs
index 6e79cb4..767ba4b 100644
--- a/src/merge.rs
+++ b/src/merge.rs
@@ -553,9 +553,7 @@ mod tests {
MergeOutcome::Merged(m) => {
assert_eq!(m.shape(&o, &a, &b), Shape::of(&expected));
}
- MergeOutcome::Conflicts(conflicts) => {
- panic!("expected a clean merge, got conflicts: {conflicts:?}");
- }
+ MergeOutcome::Conflicts(conflicts) => panic!("unexpected conflicts: {conflicts:?}"),
}
let report = check::check(&o, &a, &b, &expected);
assert!(report.is_correct(), "{:?}", report.violations);
@@ -675,9 +673,7 @@ mod tests {
let a = parse(a, lang)?;
let b = parse(b, lang)?;
match merge(&o, &a, &b)? {
- MergeOutcome::Merged(m) => {
- panic!("expected conflicts, got a merge: {:?}", m.shape(&o, &a, &b));
- }
+ MergeOutcome::Merged(m) => panic!("unexpected merge: {:?}", m.shape(&o, &a, &b)),
MergeOutcome::Conflicts(conflicts) => {
assert!(
conflicts.iter().any(|c| c.rule == rule),
diff --git a/src/synth.rs b/src/synth.rs
index c68b1c2..30160ee 100644
--- a/src/synth.rs
+++ b/src/synth.rs
@@ -205,9 +205,7 @@ mod tests {
let b = parse(b, lang)?;
match merge(&o, &a, &b)? {
MergeOutcome::Merged(m) => Ok(synthesize(&m, &o, &a, &b)),
- MergeOutcome::Conflicts(conflicts) => {
- panic!("expected a clean merge, got conflicts: {conflicts:?}");
- }
+ MergeOutcome::Conflicts(conflicts) => panic!("unexpected conflicts: {conflicts:?}"),
}
}
diff --git a/src/zs.rs b/src/zs.rs
index 37b4dfe..5f525e5 100644
--- a/src/zs.rs
+++ b/src/zs.rs
@@ -316,6 +316,7 @@ mod tests {
// must be a bijection. Kills backtrack mutants that hand-picked
// cases let through.
let labels = [0u8, 1u8];
+ assert!(trees_with(0, &labels).is_empty());
let mut all: Vec<(ZsTree<(usize, u8)>, usize)> = Vec::new();
for nodes in 1..=3usize {
for tree in trees_with(nodes, &labels) {