Skip to content

Commit d09d336

Browse files
committed
fix(test): Make redactions consistent with snapbox
I'm unsure how we should be replacing these use cases, so I'm exploring keeping them but making them use snapbox under the hood. Part of the intent of snapbox is that it provides you the building blocks to make what you need.
1 parent be87c96 commit d09d336

File tree

7 files changed

+78
-275
lines changed

7 files changed

+78
-275
lines changed

Cargo.lock

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ sha2 = "0.10.8"
9696
shell-escape = "0.1.5"
9797
similar = "2.6.0"
9898
supports-hyperlinks = "3.0.0"
99-
snapbox = { version = "0.6.18", features = ["diff", "dir", "term-svg", "regex", "json"] }
99+
snapbox = { version = "0.6.20", features = ["diff", "dir", "term-svg", "regex", "json"] }
100100
tar = { version = "0.4.42", default-features = false }
101101
tempfile = "3.10.1"
102102
thiserror = "1.0.63"

crates/cargo-test-support/src/compare.rs

+27-213
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ use std::fmt;
5151
use std::path::Path;
5252
use std::path::PathBuf;
5353
use std::str;
54-
use url::Url;
5554

5655
/// This makes it easier to write regex replacements that are guaranteed to only
5756
/// get compiled once
@@ -333,111 +332,37 @@ static E2E_LITERAL_REDACTIONS: &[(&str, &str)] = &[
333332
];
334333

335334
/// Normalizes the output so that it can be compared against the expected value.
336-
fn normalize_actual(actual: &str, cwd: Option<&Path>) -> String {
337-
// It's easier to read tabs in outputs if they don't show up as literal
338-
// hidden characters
339-
let actual = actual.replace('\t', "<tab>");
340-
if cfg!(windows) {
341-
// Let's not deal with \r\n vs \n on windows...
342-
let actual = actual.replace('\r', "");
343-
normalize_windows(&actual, cwd)
344-
} else {
345-
actual
346-
}
335+
fn normalize_actual(content: &str, redactions: &snapbox::Redactions) -> String {
336+
use snapbox::filter::Filter as _;
337+
let content = snapbox::filter::FilterPaths.filter(content.into_data());
338+
let content = snapbox::filter::FilterNewlines.filter(content);
339+
let content = content.render().expect("came in as a String");
340+
let content = redactions.redact(&content);
341+
content
347342
}
348343

349344
/// Normalizes the expected string so that it can be compared against the actual output.
350-
fn normalize_expected(expected: &str, cwd: Option<&Path>) -> String {
351-
let expected = replace_dirty_msvc(expected);
352-
let expected = substitute_macros(&expected);
353-
354-
if cfg!(windows) {
355-
normalize_windows(&expected, cwd)
356-
} else {
357-
let expected = match cwd {
358-
None => expected,
359-
Some(cwd) => expected.replace("[CWD]", &cwd.display().to_string()),
360-
};
361-
let expected = expected.replace("[ROOT]", &paths::root().display().to_string());
362-
expected
363-
}
364-
}
365-
366-
fn replace_dirty_msvc_impl(s: &str, is_msvc: bool) -> String {
367-
if is_msvc {
368-
s.replace("[DIRTY-MSVC]", "[DIRTY]")
369-
} else {
370-
use itertools::Itertools;
371-
372-
let mut new = s
373-
.lines()
374-
.filter(|it| !it.starts_with("[DIRTY-MSVC]"))
375-
.join("\n");
376-
377-
if s.ends_with("\n") {
378-
new.push_str("\n");
379-
}
380-
381-
new
382-
}
383-
}
384-
385-
fn replace_dirty_msvc(s: &str) -> String {
386-
replace_dirty_msvc_impl(s, cfg!(target_env = "msvc"))
387-
}
388-
389-
/// Normalizes text for both actual and expected strings on Windows.
390-
fn normalize_windows(text: &str, cwd: Option<&Path>) -> String {
391-
// Let's not deal with / vs \ (windows...)
392-
let text = text.replace('\\', "/");
393-
394-
// Weirdness for paths on Windows extends beyond `/` vs `\` apparently.
395-
// Namely paths like `c:\` and `C:\` are equivalent and that can cause
396-
// issues. The return value of `env::current_dir()` may return a
397-
// lowercase drive name, but we round-trip a lot of values through `Url`
398-
// which will auto-uppercase the drive name. To just ignore this
399-
// distinction we try to canonicalize as much as possible, taking all
400-
// forms of a path and canonicalizing them to one.
401-
let replace_path = |s: &str, path: &Path, with: &str| {
402-
let path_through_url = Url::from_file_path(path).unwrap().to_file_path().unwrap();
403-
let path1 = path.display().to_string().replace('\\', "/");
404-
let path2 = path_through_url.display().to_string().replace('\\', "/");
405-
s.replace(&path1, with)
406-
.replace(&path2, with)
407-
.replace(with, &path1)
408-
};
409-
410-
let text = match cwd {
411-
None => text,
412-
Some(p) => replace_path(&text, p, "[CWD]"),
413-
};
414-
415-
// Similar to cwd above, perform similar treatment to the root path
416-
// which in theory all of our paths should otherwise get rooted at.
417-
let root = paths::root();
418-
let text = replace_path(&text, &root, "[ROOT]");
419-
420-
text
421-
}
422-
423-
fn substitute_macros(input: &str) -> String {
424-
let mut result = input.to_owned();
425-
for &(pat, subst) in MIN_LITERAL_REDACTIONS {
426-
result = result.replace(pat, subst)
427-
}
428-
for &(pat, subst) in E2E_LITERAL_REDACTIONS {
429-
result = result.replace(pat, subst)
430-
}
431-
result
345+
fn normalize_expected(content: &str, redactions: &snapbox::Redactions) -> String {
346+
use snapbox::filter::Filter as _;
347+
let content = snapbox::filter::FilterPaths.filter(content.into_data());
348+
let content = snapbox::filter::FilterNewlines.filter(content);
349+
// Remove any conditionally absent redactions like `[EXE]`
350+
let content = content.render().expect("came in as a String");
351+
let content = redactions.clear_unused(&content);
352+
content.into_owned()
432353
}
433354

434355
/// Checks that the given string contains the given contiguous lines
435356
/// somewhere.
436357
///
437358
/// See [Patterns](index.html#patterns) for more information on pattern matching.
438-
pub(crate) fn match_contains(expected: &str, actual: &str, cwd: Option<&Path>) -> Result<()> {
439-
let expected = normalize_expected(expected, cwd);
440-
let actual = normalize_actual(actual, cwd);
359+
pub(crate) fn match_contains(
360+
expected: &str,
361+
actual: &str,
362+
redactions: &snapbox::Redactions,
363+
) -> Result<()> {
364+
let expected = normalize_expected(expected, redactions);
365+
let actual = normalize_actual(actual, redactions);
441366
let e: Vec<_> = expected.lines().map(|line| WildStr::new(line)).collect();
442367
let a: Vec<_> = actual.lines().map(|line| WildStr::new(line)).collect();
443368
if e.len() == 0 {
@@ -465,9 +390,9 @@ pub(crate) fn match_contains(expected: &str, actual: &str, cwd: Option<&Path>) -
465390
pub(crate) fn match_does_not_contain(
466391
expected: &str,
467392
actual: &str,
468-
cwd: Option<&Path>,
393+
redactions: &snapbox::Redactions,
469394
) -> Result<()> {
470-
if match_contains(expected, actual, cwd).is_ok() {
395+
if match_contains(expected, actual, redactions).is_ok() {
471396
bail!(
472397
"expected not to find:\n\
473398
{}\n\n\
@@ -492,10 +417,10 @@ pub(crate) fn match_with_without(
492417
actual: &str,
493418
with: &[String],
494419
without: &[String],
495-
cwd: Option<&Path>,
420+
redactions: &snapbox::Redactions,
496421
) -> Result<()> {
497-
let actual = normalize_actual(actual, cwd);
498-
let norm = |s: &String| format!("[..]{}[..]", normalize_expected(s, cwd));
422+
let actual = normalize_actual(actual, redactions);
423+
let norm = |s: &String| format!("[..]{}[..]", normalize_expected(s, redactions));
499424
let with: Vec<_> = with.iter().map(norm).collect();
500425
let without: Vec<_> = without.iter().map(norm).collect();
501426
let with_wild: Vec<_> = with.iter().map(|w| WildStr::new(w)).collect();
@@ -748,117 +673,6 @@ mod test {
748673
}
749674
}
750675

751-
#[test]
752-
fn dirty_msvc() {
753-
let case = |expected: &str, wild: &str, msvc: bool| {
754-
assert_eq!(expected, &replace_dirty_msvc_impl(wild, msvc));
755-
};
756-
757-
// no replacements
758-
case("aa", "aa", false);
759-
case("aa", "aa", true);
760-
761-
// with replacements
762-
case(
763-
"\
764-
[DIRTY] a",
765-
"\
766-
[DIRTY-MSVC] a",
767-
true,
768-
);
769-
case(
770-
"",
771-
"\
772-
[DIRTY-MSVC] a",
773-
false,
774-
);
775-
case(
776-
"\
777-
[DIRTY] a
778-
[COMPILING] a",
779-
"\
780-
[DIRTY-MSVC] a
781-
[COMPILING] a",
782-
true,
783-
);
784-
case(
785-
"\
786-
[COMPILING] a",
787-
"\
788-
[DIRTY-MSVC] a
789-
[COMPILING] a",
790-
false,
791-
);
792-
793-
// test trailing newline behavior
794-
case(
795-
"\
796-
A
797-
B
798-
", "\
799-
A
800-
B
801-
", true,
802-
);
803-
804-
case(
805-
"\
806-
A
807-
B
808-
", "\
809-
A
810-
B
811-
", false,
812-
);
813-
814-
case(
815-
"\
816-
A
817-
B", "\
818-
A
819-
B", true,
820-
);
821-
822-
case(
823-
"\
824-
A
825-
B", "\
826-
A
827-
B", false,
828-
);
829-
830-
case(
831-
"\
832-
[DIRTY] a
833-
",
834-
"\
835-
[DIRTY-MSVC] a
836-
",
837-
true,
838-
);
839-
case(
840-
"\n",
841-
"\
842-
[DIRTY-MSVC] a
843-
",
844-
false,
845-
);
846-
847-
case(
848-
"\
849-
[DIRTY] a",
850-
"\
851-
[DIRTY-MSVC] a",
852-
true,
853-
);
854-
case(
855-
"",
856-
"\
857-
[DIRTY-MSVC] a",
858-
false,
859-
);
860-
}
861-
862676
#[test]
863677
fn redact_elapsed_time() {
864678
let mut subs = snapbox::Redactions::new();

crates/cargo-test-support/src/lib.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -820,10 +820,6 @@ impl Execs {
820820
self
821821
}
822822

823-
fn get_cwd(&self) -> Option<&Path> {
824-
self.process_builder.as_ref().and_then(|p| p.get_cwd())
825-
}
826-
827823
pub fn env<T: AsRef<OsStr>>(&mut self, key: &str, val: T) -> &mut Self {
828824
if let Some(ref mut p) = self.process_builder {
829825
p.env(key, val);
@@ -1021,7 +1017,6 @@ impl Execs {
10211017
self.verify_checks_output(stdout, stderr);
10221018
let stdout = std::str::from_utf8(stdout).expect("stdout is not utf8");
10231019
let stderr = std::str::from_utf8(stderr).expect("stderr is not utf8");
1024-
let cwd = self.get_cwd();
10251020

10261021
match self.expect_exit_code {
10271022
None => {}
@@ -1054,19 +1049,19 @@ impl Execs {
10541049
}
10551050
}
10561051
for expect in self.expect_stdout_contains.iter() {
1057-
compare::match_contains(expect, stdout, cwd)?;
1052+
compare::match_contains(expect, stdout, self.assert.redactions())?;
10581053
}
10591054
for expect in self.expect_stderr_contains.iter() {
1060-
compare::match_contains(expect, stderr, cwd)?;
1055+
compare::match_contains(expect, stderr, self.assert.redactions())?;
10611056
}
10621057
for expect in self.expect_stdout_not_contains.iter() {
1063-
compare::match_does_not_contain(expect, stdout, cwd)?;
1058+
compare::match_does_not_contain(expect, stdout, self.assert.redactions())?;
10641059
}
10651060
for expect in self.expect_stderr_not_contains.iter() {
1066-
compare::match_does_not_contain(expect, stderr, cwd)?;
1061+
compare::match_does_not_contain(expect, stderr, self.assert.redactions())?;
10671062
}
10681063
for (with, without) in self.expect_stderr_with_without.iter() {
1069-
compare::match_with_without(stderr, with, without, cwd)?;
1064+
compare::match_with_without(stderr, with, without, self.assert.redactions())?;
10701065
}
10711066
Ok(())
10721067
}

0 commit comments

Comments
 (0)