diff --git a/Cargo.lock b/Cargo.lock index f1bb1437..cc86354b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,15 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "atty" version = "0.2.14" @@ -217,21 +208,11 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "diff" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "eyre" @@ -321,15 +302,6 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "owo-colors" version = "3.4.0" @@ -342,18 +314,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - [[package]] name = "proc-macro2" version = "1.0.39" @@ -535,8 +495,8 @@ dependencies = [ "color-eyre", "colored", "crossbeam", + "diff", "lazy_static", - "pretty_assertions", "regex", "rustc_version", "serde", diff --git a/Cargo.toml b/Cargo.toml index 31fee366..a68fbc92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ rustc_version = "0.4" colored = "2" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } -pretty_assertions = "1.2.1" +diff = "0.1.13" crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } diff --git a/src/diff.rs b/src/diff.rs new file mode 100644 index 00000000..1c8e4e20 --- /dev/null +++ b/src/diff.rs @@ -0,0 +1,161 @@ +use colored::*; +use diff::{chars, lines, Result, Result::*}; + +#[derive(Default)] +struct DiffState<'a> { + /// Whether we've already printed something, so we should print starting context, too. + print_start_context: bool, + /// When we skip lines, remember the last `CONTEXT` ones to + /// display after the "skipped N lines" message + skipped_lines: Vec<&'a str>, + /// When we see a removed line, we don't print it, we + /// keep it around to compare it with the next added line. + prev_left: Option<&'a str>, +} + +/// How many lines of context are displayed around the actual diffs +const CONTEXT: usize = 2; + +impl<'a> DiffState<'a> { + /// Print `... n lines skipped ...` followed by the last `CONTEXT` lines. + fn print_end_skip(&self, skipped: usize) { + self.print_skipped_msg(skipped); + for line in self.skipped_lines.iter().rev().take(CONTEXT).rev() { + eprintln!(" {line}"); + } + } + + fn print_skipped_msg(&self, skipped: usize) { + match skipped { + // When the amount of skipped lines is exactly `CONTEXT * 2`, we already + // print all the context and don't actually skip anything. + 0 => {} + // Instead of writing a line saying we skipped one line, print that one line + 1 => eprintln!(" {}", self.skipped_lines[CONTEXT]), + _ => eprintln!("... {skipped} lines skipped ..."), + } + } + + /// Print an initial `CONTEXT` amount of lines. + fn print_start_skip(&self) { + for line in self.skipped_lines.iter().take(CONTEXT) { + eprintln!(" {line}"); + } + } + + fn print_skip(&mut self) { + let half = self.skipped_lines.len() / 2; + if !self.print_start_context { + self.print_start_context = true; + self.print_end_skip(self.skipped_lines.len().saturating_sub(CONTEXT)); + } else if half < CONTEXT { + // Print all the skipped lines if the amount of context desired is less than the amount of lines + for line in self.skipped_lines.drain(..) { + eprintln!(" {line}"); + } + } else { + self.print_start_skip(); + let skipped = self.skipped_lines.len() - CONTEXT * 2; + self.print_end_skip(skipped); + } + self.skipped_lines.clear(); + } + + fn skip(&mut self, line: &'a str) { + self.skipped_lines.push(line); + } + + fn print_prev(&mut self) { + if let Some(l) = self.prev_left.take() { + self.print_left(l); + } + } + + fn print_left(&self, l: &str) { + eprintln!("{}{}", "-".red(), l.red()); + } + + fn print_right(&self, r: &str) { + eprintln!("{}{}", "+".green(), r.green()); + } + + fn row(&mut self, row: Result<&'a str>) { + match row { + Left(l) => { + self.print_skip(); + self.print_prev(); + self.prev_left = Some(l); + } + Both(l, _) => { + self.print_prev(); + self.skip(l); + } + Right(r) => { + // When there's an added line after a removed line, we'll want to special case some print cases. + // FIXME(oli-obk): also do special printing modes when there are multiple lines that only have minor changes. + if let Some(l) = self.prev_left.take() { + let diff = chars(l, r); + let mut seen_l = false; + let mut seen_r = false; + for char in &diff { + match char { + Left(l) if !l.is_whitespace() => seen_l = true, + Right(r) if !r.is_whitespace() => seen_r = true, + _ => {} + } + } + if seen_l && seen_r { + // The line both adds and removes chars, print both lines, but highlight their differences instead of + // drawing the entire line in red/green. + eprint!("{}", "-".red()); + for char in &diff { + match char { + Left(l) => eprint!("{}", l.to_string().red()), + Right(_) => {} + Both(l, _) => eprint!("{}", l), + } + } + eprintln!(); + eprint!("{}", "+".green()); + for char in &diff { + match char { + Left(_) => {} + Right(r) => eprint!("{}", r.to_string().green()), + Both(l, _) => eprint!("{}", l), + } + } + eprintln!(); + } else { + // The line only adds or only removes chars, print a single line highlighting their differences. + eprint!("{}", "~".yellow()); + for char in diff { + match char { + Left(l) => eprint!("{}", l.to_string().red()), + Both(l, _) => eprint!("{}", l), + Right(r) => eprint!("{}", r.to_string().green()), + } + } + eprintln!(); + } + } else { + self.print_skip(); + self.print_right(r); + } + } + } + } + + fn finish(self) { + self.print_start_skip(); + self.print_skipped_msg(self.skipped_lines.len().saturating_sub(CONTEXT)); + eprintln!() + } +} + +pub fn print_diff(expected: &str, actual: &str) { + let mut state = DiffState::default(); + for row in lines(expected, actual) { + state.row(row); + } + state.finish(); +} diff --git a/src/lib.rs b/src/lib.rs index a631ad2f..ef5db360 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ use crate::dependencies::build_dependencies; use crate::parser::{Comments, Condition}; mod dependencies; +mod diff; mod parser; mod rustc_stderr; #[cfg(test)] @@ -321,12 +322,10 @@ pub fn run_tests_generic(config: Config, file_filter: impl Fn(&Path) -> bool + S actual, expected, } => { - eprintln!("actual output differed from expected {}", path.display()); - eprintln!( - "{}", - pretty_assertions::StrComparison::new(expected, actual) - ); - eprintln!() + eprintln!("{}", "actual output differed from expected".underline()); + eprintln!("{}", format!("--- {}", path.display()).red()); + eprintln!("{}", "+++ ".green()); + diff::print_diff(expected, actual); } Error::ErrorsWithoutPattern { path: None, msgs } => { eprintln!( diff --git a/tests/integrations/basic-fail/Cargo.lock b/tests/integrations/basic-fail/Cargo.lock index 0bb0ccbb..e7ea4fa8 100644 --- a/tests/integrations/basic-fail/Cargo.lock +++ b/tests/integrations/basic-fail/Cargo.lock @@ -26,15 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "atty" version = "0.2.14" @@ -224,16 +215,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "ctor" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "diff" version = "0.1.13" @@ -328,15 +309,6 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "owo-colors" version = "3.5.0" @@ -349,18 +321,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - [[package]] name = "proc-macro2" version = "1.0.43" @@ -542,8 +502,8 @@ dependencies = [ "color-eyre", "colored", "crossbeam", + "diff", "lazy_static", - "pretty_assertions", "regex", "rustc_version", "serde", diff --git a/tests/integrations/basic-fail/Cargo.stderr b/tests/integrations/basic-fail/Cargo.stderr index f957cabc..e0812482 100644 --- a/tests/integrations/basic-fail/Cargo.stderr +++ b/tests/integrations/basic-fail/Cargo.stderr @@ -39,32 +39,28 @@ For more information about this error, try `rustc --explain E0308`. tests/actual_tests/foomp.rs FAILED: command: "rustc" "--error-format=json" "--edition=2021" "--extern" "basic_fail=$DIR/$DIR/../../../target/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/$DIR/../../../target/debug" "-L" "$DIR/$DIR/../../../target/debug" "tests/actual_tests/foomp.rs" -actual output differed from expected tests/actual_tests/foomp.stderr -Diff < left / right > : - error[E0308]: mismatched types - --> $DIR/foomp.rs:4:9 - | +actual output differed from expected +--- tests/actual_tests/foomp.stderr ++++ +... 3 lines skipped ... 4 | add("42", 3); | --- ^^^^ expected `usize`, found `&str` -> | | -> | arguments to this function are incorrect ++ | | ++ | arguments to this function are incorrect | note: function defined here -< --> $DIR/tests/integrations/basic/src/lib.rs:1:8 -> --> $DIR/tests/integrations/basic-fail/src/lib.rs:1:8 +~ --> $DIR/$DIR/src/lib.rs:1:8 | 1 | pub fn add(left: usize, right: usize) -> usize { -< | ^^^ some expected text that isn't in the actual message -> | ^^^ +~ | ^^^ some expected text that isn't in the actual message -error: aborting due to previous error +-error: aborting doo to previous error ++error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. - full stderr: error[E0308]: mismatched types --> tests/actual_tests/foomp.rs:4:9 diff --git a/tests/integrations/basic/Cargo.lock b/tests/integrations/basic/Cargo.lock index da789af0..d3ecb130 100644 --- a/tests/integrations/basic/Cargo.lock +++ b/tests/integrations/basic/Cargo.lock @@ -26,15 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "atty" version = "0.2.14" @@ -224,16 +215,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "ctor" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "diff" version = "0.1.13" @@ -328,15 +309,6 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "owo-colors" version = "3.5.0" @@ -349,18 +321,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - [[package]] name = "proc-macro2" version = "1.0.43" @@ -542,8 +502,8 @@ dependencies = [ "color-eyre", "colored", "crossbeam", + "diff", "lazy_static", - "pretty_assertions", "regex", "rustc_version", "serde",