From 8224904172134fb28cc25cd71f44eb37c8b96791 Mon Sep 17 00:00:00 2001 From: HackingGate Date: Fri, 2 Oct 2026 01:05:23 +0900 Subject: [PATCH] Every assert of an empty collection prints it on failure, as Rust 1.99's clippy::assert_is_empty asks Clippy 1.99 adds assert_is_empty to pedantic, and CI's stable toolchain took it, so every job that compiles the tests refused 45 `assert!(x.is_empty())` calls. Each now carries a message that prints the collection, which is what the lint wants and what a failing run needs; the one asserting non-emptiness says which list was empty. --- src/anchors.rs | 6 ++++- src/audit.rs | 2 +- src/config.rs | 20 ++++++++++++--- src/engine.rs | 20 ++++++++++++--- src/evidence.rs | 22 +++++++++++----- src/evidence/diff.rs | 6 ++++- src/evidence/git.rs | 6 ++++- src/git.rs | 4 ++- src/guard/message.rs | 36 +++++++++++++++++++++----- src/guard/names.rs | 4 ++- src/guard/unicode.rs | 50 +++++++++++++++++++++++++++++------- src/install.rs | 6 ++++- src/pins.rs | 2 +- src/prose.rs | 6 ++++- src/selection.rs | 6 ++++- src/shim.rs | 4 +-- src/sources.rs | 12 +++++++-- tests/structural_evidence.rs | 6 ++++- 18 files changed, 173 insertions(+), 45 deletions(-) diff --git a/src/anchors.rs b/src/anchors.rs index c51eef2..2d59329 100644 --- a/src/anchors.rs +++ b/src/anchors.rs @@ -428,7 +428,11 @@ mod tests { #[test] fn a_file_with_no_marker_parses_to_nothing() { - assert!(parse("ordinary prose about anchors and facts\n").is_empty()); + assert!( + parse("ordinary prose about anchors and facts\n").is_empty(), + "{:?}", + parse("ordinary prose about anchors and facts\n") + ); } #[test] diff --git a/src/audit.rs b/src/audit.rs index aa77eb8..9ba293e 100644 --- a/src/audit.rs +++ b/src/audit.rs @@ -794,7 +794,7 @@ mod tests { /// came to have an unreachable clean arm. #[test] fn the_standing_caveats_are_not_surfaces_this_run_failed_to_read() { - assert!(!STANDING_CAVEATS.is_empty()); + assert!(!STANDING_CAVEATS.is_empty(), "STANDING_CAVEATS is empty"); for caveat in STANDING_CAVEATS { assert!( caveat.contains("cannot"), diff --git a/src/config.rs b/src/config.rs index f50724e..9a01b93 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3742,10 +3742,22 @@ mod tests { // changes what a guard does in every repository that never wrote the // field, which is most of them. let rule = Rule::synthetic("x", Check::empty(CheckKind::Builtin)); - assert!(rule.public_repos().is_empty()); - assert!(rule.allowed_owners().is_empty()); - assert!(rule.allowed_repos().is_empty()); - assert!(rule.private_owners().is_empty()); + assert!(rule.public_repos().is_empty(), "{:?}", rule.public_repos()); + assert!( + rule.allowed_owners().is_empty(), + "{:?}", + rule.allowed_owners() + ); + assert!( + rule.allowed_repos().is_empty(), + "{:?}", + rule.allowed_repos() + ); + assert!( + rule.private_owners().is_empty(), + "{:?}", + rule.private_owners() + ); assert!( !rule.refuse_unknown(), "an unknown name is not private by default" diff --git a/src/engine.rs b/src/engine.rs index cff7e1d..62b9c60 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -234,7 +234,9 @@ mod tests { assert!( search_text("literally $HOME/secrets here\n", &plain, "t") .unwrap() - .is_empty() + .is_empty(), + "{:?}", + search_text("literally $HOME/secrets here\n", &plain, "t").unwrap() ); } @@ -247,14 +249,22 @@ mod tests { ..Default::default() }; let query = Query::from_files("LICENSE", &files); - assert!(search_text("LICENSEE\n", &query, "t").unwrap().is_empty()); + assert!( + search_text("LICENSEE\n", &query, "t").unwrap().is_empty(), + "{:?}", + search_text("LICENSEE\n", &query, "t").unwrap() + ); assert_eq!(search_text("LICENSE\n", &query, "t").unwrap().len(), 1); } #[test] fn word_matching_keeps_a_short_needle_out_of_a_longer_word() { let query = Query::literal("arc", true); - assert!(search_text("search\n", &query, "t").unwrap().is_empty()); + assert!( + search_text("search\n", &query, "t").unwrap().is_empty(), + "{:?}", + search_text("search\n", &query, "t").unwrap() + ); assert_eq!(search_text("arc\n", &query, "t").unwrap().len(), 1); } @@ -280,7 +290,9 @@ mod tests { assert!( search_text(text, &Query::regex(pattern, false), "t") .unwrap() - .is_empty() + .is_empty(), + "{:?}", + search_text(text, &Query::regex(pattern, false), "t").unwrap() ); } diff --git a/src/evidence.rs b/src/evidence.rs index 731dcb6..005dd0d 100644 --- a/src/evidence.rs +++ b/src/evidence.rs @@ -455,8 +455,8 @@ mod tests { }, ); let collected = body(&[&unread]); - assert!(collected.found.is_empty()); - assert!(collected.read.is_empty()); + assert!(collected.found.is_empty(), "{:?}", collected.found); + assert!(collected.read.is_empty(), "{:?}", collected.read); assert_eq!(collected.unavailable.len(), 1); assert_eq!(collected.unavailable[0].reason, "a.rs:3 did not parse"); assert_eq!( @@ -503,7 +503,11 @@ mod tests { unavailable: Vec::new(), read: vec![PARSER, PATTERN], }; - assert!(collected.contradictions().is_empty()); + assert!( + collected.contradictions().is_empty(), + "{:?}", + collected.contradictions() + ); } #[test] @@ -565,7 +569,7 @@ mod tests { ]); let removed = collected.established(Kind::FunctionRemoved); assert!(!removed.clean()); - assert!(removed.found().is_empty()); + assert!(removed.found().is_empty(), "{:?}", removed.found()); assert_eq!(removed.unread().len(), 1); assert!(matches!(removed, Established::HeuristicOnly { .. })); } @@ -595,7 +599,7 @@ mod tests { let collected = body(&[&Scripted(PATTERN, Observation::Found(Vec::new()))]); let removed = collected.established(Kind::FunctionRemoved); assert!(removed.clean()); - assert!(removed.unread().is_empty()); + assert!(removed.unread().is_empty(), "{:?}", removed.unread()); } #[test] @@ -609,7 +613,7 @@ mod tests { )]); let removed = collected.established(Kind::FunctionRemoved); assert_eq!(removed, Established::Unavailable(Vec::new())); - assert!(removed.found().is_empty()); + assert!(removed.found().is_empty(), "{:?}", removed.found()); assert!(!removed.clean()); // Still in the body for a reader; just in no verdict. assert_eq!(collected.found, vec![inferred]); @@ -627,7 +631,11 @@ mod tests { collected.established(Kind::FunctionRemoved), Established::Proven(vec![&proven]) ); - assert!(collected.contradictions().is_empty()); + assert!( + collected.contradictions().is_empty(), + "{:?}", + collected.contradictions() + ); let assertion = fact(ORACLE, Kind::FunctionRemoved, "a.rs::stop"); let clean = body(&[ diff --git a/src/evidence/diff.rs b/src/evidence/diff.rs index 0f186e0..2113334 100644 --- a/src/evidence/diff.rs +++ b/src/evidence/diff.rs @@ -259,7 +259,11 @@ mod tests { // `--- a/fn_x.rs` opens with the removal marker and is not a line // of the file; only a hunk's lines are. let diff = "diff --git a/lib.rs b/lib.rs\n--- a/lib.rs\n+++ b/lib.rs\n"; - assert!(compare("lib.rs", rust(), diff).is_empty()); + assert!( + compare("lib.rs", rust(), diff).is_empty(), + "{:?}", + compare("lib.rs", rust(), diff) + ); } #[test] diff --git a/src/evidence/git.rs b/src/evidence/git.rs index d7dfa41..977aed4 100644 --- a/src/evidence/git.rs +++ b/src/evidence/git.rs @@ -271,7 +271,11 @@ mod tests { assert_eq!(marked.len(), 2); assert_eq!(marked[0].line, "Co-Authored-By: A "); assert_eq!(marked[1].line, "Generated with Claude Code"); - assert!(agent_markers_in("Plain\n").is_empty()); + assert!( + agent_markers_in("Plain\n").is_empty(), + "{:?}", + agent_markers_in("Plain\n") + ); } #[test] diff --git a/src/git.rs b/src/git.rs index 1da781b..ed13471 100644 --- a/src/git.rs +++ b/src/git.rs @@ -592,7 +592,9 @@ mod tests { assert!( each_blob(&std::env::temp_dir(), &[], |_, _| ()) .unwrap() - .is_empty() + .is_empty(), + "{:?}", + each_blob(&std::env::temp_dir(), &[], |_, _| ()).unwrap() ); } diff --git a/src/guard/message.rs b/src/guard/message.rs index 36c94cd..b5f24e9 100644 --- a/src/guard/message.rs +++ b/src/guard/message.rs @@ -467,7 +467,11 @@ mod tests { fn a_fullwidth_form_needs_an_east_asian_script_beside_it() { // `Script_Extensions=Common`, so the intersection cannot decide these // and the range decides them instead. - assert!(findings(&format!("{JAPANESE}\u{FF08}{KANA}\u{FF09}\u{FF01}\n")).is_empty()); + assert!( + findings(&format!("{JAPANESE}\u{FF08}{KANA}\u{FF09}\u{FF01}\n")).is_empty(), + "{:?}", + findings(&format!("{JAPANESE}\u{FF08}{KANA}\u{FF09}\u{FF01}\n")) + ); assert_eq!(findings("Fix the parser\u{FF01}\n").len(), 1); assert_eq!(findings("Fix the parser\u{FF08}1\u{FF09}\n").len(), 2); } @@ -501,9 +505,21 @@ mod tests { #[test] fn punctuation_is_admitted_only_by_the_script_that_owns_it() { // Greek, Arabic and Hebrew marks beside their own letters. - assert!(findings(&format!("{GREEK}\u{0384}\n")).is_empty()); - assert!(findings(&format!("{ARABIC}\u{060C} {ARABIC}\n")).is_empty()); - assert!(findings(&format!("{HEBREW}\u{05C3}\n")).is_empty()); + assert!( + findings(&format!("{GREEK}\u{0384}\n")).is_empty(), + "{:?}", + findings(&format!("{GREEK}\u{0384}\n")) + ); + assert!( + findings(&format!("{ARABIC}\u{060C} {ARABIC}\n")).is_empty(), + "{:?}", + findings(&format!("{ARABIC}\u{060C} {ARABIC}\n")) + ); + assert!( + findings(&format!("{HEBREW}\u{05C3}\n")).is_empty(), + "{:?}", + findings(&format!("{HEBREW}\u{05C3}\n")) + ); // And the same marks with only Latin letters to vouch for them. assert_eq!(findings("Fix the parser\u{0384}\n").len(), 1); assert_eq!(findings("Fix the parser\u{060C}\n").len(), 1); @@ -519,12 +535,20 @@ mod tests { // are, so a Cyrillic homoglyph inside a Latin word is not what this // guard refuses. What it refuses is the mark that arrives with no // letters of its own script, and a Cyrillic word vouches for none. - assert!(findings("Fix the c\u{0430}che\n").is_empty()); + assert!( + findings("Fix the c\u{0430}che\n").is_empty(), + "{:?}", + findings("Fix the c\u{0430}che\n") + ); assert_eq!(findings(&format!("{CYRILLIC}\u{3002}\n")).len(), 1); } #[test] fn ascii_prose_and_a_tab_are_untouched() { - assert!(findings("Fix the parser\n\nIt read a\ttab.\n").is_empty()); + assert!( + findings("Fix the parser\n\nIt read a\ttab.\n").is_empty(), + "{:?}", + findings("Fix the parser\n\nIt read a\ttab.\n") + ); } } diff --git a/src/guard/names.rs b/src/guard/names.rs index 64406ad..fdb606d 100644 --- a/src/guard/names.rs +++ b/src/guard/names.rs @@ -1625,7 +1625,9 @@ mod tests { assert!( declared_owners(&permitted_dir, &permitted, permitted_rule) .unwrap() - .is_empty() + .is_empty(), + "{:?}", + declared_owners(&permitted_dir, &permitted, permitted_rule).unwrap() ); } diff --git a/src/guard/unicode.rs b/src/guard/unicode.rs index 3fe5d4b..d1454fc 100644 --- a/src/guard/unicode.rs +++ b/src/guard/unicode.rs @@ -424,12 +424,20 @@ mod tests { #[test] fn ordinary_text_and_real_emoji_pass() { - assert!(findings("hello\tworld\n日本語 ☕\n").is_empty()); + assert!( + findings("hello\tworld\n日本語 ☕\n").is_empty(), + "{:?}", + findings("hello\tworld\n日本語 ☕\n") + ); } #[test] fn a_variation_selector_after_an_emoji_is_earned() { - assert!(findings("\u{26A0}\u{FE0F}\n").is_empty()); + assert!( + findings("\u{26A0}\u{FE0F}\n").is_empty(), + "{:?}", + findings("\u{26A0}\u{FE0F}\n") + ); } #[test] @@ -441,12 +449,20 @@ mod tests { #[test] fn a_keycap_sequence_is_the_one_ascii_exception() { - assert!(findings("1\u{FE0F}\u{20E3}\n").is_empty()); + assert!( + findings("1\u{FE0F}\u{20E3}\n").is_empty(), + "{:?}", + findings("1\u{FE0F}\u{20E3}\n") + ); } #[test] fn an_ideographic_selector_needs_an_ideograph() { - assert!(findings("\u{845B}\u{E0100}\n").is_empty()); + assert!( + findings("\u{845B}\u{E0100}\n").is_empty(), + "{:?}", + findings("\u{845B}\u{E0100}\n") + ); assert_eq!(findings("7\u{E0100}\n").len(), 1); } @@ -463,7 +479,11 @@ mod tests { #[test] fn an_allowance_may_be_scoped_to_a_path() { let allowances = vec![parse_allowance("U+00A0:docs/**").unwrap()]; - assert!(scan("a\u{00A0}b\n", "docs/page.md", &allowances).is_empty()); + assert!( + scan("a\u{00A0}b\n", "docs/page.md", &allowances).is_empty(), + "{:?}", + scan("a\u{00A0}b\n", "docs/page.md", &allowances) + ); assert_eq!(scan("a\u{00A0}b\n", "src/main.rs", &allowances).len(), 1); } @@ -471,7 +491,11 @@ mod tests { fn an_allowance_grants_and_never_revokes() { // Adding an entry cannot tighten the guard on anybody else's file. let allowances = vec![parse_allowance("U+00A0").unwrap()]; - assert!(scan("a\u{00A0}b\n", "any.txt", &allowances).is_empty()); + assert!( + scan("a\u{00A0}b\n", "any.txt", &allowances).is_empty(), + "{:?}", + scan("a\u{00A0}b\n", "any.txt", &allowances) + ); assert_eq!(scan("a\u{200B}b\n", "any.txt", &allowances).len(), 1); } @@ -491,14 +515,18 @@ mod tests { assert_eq!(found.len(), 1, "{found:?}"); assert!(found[0].contains("U+200B"), "{found:?}"); assert!(found[0].contains("FILE NAME"), "{found:?}"); - assert!(scan_name("docs/readme.md", &[]).is_empty()); + assert!( + scan_name("docs/readme.md", &[]).is_empty(), + "{:?}", + scan_name("docs/readme.md", &[]) + ); } #[test] fn a_tab_is_legal_in_a_file_and_never_in_a_path() { // The two characters the content rule exempts, which is why the path // cannot simply be handed to `scan`. - assert!(findings("a\tb\n").is_empty()); + assert!(findings("a\tb\n").is_empty(), "{:?}", findings("a\tb\n")); assert_eq!(scan_name("a\tb", &[]).len(), 1); assert_eq!(scan_name("a\nb", &[]).len(), 1); } @@ -506,7 +534,11 @@ mod tests { #[test] fn an_allowance_scoped_to_a_path_reaches_that_paths_name() { let allowances = vec![parse_allowance("U+00A0:docs/**").unwrap()]; - assert!(scan_name("docs/a\u{00A0}b.md", &allowances).is_empty()); + assert!( + scan_name("docs/a\u{00A0}b.md", &allowances).is_empty(), + "{:?}", + scan_name("docs/a\u{00A0}b.md", &allowances) + ); assert_eq!(scan_name("src/a\u{00A0}b.rs", &allowances).len(), 1); } diff --git a/src/install.rs b/src/install.rs index 48dba05..c8d86bf 100644 --- a/src/install.rs +++ b/src/install.rs @@ -584,7 +584,11 @@ mod tests { Placed::Occupied(_) )); // And neither is listed as one of ours, so neither would be removed. - assert!(links(&dir).unwrap().is_empty()); + assert!( + links(&dir).unwrap().is_empty(), + "{:?}", + links(&dir).unwrap() + ); assert_eq!(std::fs::read(dir.join("git")).unwrap(), b"the real git"); } diff --git a/src/pins.rs b/src/pins.rs index ef90795..e063fc1 100644 --- a/src/pins.rs +++ b/src/pins.rs @@ -1085,7 +1085,7 @@ mod tests { "repos:\n - repo: local\n hooks:\n - id: x\n", ); let read = read_pins(&dir).unwrap(); - assert!(read.pins.is_empty()); + assert!(read.pins.is_empty(), "{:?}", read.pins); assert_eq!(read.configs, 1); assert!( read.notes diff --git a/src/prose.rs b/src/prose.rs index bf64289..86da0c5 100644 --- a/src/prose.rs +++ b/src/prose.rs @@ -451,7 +451,11 @@ mod tests { #[test] fn a_file_of_no_kind_contributes_nothing_rather_than_a_finding() { assert!(!reads("capture.png")); - assert!(of("capture.png", "arguably\n").is_empty()); + assert!( + of("capture.png", "arguably\n").is_empty(), + "{:?}", + of("capture.png", "arguably\n") + ); } #[test] diff --git a/src/selection.rs b/src/selection.rs index ad62d27..f3aab1f 100644 --- a/src/selection.rs +++ b/src/selection.rs @@ -1363,7 +1363,11 @@ mod tests { // Not a repository, so `check-attr` exits non-zero inside it. std::fs::create_dir_all(root.join("sub")).unwrap(); pinned_content.ask_not_text(&root, "sub", &["a.txt".to_owned()]); - assert!(pinned_content.not_text.is_empty()); + assert!( + pinned_content.not_text.is_empty(), + "{:?}", + pinned_content.not_text + ); assert_eq!( pinned_content.unmeasured.len(), 1, diff --git a/src/shim.rs b/src/shim.rs index ff72bea..8653138 100644 --- a/src/shim.rs +++ b/src/shim.rs @@ -3729,7 +3729,7 @@ mod tests { let collected = gh() .collect(Path::new("."), &argv("pr create --fill")) .unwrap(); - assert!(collected.subjects.is_empty()); + assert!(collected.subjects.is_empty(), "{:?}", collected.subjects); assert!(collected.body_given); } @@ -4115,7 +4115,7 @@ mod tests { // A dry run publishes nothing, and refusing one would stop the very // command somebody runs to find out what they are about to publish. let dry = npm().collect(&dir, &argv("publish --dry-run")).unwrap(); - assert!(dry.subjects.is_empty()); + assert!(dry.subjects.is_empty(), "{:?}", dry.subjects); } #[test] diff --git a/src/sources.rs b/src/sources.rs index 832079d..7f8cd6a 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -560,12 +560,20 @@ mod tests { // "pi" is two characters, which collides with far too much ordinary // text even under whole-word matching; "12" and "01" are digits. assert!(!hostname_segments("a-12-pi").contains(&"pi".to_owned())); - assert!(hostname_segments("node-01").is_empty()); + assert!( + hostname_segments("node-01").is_empty(), + "{:?}", + hostname_segments("node-01") + ); } #[test] fn the_whole_hostname_is_not_repeated_as_a_segment() { - assert!(hostname_segments("solo").is_empty()); + assert!( + hostname_segments("solo").is_empty(), + "{:?}", + hostname_segments("solo") + ); } #[test] diff --git a/tests/structural_evidence.rs b/tests/structural_evidence.rs index 119ff83..592e225 100644 --- a/tests/structural_evidence.rs +++ b/tests/structural_evidence.rs @@ -160,5 +160,9 @@ fn the_reader_can_tell_a_policy_that_names_a_provider_from_one_that_does_not() { } "; assert_eq!(unparsed(silent), None, "the fixture is Rust"); - assert!(offending_words(silent, &forbidden).is_empty()); + assert!( + offending_words(silent, &forbidden).is_empty(), + "{:?}", + offending_words(silent, &forbidden) + ); }