diff --git a/crates/cargo-test-support/src/compare.rs b/crates/cargo-test-support/src/compare.rs index 848468cf97b..d1c06090df0 100644 --- a/crates/cargo-test-support/src/compare.rs +++ b/crates/cargo-test-support/src/compare.rs @@ -331,27 +331,6 @@ static E2E_LITERAL_REDACTIONS: &[(&str, &str)] = &[ ("[OPENING]", " Opening"), ]; -/// Normalizes the output so that it can be compared against the expected value. -fn normalize_actual(content: &str, redactions: &snapbox::Redactions) -> String { - use snapbox::filter::Filter as _; - let content = snapbox::filter::FilterPaths.filter(content.into_data()); - let content = snapbox::filter::FilterNewlines.filter(content); - let content = content.render().expect("came in as a String"); - let content = redactions.redact(&content); - content -} - -/// Normalizes the expected string so that it can be compared against the actual output. -fn normalize_expected(content: &str, redactions: &snapbox::Redactions) -> String { - use snapbox::filter::Filter as _; - let content = snapbox::filter::FilterPaths.filter(content.into_data()); - let content = snapbox::filter::FilterNewlines.filter(content); - // Remove any conditionally absent redactions like `[EXE]` - let content = content.render().expect("came in as a String"); - let content = redactions.clear_unused(&content); - content.into_owned() -} - /// Checks that the given string contains the given contiguous lines /// somewhere. /// @@ -364,12 +343,12 @@ pub(crate) fn match_contains( let expected = normalize_expected(expected, redactions); let actual = normalize_actual(actual, redactions); let e: Vec<_> = expected.lines().map(|line| WildStr::new(line)).collect(); - let a: Vec<_> = actual.lines().map(|line| WildStr::new(line)).collect(); + let a: Vec<_> = actual.lines().collect(); if e.len() == 0 { bail!("expected length must not be zero"); } for window in a.windows(e.len()) { - if window == e { + if e == window { return Ok(()); } } @@ -428,7 +407,6 @@ pub(crate) fn match_with_without( let matches: Vec<_> = actual .lines() - .map(WildStr::new) .filter(|line| with_wild.iter().all(|with| with == line)) .filter(|line| !without_wild.iter().any(|without| without == line)) .collect(); @@ -457,14 +435,35 @@ pub(crate) fn match_with_without( } } +/// Normalizes the output so that it can be compared against the expected value. +fn normalize_actual(content: &str, redactions: &snapbox::Redactions) -> String { + use snapbox::filter::Filter as _; + let content = snapbox::filter::FilterPaths.filter(content.into_data()); + let content = snapbox::filter::FilterNewlines.filter(content); + let content = content.render().expect("came in as a String"); + let content = redactions.redact(&content); + content +} + +/// Normalizes the expected string so that it can be compared against the actual output. +fn normalize_expected(content: &str, redactions: &snapbox::Redactions) -> String { + use snapbox::filter::Filter as _; + let content = snapbox::filter::FilterPaths.filter(content.into_data()); + let content = snapbox::filter::FilterNewlines.filter(content); + // Remove any conditionally absent redactions like `[EXE]` + let content = content.render().expect("came in as a String"); + let content = redactions.clear_unused(&content); + content.into_owned() +} + /// A single line string that supports `[..]` wildcard matching. -pub(crate) struct WildStr<'a> { +struct WildStr<'a> { has_meta: bool, line: &'a str, } impl<'a> WildStr<'a> { - pub fn new(line: &'a str) -> WildStr<'a> { + fn new(line: &'a str) -> WildStr<'a> { WildStr { has_meta: line.contains("[..]"), line, @@ -472,13 +471,12 @@ impl<'a> WildStr<'a> { } } -impl<'a> PartialEq for WildStr<'a> { - fn eq(&self, other: &Self) -> bool { - match (self.has_meta, other.has_meta) { - (false, false) => self.line == other.line, - (true, false) => meta_cmp(self.line, other.line), - (false, true) => meta_cmp(other.line, self.line), - (true, true) => panic!("both lines cannot have [..]"), +impl PartialEq<&str> for WildStr<'_> { + fn eq(&self, other: &&str) -> bool { + if self.has_meta { + meta_cmp(self.line, other) + } else { + self.line == *other } } } @@ -666,10 +664,10 @@ mod test { ("[..]", "a b"), ("[..]b", "a b"), ] { - assert_eq!(WildStr::new(a), WildStr::new(b)); + assert_eq!(WildStr::new(a), b); } for (a, b) in &[("[..]b", "c"), ("b", "c"), ("b", "cb")] { - assert_ne!(WildStr::new(a), WildStr::new(b)); + assert_ne!(WildStr::new(a), b); } } diff --git a/crates/cargo-test-support/src/lib.rs b/crates/cargo-test-support/src/lib.rs index 964b72502a7..e736f0712a2 100644 --- a/crates/cargo-test-support/src/lib.rs +++ b/crates/cargo-test-support/src/lib.rs @@ -667,6 +667,57 @@ impl Execs { /// Verifies that stdout is equal to the given lines. /// /// See [`compare::assert_e2e`] for assertion details. + /// + ///
+ /// + /// Prefer passing in [`str!`] for `expected` to get snapshot updating. + /// + /// If `format!` is needed for content that changes from run to run that you don't care about, + /// consider whether you could have [`compare::assert_e2e`] redact the content. + /// If nothing else, a wildcard (`[..]`, `...`) may be useful. + /// + /// However, `""` may be preferred for intentionally empty output so people don't accidentally + /// bless a change. + /// + ///
+ /// + /// # Examples + /// + /// ```no_run + /// use cargo_test_support::prelude::*; + /// use cargo_test_support::str; + /// use cargo_test_support::execs; + /// + /// execs().with_stdout_data(str![r#" + /// Hello world! + /// "#]); + /// ``` + /// + /// Non-deterministic compiler output + /// ```no_run + /// use cargo_test_support::prelude::*; + /// use cargo_test_support::str; + /// use cargo_test_support::execs; + /// + /// execs().with_stdout_data(str![r#" + /// [COMPILING] foo + /// [COMPILING] bar + /// "#].unordered()); + /// ``` + /// + /// jsonlines + /// ```no_run + /// use cargo_test_support::prelude::*; + /// use cargo_test_support::str; + /// use cargo_test_support::execs; + /// + /// execs().with_stdout_data(str![r#" + /// [ + /// {}, + /// {} + /// ] + /// "#].is_json().against_jsonlines()); + /// ``` pub fn with_stdout_data(&mut self, expected: impl snapbox::IntoData) -> &mut Self { self.expect_stdout_data = Some(expected.into_data()); self @@ -675,6 +726,57 @@ impl Execs { /// Verifies that stderr is equal to the given lines. /// /// See [`compare::assert_e2e`] for assertion details. + /// + ///
+ /// + /// Prefer passing in [`str!`] for `expected` to get snapshot updating. + /// + /// If `format!` is needed for content that changes from run to run that you don't care about, + /// consider whether you could have [`compare::assert_e2e`] redact the content. + /// If nothing else, a wildcard (`[..]`, `...`) may be useful. + /// + /// However, `""` may be preferred for intentionally empty output so people don't accidentally + /// bless a change. + /// + ///
+ /// + /// # Examples + /// + /// ```no_run + /// use cargo_test_support::prelude::*; + /// use cargo_test_support::str; + /// use cargo_test_support::execs; + /// + /// execs().with_stderr_data(str![r#" + /// Hello world! + /// "#]); + /// ``` + /// + /// Non-deterministic compiler output + /// ```no_run + /// use cargo_test_support::prelude::*; + /// use cargo_test_support::str; + /// use cargo_test_support::execs; + /// + /// execs().with_stderr_data(str![r#" + /// [COMPILING] foo + /// [COMPILING] bar + /// "#].unordered()); + /// ``` + /// + /// jsonlines + /// ```no_run + /// use cargo_test_support::prelude::*; + /// use cargo_test_support::str; + /// use cargo_test_support::execs; + /// + /// execs().with_stderr_data(str![r#" + /// [ + /// {}, + /// {} + /// ] + /// "#].is_json().against_jsonlines()); + /// ``` pub fn with_stderr_data(&mut self, expected: impl snapbox::IntoData) -> &mut Self { self.expect_stderr_data = Some(expected.into_data()); self @@ -706,7 +808,14 @@ impl Execs { /// its output. /// /// See [`compare`] for supported patterns. - #[deprecated(note = "replaced with `Execs::with_stdout_data(expected)`")] + /// + ///
+ /// + /// Prefer [`Execs::with_stdout_data`] where possible. + /// - `expected` cannot be snapshotted + /// - `expected` can end up being ambiguous, causing the assertion to succeed when it should fail + /// + ///
pub fn with_stdout_contains(&mut self, expected: S) -> &mut Self { self.expect_stdout_contains.push(expected.to_string()); self @@ -716,7 +825,14 @@ impl Execs { /// its output. /// /// See [`compare`] for supported patterns. - #[deprecated(note = "replaced with `Execs::with_stderr_data(expected)`")] + /// + ///
+ /// + /// Prefer [`Execs::with_stderr_data`] where possible. + /// - `expected` cannot be snapshotted + /// - `expected` can end up being ambiguous, causing the assertion to succeed when it should fail + /// + ///
pub fn with_stderr_contains(&mut self, expected: S) -> &mut Self { self.expect_stderr_contains.push(expected.to_string()); self @@ -727,7 +843,18 @@ impl Execs { /// See [`compare`] for supported patterns. /// /// See note on [`Self::with_stderr_does_not_contain`]. - #[deprecated] + /// + ///
+ /// + /// Prefer [`Execs::with_stdout_data`] where possible. + /// - `expected` cannot be snapshotted + /// - The absence of `expected` can either mean success or that the string being looked for + /// changed. + /// + /// To mitigate this, consider matching this up with + /// [`Execs::with_stdout_contains`]. + /// + ///
pub fn with_stdout_does_not_contain(&mut self, expected: S) -> &mut Self { self.expect_stdout_not_contains.push(expected.to_string()); self @@ -737,12 +864,18 @@ impl Execs { /// /// See [`compare`] for supported patterns. /// - /// Care should be taken when using this method because there is a - /// limitless number of possible things that *won't* appear. A typo means - /// your test will pass without verifying the correct behavior. If - /// possible, write the test first so that it fails, and then implement - /// your fix/feature to make it pass. - #[deprecated] + ///
+ /// + /// Prefer [`Execs::with_stdout_data`] where possible. + /// - `expected` cannot be snapshotted + /// - The absence of `expected` can either mean success or that the string being looked for + /// changed. + /// + /// To mitigate this, consider either matching this up with + /// [`Execs::with_stdout_contains`] or replace it + /// with [`Execs::with_stderr_line_without`]. + /// + ///
pub fn with_stderr_does_not_contain(&mut self, expected: S) -> &mut Self { self.expect_stderr_not_contains.push(expected.to_string()); self @@ -751,7 +884,18 @@ impl Execs { /// Verify that a particular line appears in stderr with and without the /// given substrings. Exactly one line must match. /// - /// The substrings are matched as `contains`. Example: + /// The substrings are matched as `contains`. + /// + ///
+ /// + /// Prefer [`Execs::with_stdout_data`] where possible. + /// - `with` cannot be snapshotted + /// - The absence of `without`` can either mean success or that the string being looked for + /// changed. + /// + ///
+ /// + /// # Example /// /// ```no_run /// use cargo_test_support::execs; @@ -768,9 +912,6 @@ impl Execs { /// This will check that a build line includes `-C opt-level=3` but does /// not contain `-C debuginfo` or `-C incremental`. /// - /// Be careful writing the `without` fragments, see note in - /// `with_stderr_does_not_contain`. - #[deprecated] pub fn with_stderr_line_without( &mut self, with: &[S], diff --git a/tests/testsuite/artifact_dep.rs b/tests/testsuite/artifact_dep.rs index ffb4512ddda..9b93ba8eb52 100644 --- a/tests/testsuite/artifact_dep.rs +++ b/tests/testsuite/artifact_dep.rs @@ -687,7 +687,6 @@ fn build_script_with_bin_artifact_and_lib_false() { ) .build(); - #[expect(deprecated)] p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) @@ -731,7 +730,6 @@ fn lib_with_bin_artifact_and_lib_false() { ) .build(); - #[expect(deprecated)] p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) @@ -1117,7 +1115,6 @@ fn build_script_deps_adopt_specified_target_unconditionally() { .file("bar/src/lib.rs", "pub fn doit() {}") .build(); - #[expect(deprecated)] p.cargo("check -v -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_does_not_contain( @@ -1233,7 +1230,6 @@ fn non_build_script_deps_adopt_specified_target_unconditionally() { .file("bar/src/lib.rs", "pub fn doit() {}") .build(); - #[expect(deprecated)] p.cargo("check -v -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_contains( @@ -1378,7 +1374,6 @@ fn build_script_deps_adopts_target_platform_if_target_equals_target() { .build(); let alternate_target = cross_compile::alternate(); - #[expect(deprecated)] p.cargo("check -v -Z bindeps --target") .arg(alternate_target) .masquerade_as_nightly_cargo(&["bindeps"]) diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 8031cbd9c6b..e184972035e 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -132,7 +132,6 @@ fn cargo_compile_incremental() { .run(); } -#[expect(deprecated)] #[cargo_test] fn incremental_profile() { let p = project() @@ -176,7 +175,6 @@ fn incremental_profile() { .run(); } -#[expect(deprecated)] #[cargo_test] fn incremental_config() { let p = project() @@ -5180,7 +5178,6 @@ WRAPPER CALLED: rustc --crate-name foo [..] .run(); } -#[expect(deprecated)] #[cargo_test] fn rustc_wrapper_queries() { // Check that the invocations querying rustc for information are done with the wrapper. @@ -5920,7 +5917,6 @@ fn build_filter_infer_profile() { .run(); } -#[expect(deprecated)] #[cargo_test] fn targets_selected_default() { let p = project().file("src/main.rs", "fn main() {}").build(); @@ -6874,7 +6870,6 @@ Caused by: .run(); } -#[expect(deprecated)] #[cargo_test] fn build_script_o0_default() { let p = project() @@ -6887,7 +6882,6 @@ fn build_script_o0_default() { .run(); } -#[expect(deprecated)] #[cargo_test] fn build_script_o0_default_even_with_release() { let p = project() diff --git a/tests/testsuite/build_script.rs b/tests/testsuite/build_script.rs index 022d6e96fe3..897a0b493ef 100644 --- a/tests/testsuite/build_script.rs +++ b/tests/testsuite/build_script.rs @@ -3779,7 +3779,6 @@ fn custom_target_dir() { p.cargo("build -v").run(); } -#[expect(deprecated)] #[cargo_test] fn panic_abort_with_build_scripts() { let p = project() diff --git a/tests/testsuite/build_script_extra_link_arg.rs b/tests/testsuite/build_script_extra_link_arg.rs index 271d946fb81..ad3a8d13b7b 100644 --- a/tests/testsuite/build_script_extra_link_arg.rs +++ b/tests/testsuite/build_script_extra_link_arg.rs @@ -233,7 +233,6 @@ the future. For more information, see Project { .build() } -#[expect(deprecated)] #[cargo_test] fn profile_selection_build() { let p = all_target_project(); @@ -158,7 +157,6 @@ fn profile_selection_build_release() { .run(); } -#[expect(deprecated)] #[cargo_test] fn profile_selection_build_all_targets() { let p = all_target_project(); diff --git a/tests/testsuite/profile_trim_paths.rs b/tests/testsuite/profile_trim_paths.rs index df2c99f0a60..2adc1897b73 100644 --- a/tests/testsuite/profile_trim_paths.rs +++ b/tests/testsuite/profile_trim_paths.rs @@ -91,7 +91,6 @@ fn release_profile_default_to_object() { .run(); } -#[expect(deprecated)] #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn one_option() { let build = |option| { @@ -388,7 +387,6 @@ bar-0.0.1/src/lib.rs .run(); } -#[expect(deprecated)] #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn diagnostics_works() { Package::new("bar", "0.0.1") diff --git a/tests/testsuite/profiles.rs b/tests/testsuite/profiles.rs index dac6e562741..36a70391050 100644 --- a/tests/testsuite/profiles.rs +++ b/tests/testsuite/profiles.rs @@ -439,7 +439,6 @@ fn panic_unwind_does_not_build_twice() { .run(); } -#[expect(deprecated)] #[cargo_test] fn debug_0_report() { // The finished line handles 0 correctly. @@ -584,7 +583,6 @@ fn strip_accepts_true_to_strip_symbols() { .run(); } -#[expect(deprecated)] #[cargo_test] fn strip_accepts_false_to_disable_strip() { let p = project() @@ -670,7 +668,6 @@ fn strip_debuginfo_without_debug() { .run(); } -#[expect(deprecated)] #[cargo_test] fn do_not_strip_debuginfo_with_requested_debug() { let p = project() @@ -834,7 +831,6 @@ Caused by: .run(); } -#[expect(deprecated)] #[cargo_test] fn debug_options_valid() { let build = |option| { diff --git a/tests/testsuite/progress.rs b/tests/testsuite/progress.rs index e6686df8c27..5f9b8d2ebdd 100644 --- a/tests/testsuite/progress.rs +++ b/tests/testsuite/progress.rs @@ -125,7 +125,6 @@ fn always_shows_progress() { .run(); } -#[expect(deprecated)] #[cargo_test] fn never_progress() { const N: usize = 3; diff --git a/tests/testsuite/publish.rs b/tests/testsuite/publish.rs index 62be26c5dd9..417ae89485d 100644 --- a/tests/testsuite/publish.rs +++ b/tests/testsuite/publish.rs @@ -1385,7 +1385,6 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. ); } -#[expect(deprecated)] #[cargo_test] fn publish_checks_for_token_before_verify() { let registry = registry::RegistryBuilder::new() diff --git a/tests/testsuite/rustc.rs b/tests/testsuite/rustc.rs index 71ca898ae16..599438bc09e 100644 --- a/tests/testsuite/rustc.rs +++ b/tests/testsuite/rustc.rs @@ -437,7 +437,6 @@ fn build_only_bar_dependency() { .run(); } -#[expect(deprecated)] #[cargo_test] fn targets_selected_default() { let p = project().file("src/main.rs", "fn main() {}").build(); @@ -589,7 +588,6 @@ fn rustc_with_other_profile() { p.cargo("rustc --profile test").run(); } -#[expect(deprecated)] #[cargo_test] fn rustc_fingerprint() { // Verify that the fingerprint includes the rustc args. diff --git a/tests/testsuite/rustc_info_cache.rs b/tests/testsuite/rustc_info_cache.rs index adf153c82c5..2ef7da92cb4 100644 --- a/tests/testsuite/rustc_info_cache.rs +++ b/tests/testsuite/rustc_info_cache.rs @@ -10,7 +10,6 @@ const MISS: &str = "[..] rustc info cache miss[..]"; const HIT: &str = "[..]rustc info cache hit[..]"; const UPDATE: &str = "[..]updated rustc info cache[..]"; -#[expect(deprecated)] #[cargo_test] fn rustc_info_cache() { let p = project() @@ -106,7 +105,6 @@ fn rustc_info_cache() { .run(); } -#[expect(deprecated)] #[cargo_test] fn rustc_info_cache_with_wrappers() { let wrapper_project = project() diff --git a/tests/testsuite/rustdoc_extern_html.rs b/tests/testsuite/rustdoc_extern_html.rs index 341db1281c6..10856fd87bf 100644 --- a/tests/testsuite/rustdoc_extern_html.rs +++ b/tests/testsuite/rustdoc_extern_html.rs @@ -33,7 +33,6 @@ fn basic_project() -> Project { .build() } -#[expect(deprecated)] #[cargo_test] fn ignores_on_stable() { // Requires -Zrustdoc-map to use. @@ -61,7 +60,6 @@ fn simple() { assert!(myfun.contains(r#"href="https://docs.rs/bar/1.0.0/bar/struct.Straw.html""#)); } -#[expect(deprecated)] #[ignore = "Broken, temporarily disabled until https://github.com/rust-lang/rust/pull/82776 is resolved."] #[cargo_test] // #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] @@ -451,7 +449,6 @@ fn alt_sparse_registry() { assert!(gold.contains(r#"href="https://docs.rs/grimm/1.0.0/grimm/struct.Gold.html""#)); } -#[expect(deprecated)] #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn same_deps_multi_occurrence_in_dep_tree() { // rust-lang/cargo#13543 diff --git a/tests/testsuite/search.rs b/tests/testsuite/search.rs index 222a15bab2a..87203606714 100644 --- a/tests/testsuite/search.rs +++ b/tests/testsuite/search.rs @@ -178,7 +178,6 @@ fn ignore_quiet() { .run(); } -#[expect(deprecated)] #[cargo_test] fn colored_results() { let registry = setup().build(); diff --git a/tests/testsuite/standard_lib.rs b/tests/testsuite/standard_lib.rs index c4108cdfad3..1a277365797 100644 --- a/tests/testsuite/standard_lib.rs +++ b/tests/testsuite/standard_lib.rs @@ -348,7 +348,6 @@ fn simple_bin_std() { p.cargo("run -v").build_std(&setup).target_host().run(); } -#[expect(deprecated)] #[cargo_test(build_std_mock)] fn lib_nostd() { let setup = setup(); @@ -661,7 +660,6 @@ fn ignores_incremental() { .starts_with("foo-")); } -#[expect(deprecated)] #[cargo_test(build_std_mock)] fn cargo_config_injects_compiler_builtins() { let setup = setup(); @@ -760,7 +758,6 @@ fn proc_macro_only() { .run(); } -#[expect(deprecated)] #[cargo_test(build_std_mock)] fn fetch() { let setup = setup(); diff --git a/tests/testsuite/test.rs b/tests/testsuite/test.rs index a0eb50664e6..dd66bfff003 100644 --- a/tests/testsuite/test.rs +++ b/tests/testsuite/test.rs @@ -1809,7 +1809,6 @@ test test_in_bench ... ok .run(); } -#[expect(deprecated)] #[cargo_test] fn test_run_implicit_example_target() { let prj = project() @@ -1897,7 +1896,6 @@ fn test_run_implicit_example_target() { .run(); } -#[expect(deprecated)] #[cargo_test] fn test_filtered_excludes_compiling_examples() { let p = project() @@ -3596,7 +3594,6 @@ test b ... ok .run(); } -#[expect(deprecated)] #[cargo_test] fn test_virtual_manifest_one_project() { let p = project() @@ -3619,7 +3616,6 @@ fn test_virtual_manifest_one_project() { .run(); } -#[expect(deprecated)] #[cargo_test] fn test_virtual_manifest_glob() { let p = project() @@ -3872,7 +3868,6 @@ fn doctest_and_registry() { p.cargo("test --workspace -v").run(); } -#[expect(deprecated)] #[cargo_test] fn cargo_test_env() { let src = format!( @@ -4567,7 +4562,6 @@ fn doctest_skip_staticlib() { .run(); } -#[expect(deprecated)] #[cargo_test] fn can_not_mix_doc_tests_and_regular_tests() { let p = project() @@ -5419,7 +5413,6 @@ Caused by: .run(); } -#[expect(deprecated)] #[cargo_test] fn nonzero_exit_status() { // Tests for nonzero exit codes from tests. diff --git a/tests/testsuite/warn_on_failure.rs b/tests/testsuite/warn_on_failure.rs index 74d1706b1e1..f5b91597e4b 100644 --- a/tests/testsuite/warn_on_failure.rs +++ b/tests/testsuite/warn_on_failure.rs @@ -77,7 +77,6 @@ fn no_warning_on_success() { .run(); } -#[expect(deprecated)] #[cargo_test] fn no_warning_on_bin_failure() { make_lib(""); @@ -101,7 +100,6 @@ error[E0425]: cannot find function `hi` in this scope .run(); } -#[expect(deprecated)] #[cargo_test] fn warning_on_lib_failure() { make_lib("err()");