diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:25 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:25 +0000 |
commit | 5363f350887b1e5b5dd21a86f88c8af9d7fea6da (patch) | |
tree | 35ca005eb6e0e9a1ba3bb5dbc033209ad445dc17 /vendor/pretty_assertions/src | |
parent | Adding debian version 1.66.0+dfsg1-1. (diff) | |
download | rustc-5363f350887b1e5b5dd21a86f88c8af9d7fea6da.tar.xz rustc-5363f350887b1e5b5dd21a86f88c8af9d7fea6da.zip |
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/pretty_assertions/src')
-rw-r--r-- | vendor/pretty_assertions/src/lib.rs | 515 | ||||
-rw-r--r-- | vendor/pretty_assertions/src/printer.rs | 164 |
2 files changed, 398 insertions, 281 deletions
diff --git a/vendor/pretty_assertions/src/lib.rs b/vendor/pretty_assertions/src/lib.rs index 5c1787533..aebe08776 100644 --- a/vendor/pretty_assertions/src/lib.rs +++ b/vendor/pretty_assertions/src/lib.rs @@ -6,11 +6,11 @@ //! But you have to spot the differences yourself, which is not always straightforward, //! like here: //! -//! ![standard assertion](https://raw.githubusercontent.com/colin-kiegel/rust-pretty-assertions/2d2357ff56d22c51a86b2f1cfe6efcee9f5a8081/examples/standard_assertion.png) +//! ![standard assertion](https://raw.githubusercontent.com/rust-pretty-assertions/rust-pretty-assertions/2d2357ff56d22c51a86b2f1cfe6efcee9f5a8081/examples/standard_assertion.png) //! //! Wouldn't that task be _much_ easier with a colorful diff? //! -//! ![pretty assertion](https://raw.githubusercontent.com/colin-kiegel/rust-pretty-assertions/2d2357ff56d22c51a86b2f1cfe6efcee9f5a8081/examples/pretty_assertion.png) +//! ![pretty assertion](https://raw.githubusercontent.com/rust-pretty-assertions/rust-pretty-assertions/2d2357ff56d22c51a86b2f1cfe6efcee9f5a8081/examples/pretty_assertion.png) //! //! Yep — and you only need **one line of code** to make it happen: //! @@ -62,11 +62,25 @@ //! you include. //! * `assert_ne` is also switched to multi-line presentation, but does _not_ show //! a diff. - +//! +//! ## Features +//! +//! Features provided by the crate are: +//! +//! - `std`: Use the Rust standard library. Enabled by default. +//! Exactly one of `std` and `alloc` is required. +//! - `alloc`: Use the `alloc` crate. +//! Exactly one of `std` and `alloc` is required. +//! - `unstable`: opt-in to unstable features that may not follow Semantic Versioning. +//! Implmenetion behind this feature is subject to change without warning between patch versions. + +#![cfg_attr(not(feature = "std"), no_std)] #![deny(clippy::all, missing_docs, unsafe_code)] -pub use ansi_term::Style; -use std::fmt::{self, Debug, Display}; +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; +use core::fmt::{self, Debug, Display}; mod printer; @@ -126,12 +140,82 @@ where } } +/// A comparison of two strings. +/// +/// In contrast to [`Comparison`], which uses the [`core::fmt::Debug`] representation, +/// `StrComparison` uses the string values directly, resulting in multi-line output for multiline strings. +/// +/// ``` +/// use pretty_assertions::StrComparison; +/// +/// print!("{}", StrComparison::new("foo\nbar", "foo\nbaz")); +/// ``` +/// +/// ## Value type bounds +/// +/// Any value that can be referenced as a [`str`] via [`AsRef`] may be used: +/// +/// ``` +/// use pretty_assertions::StrComparison; +/// +/// #[derive(PartialEq)] +/// struct MyString(String); +/// +/// impl AsRef<str> for MyString { +/// fn as_ref(&self) -> &str { +/// &self.0 +/// } +/// } +/// +/// print!( +/// "{}", +/// StrComparison::new( +/// &MyString("foo\nbar".to_owned()), +/// &MyString("foo\nbaz".to_owned()), +/// ), +/// ); +/// ``` +/// +/// The values may have different types, although in practice they are usually the same. +pub struct StrComparison<'a, TLeft, TRight> +where + TLeft: ?Sized, + TRight: ?Sized, +{ + left: &'a TLeft, + right: &'a TRight, +} + +impl<'a, TLeft, TRight> StrComparison<'a, TLeft, TRight> +where + TLeft: AsRef<str> + ?Sized, + TRight: AsRef<str> + ?Sized, +{ + /// Store two values to be compared in future. + /// + /// Expensive diffing is deferred until calling `Debug::fmt`. + pub fn new(left: &'a TLeft, right: &'a TRight) -> StrComparison<'a, TLeft, TRight> { + StrComparison { left, right } + } +} + +impl<'a, TLeft, TRight> Display for StrComparison<'a, TLeft, TRight> +where + TLeft: AsRef<str> + ?Sized, + TRight: AsRef<str> + ?Sized, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + printer::write_header(f)?; + printer::write_lines(f, self.left.as_ref(), self.right.as_ref()) + } +} + /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// /// On panic, this macro will print a diff derived from [`Debug`] representation of /// each value. /// -/// This is a drop in replacement for [`std::assert_eq!`]. +/// This is a drop in replacement for [`core::assert_eq!`]. /// You can provide a custom panic message if desired. /// /// # Examples @@ -147,32 +231,70 @@ where /// ``` #[macro_export] macro_rules! assert_eq { - ($left:expr , $right:expr,) => ({ - $crate::assert_eq!($left, $right) + ($left:expr, $right:expr$(,)?) => ({ + $crate::assert_eq!(@ $left, $right, "", ""); + }); + ($left:expr, $right:expr, $($arg:tt)*) => ({ + $crate::assert_eq!(@ $left, $right, ": ", $($arg)+); }); - ($left:expr , $right:expr) => ({ + (@ $left:expr, $right:expr, $maybe_colon:expr, $($arg:tt)*) => ({ match (&($left), &($right)) { (left_val, right_val) => { if !(*left_val == *right_val) { - ::std::panic!("assertion failed: `(left == right)`\ - \n\ - \n{}\ - \n", - $crate::Comparison::new(left_val, right_val)) + use $crate::private::CreateComparison; + ::core::panic!("assertion failed: `(left == right)`{}{}\ + \n\ + \n{}\ + \n", + $maybe_colon, + format_args!($($arg)*), + (left_val, right_val).create_comparison() + ) } } } }); - ($left:expr , $right:expr, $($arg:tt)*) => ({ +} + +/// Asserts that two expressions are equal to each other (using [`PartialEq`]). +/// +/// On panic, this macro will print a diff derived from each value's [`str`] representation. +/// See [`StrComparison`] for further details. +/// +/// This is a drop in replacement for [`core::assert_eq!`]. +/// You can provide a custom panic message if desired. +/// +/// # Examples +/// +/// ``` +/// use pretty_assertions::assert_str_eq; +/// +/// let a = "foo\nbar"; +/// let b = ["foo", "bar"].join("\n"); +/// assert_str_eq!(a, b); +/// +/// assert_str_eq!(a, b, "we are testing concatenation with {} and {}", a, b); +/// ``` +#[macro_export] +macro_rules! assert_str_eq { + ($left:expr, $right:expr$(,)?) => ({ + $crate::assert_str_eq!(@ $left, $right, "", ""); + }); + ($left:expr, $right:expr, $($arg:tt)*) => ({ + $crate::assert_str_eq!(@ $left, $right, ": ", $($arg)+); + }); + (@ $left:expr, $right:expr, $maybe_colon:expr, $($arg:tt)*) => ({ match (&($left), &($right)) { (left_val, right_val) => { if !(*left_val == *right_val) { - ::std::panic!("assertion failed: `(left == right)`: {}\ - \n\ - \n{}\ - \n", - format_args!($($arg)*), - $crate::Comparison::new(left_val, right_val)) + ::core::panic!("assertion failed: `(left == right)`{}{}\ + \n\ + \n{}\ + \n", + $maybe_colon, + format_args!($($arg)*), + $crate::StrComparison::new(left_val, right_val) + ) } } } @@ -184,7 +306,7 @@ macro_rules! assert_eq { /// On panic, this macro will print the values of the expressions with their /// [`Debug`] representations. /// -/// This is a drop in replacement for [`std::assert_ne!`]. +/// This is a drop in replacement for [`core::assert_ne!`]. /// You can provide a custom panic message if desired. /// /// # Examples @@ -200,276 +322,145 @@ macro_rules! assert_eq { /// ``` #[macro_export] macro_rules! assert_ne { - ($left:expr, $right:expr) => ({ - $crate::assert_ne!(@ $left, $right, "", ""); - }); - ($left:expr, $right:expr,) => ({ + ($left:expr, $right:expr$(,)?) => ({ $crate::assert_ne!(@ $left, $right, "", ""); }); ($left:expr, $right:expr, $($arg:tt)+) => ({ $crate::assert_ne!(@ $left, $right, ": ", $($arg)+); }); - (@ $left:expr, $right:expr, $maybe_semicolon:expr, $($arg:tt)+) => ({ + (@ $left:expr, $right:expr, $maybe_colon:expr, $($arg:tt)+) => ({ match (&($left), &($right)) { (left_val, right_val) => { if *left_val == *right_val { - let left_dbg = ::std::format!("{:?}", &*left_val); - let right_dbg = ::std::format!("{:?}", &*right_val); - if left_dbg != right_dbg { - - ::std::panic!("assertion failed: `(left != right)`{}{}\ - \n\ - \n{}\ - \n{}: According to the `PartialEq` implementation, both of the values \ - are partially equivalent, even if the `Debug` outputs differ.\ - \n\ - \n", - $maybe_semicolon, - format_args!($($arg)+), - $crate::Comparison::new(left_val, right_val), - $crate::Style::new() - .bold() - .underline() - .paint("Note")) - } - - ::std::panic!("assertion failed: `(left != right)`{}{}\ + ::core::panic!("assertion failed: `(left != right)`{}{}\ \n\ - \n{}:\ + \nBoth sides:\ \n{:#?}\ \n\ \n", - $maybe_semicolon, - format_args!($($arg)+), - $crate::Style::new().bold().paint("Both sides"), - left_val) + $maybe_colon, + format_args!($($arg)+), + left_val + ) } } } }); } -#[cfg(test)] -#[allow(clippy::eq_op)] -#[no_implicit_prelude] -mod test { - mod assert_eq { - use ::std::string::{String, ToString}; - - #[test] - fn passes() { - let a = "some value"; - crate::assert_eq!(a, a); - } - - #[test] - fn passes_unsized() { - let a: &[u8] = b"e"; - crate::assert_eq!(*a, *a); - } - - #[test] - fn passes_comparable_types() { - let s0: &'static str = "foo"; - let s1: String = "foo".to_string(); - crate::assert_eq!(s0, s1); - } - - #[test] - #[should_panic(expected = r#"assertion failed: `(left == right)` - -[1mDiff[0m [31m< left[0m / [32mright >[0m : -[31m<[0m[1;48;5;52;31m666[0m -[32m>[0m[1;48;5;22;32m999[0m - -"#)] - fn fails() { - crate::assert_eq!(666, 999); - } - - #[test] - #[should_panic(expected = r#"assertion failed: `(left == right)` - -[1mDiff[0m [31m< left[0m / [32mright >[0m : -[31m<[0m[1;48;5;52;31m666[0m -[32m>[0m[1;48;5;22;32m999[0m - -"#)] - fn fails_trailing_comma() { - crate::assert_eq!(666, 999,); +/// Asserts that a value matches a pattern. +/// +/// On panic, this macro will print a diff derived from [`Debug`] representation of +/// the value, and a string representation of the pattern. +/// +/// This is a drop in replacement for [`core::assert_matches::assert_matches!`]. +/// You can provide a custom panic message if desired. +/// +/// # Examples +/// +/// ``` +/// use pretty_assertions::assert_matches; +/// +/// let a = Some(3); +/// assert_matches!(a, Some(_)); +/// +/// assert_matches!(a, Some(value) if value > 2, "we are testing {:?} with a pattern", a); +/// ``` +/// +/// # Features +/// +/// Requires the `unstable` feature to be enabled. +/// +/// **Please note:** implementation under the `unstable` feature may be changed between +/// patch versions without warning. +#[cfg(feature = "unstable")] +#[macro_export] +macro_rules! assert_matches { + ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => ({ + match $left { + $( $pattern )|+ $( if $guard )? => {} + ref left_val => { + $crate::assert_matches!( + @ + left_val, + ::core::stringify!($($pattern)|+ $(if $guard)?), + "", + "" + ); + } } - - #[test] - #[should_panic(expected = r#"assertion failed: `(left == right)` - -[1mDiff[0m [31m< left[0m / [32mright >[0m : - [ - 101, -[32m> 101,[0m - ] - -"#)] - fn fails_unsized() { - let a: &[u8] = b"e"; - let b: &[u8] = b"ee"; - crate::assert_eq!(*a, *b); + }); + ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )?, $($arg:tt)+) => ({ + match $left { + $( $pattern )|+ $( if $guard )? => {} + ref left_val => { + $crate::assert_matches!( + @ + left_val, + ::core::stringify!($($pattern)|+ $(if $guard)?), + ": ", + $($arg)+ + ); + } } - #[test] - #[should_panic( - expected = r#"assertion failed: `(left == right)`: custom panic message - -[1mDiff[0m [31m< left[0m / [32mright >[0m : -[31m<[0m[1;48;5;52;31m666[0m -[32m>[0m[1;48;5;22;32m999[0m + }); + (@ $left:expr, $right:expr, $maybe_colon:expr, $($arg:tt)*) => ({ + match (&($left), &($right)) { + (left_val, right_val) => { + // Use the Display implementation to display the pattern, + // as using Debug would add another layer of quotes to the output. + struct Pattern<'a>(&'a str); + impl ::core::fmt::Debug for Pattern<'_> { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + ::core::fmt::Display::fmt(self.0, f) + } + } -"# - )] - fn fails_custom() { - crate::assert_eq!(666, 999, "custom panic message"); + ::core::panic!("assertion failed: `(left matches right)`{}{}\ + \n\ + \n{}\ + \n", + $maybe_colon, + format_args!($($arg)*), + $crate::Comparison::new(left_val, &Pattern(right_val)) + ) + } } + }); +} - #[test] - #[should_panic( - expected = r#"assertion failed: `(left == right)`: custom panic message +// Not public API. Used by the expansion of this crate's assert macros. +#[doc(hidden)] +pub mod private { + #[cfg(feature = "alloc")] + use alloc::string::String; -[1mDiff[0m [31m< left[0m / [32mright >[0m : -[31m<[0m[1;48;5;52;31m666[0m -[32m>[0m[1;48;5;22;32m999[0m + pub trait CompareAsStrByDefault: AsRef<str> {} + impl CompareAsStrByDefault for str {} + impl CompareAsStrByDefault for String {} + impl<T: CompareAsStrByDefault + ?Sized> CompareAsStrByDefault for &T {} -"# - )] - fn fails_custom_trailing_comma() { - crate::assert_eq!(666, 999, "custom panic message",); - } + pub trait CreateComparison { + type Comparison; + fn create_comparison(self) -> Self::Comparison; } - mod assert_ne { - use ::std::string::{String, ToString}; - - #[test] - fn passes() { - let a = "a"; - let b = "b"; - crate::assert_ne!(a, b); + impl<'a, T, U> CreateComparison for &'a (T, U) { + type Comparison = crate::Comparison<'a, T, U>; + fn create_comparison(self) -> Self::Comparison { + crate::Comparison::new(&self.0, &self.1) } + } - #[test] - fn passes_unsized() { - let a: &[u8] = b"e"; - let b: &[u8] = b"ee"; - crate::assert_ne!(*a, *b); - } - - #[test] - fn passes_comparable_types() { - let s0: &'static str = "foo"; - let s1: String = "bar".to_string(); - crate::assert_ne!(s0, s1); - } - - #[test] - #[should_panic(expected = r#"assertion failed: `(left != right)` - -[1mBoth sides[0m: -666 -"#)] - fn fails() { - crate::assert_ne!(666, 666); - } - - #[test] - #[should_panic(expected = r#"assertion failed: `(left != right)` - -[1mBoth sides[0m: -666 -"#)] - fn fails_trailing_comma() { - crate::assert_ne!(666, 666,); - } - - #[test] - #[should_panic(expected = r#"assertion failed: `(left != right)` - -[1mBoth sides[0m: -[ - 101, -] - -"#)] - fn fails_unsized() { - let a: &[u8] = b"e"; - crate::assert_ne!(*a, *a); - } - - #[test] - #[should_panic( - expected = r#"assertion failed: `(left != right)`: custom panic message - -[1mBoth sides[0m: -666 -"# - )] - fn fails_custom() { - crate::assert_ne!(666, 666, "custom panic message"); - } - - #[test] - #[should_panic( - expected = r#"assertion failed: `(left != right)`: custom panic message - -[1mBoth sides[0m: -666 -"# - )] - fn fails_custom_trailing_comma() { - crate::assert_ne!(666, 666, "custom panic message",); - } - - // If the values are equal but their debug outputs are not - // show a specific warning - - #[test] - #[should_panic(expected = r#"assertion failed: `(left != right)` - -[1mDiff[0m [31m< left[0m / [32mright >[0m : -[31m<[0m[1;48;5;52;31m-[0m[31m0.0[0m -[32m>0.0[0m - -[1;4mNote[0m: According to the `PartialEq` implementation, both of the values are partially equivalent, even if the `Debug` outputs differ. - -"#)] - fn assert_ne_partial() { - // Workaround for https://github.com/rust-lang/rust/issues/47619 - // can be removed, when we require rust 1.25 or higher - struct Foo(f32); - - use ::std::fmt; - impl fmt::Debug for Foo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ::std::write!(f, "{:.1?}", self.0) - } - } - - impl ::std::cmp::PartialEq for Foo { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - crate::assert_ne!(Foo(-0.0), Foo(0.0)); - } - - // Regression tests - - #[test] - #[should_panic] - fn assert_ne_non_empty_return() { - fn not_zero(x: u32) -> u32 { - crate::assert_ne!(x, 0); - x - } - not_zero(0); + impl<'a, T, U> CreateComparison for (&'a T, &'a U) + where + T: CompareAsStrByDefault + ?Sized, + U: CompareAsStrByDefault + ?Sized, + { + type Comparison = crate::StrComparison<'a, T, U>; + fn create_comparison(self) -> Self::Comparison { + crate::StrComparison::new(self.0, self.1) } } } diff --git a/vendor/pretty_assertions/src/printer.rs b/vendor/pretty_assertions/src/printer.rs index 172b1ed6c..24c25f0b7 100644 --- a/vendor/pretty_assertions/src/printer.rs +++ b/vendor/pretty_assertions/src/printer.rs @@ -1,8 +1,10 @@ -use ansi_term::{ - Colour::{Fixed, Green, Red}, +#[cfg(feature = "alloc")] +use alloc::format; +use core::fmt; +use yansi::{ + Color::{Fixed, Green, Red, Unset}, Style, }; -use std::fmt; macro_rules! paint { ($f:expr, $colour:expr, $fmt:expr, $($args:tt)*) => ( @@ -18,7 +20,7 @@ pub(crate) fn write_header(f: &mut fmt::Formatter) -> fmt::Result { writeln!( f, "{} {} / {} :", - Style::new().bold().paint("Diff"), + Style::new(Unset).bold().paint("Diff"), Red.paint(format!("{} left", SIGN_LEFT)), Green.paint(format!("right {}", SIGN_RIGHT)) ) @@ -27,7 +29,7 @@ pub(crate) fn write_header(f: &mut fmt::Formatter) -> fmt::Result { /// Delay formatting this deleted chunk until later. /// /// It can be formatted as a whole chunk by calling `flush`, or the inner value -/// obtained with `take` for further processing. +/// obtained with `take` for further processing (such as an inline diff). #[derive(Default)] struct LatentDeletion<'a> { // The most recent deleted line we've seen @@ -45,7 +47,7 @@ impl<'a> LatentDeletion<'a> { /// Take the underlying chunk value, if it's suitable for inline diffing. /// - /// If there is no value of we've seen more than one line, return `None`. + /// If there is no value or we've seen more than one line, return `None`. fn take(&mut self) -> Option<&'a str> { if self.count == 1 { self.value.take() @@ -98,10 +100,6 @@ pub(crate) fn write_lines<TWrite: fmt::Write>( previous_deletion.flush(f)?; previous_deletion.set(deleted); } - // Underlying diff library should never return this sequence - (::diff::Result::Right(_), Some(::diff::Result::Left(_))) => { - panic!("insertion followed by deletion"); - } // If we're being followed by more insertions, don't inline diff (::diff::Result::Right(inserted), Some(::diff::Result::Right(_))) => { previous_deletion.flush(f)?; @@ -141,7 +139,7 @@ where fn new(f: &'a mut Writer) -> Self { InlineWriter { f, - style: Style::new(), + style: Style::new(Unset), } } @@ -152,10 +150,11 @@ where write!(self.f, "{}", c)?; } else { // Close out previous style - write!(self.f, "{}", self.style.suffix())?; + self.style.fmt_suffix(self.f)?; // Store new style and start writing it - write!(self.f, "{}{}", style.prefix(), c)?; + style.fmt_prefix(self.f)?; + write!(self.f, "{}", c)?; self.style = style; } Ok(()) @@ -164,8 +163,9 @@ where /// Finish any existing style and reset to default state. fn finish(&mut self) -> fmt::Result { // Close out previous style - writeln!(self.f, "{}", self.style.suffix())?; - self.style = Default::default(); + self.style.fmt_suffix(self.f)?; + writeln!(self.f)?; + self.style = Style::new(Unset); Ok(()) } } @@ -180,8 +180,8 @@ fn write_inline_diff<TWrite: fmt::Write>(f: &mut TWrite, left: &str, right: &str let mut writer = InlineWriter::new(f); // Print the left string on one line, with differences highlighted - let light = Red.into(); - let heavy = Red.on(Fixed(52)).bold(); + let light = Style::new(Red); + let heavy = Style::new(Red).bg(Fixed(52)).bold(); writer.write_with_style(&SIGN_LEFT, light)?; for change in diff.iter() { match change { @@ -193,8 +193,8 @@ fn write_inline_diff<TWrite: fmt::Write>(f: &mut TWrite, left: &str, right: &str writer.finish()?; // Print the right string on one line, with differences highlighted - let light = Green.into(); - let heavy = Green.on(Fixed(22)).bold(); + let light = Style::new(Green); + let heavy = Style::new(Green).bg(Fixed(22)).bold(); writer.write_with_style(&SIGN_RIGHT, light)?; for change in diff.iter() { match change { @@ -210,6 +210,9 @@ fn write_inline_diff<TWrite: fmt::Write>(f: &mut TWrite, left: &str, right: &str mod test { use super::*; + #[cfg(feature = "alloc")] + use alloc::string::String; + // ANSI terminal codes used in our outputs. // // Interpolate these into test strings to make expected values easier to read. @@ -230,6 +233,8 @@ mod test { let mut actual = String::new(); printer(&mut actual, left, right).expect("printer function failed"); + // Cannot use IO without stdlib + #[cfg(feature = "std")] println!( "## left ##\n\ {}\n\ @@ -471,4 +476,125 @@ Cabbage"#; check_printer(write_lines, left, right, &expected); } + + mod write_lines_edge_newlines { + use super::*; + + #[test] + fn both_trailing() { + let left = "fan\n"; + let right = "mug\n"; + // Note the additional space at the bottom is caused by a trailing newline + // adding an additional line with zero content to both sides of the diff + let expected = format!( + r#"{red_light}<{reset}{red_heavy}fan{reset} +{green_light}>{reset}{green_heavy}mug{reset} + +"#, + red_light = RED_LIGHT, + red_heavy = RED_HEAVY, + green_light = GREEN_LIGHT, + green_heavy = GREEN_HEAVY, + reset = RESET, + ); + + check_printer(write_lines, left, right, &expected); + } + + #[test] + fn both_leading() { + let left = "\nfan"; + let right = "\nmug"; + // Note the additional space at the top is caused by a leading newline + // adding an additional line with zero content to both sides of the diff + let expected = format!( + r#" +{red_light}<{reset}{red_heavy}fan{reset} +{green_light}>{reset}{green_heavy}mug{reset} +"#, + red_light = RED_LIGHT, + red_heavy = RED_HEAVY, + green_light = GREEN_LIGHT, + green_heavy = GREEN_HEAVY, + reset = RESET, + ); + + check_printer(write_lines, left, right, &expected); + } + + #[test] + fn leading_added() { + let left = "fan"; + let right = "\nmug"; + let expected = format!( + r#"{red_light}<fan{reset} +{green_light}>{reset} +{green_light}>mug{reset} +"#, + red_light = RED_LIGHT, + green_light = GREEN_LIGHT, + reset = RESET, + ); + + check_printer(write_lines, left, right, &expected); + } + + #[test] + fn leading_deleted() { + let left = "\nfan"; + let right = "mug"; + let expected = format!( + r#"{red_light}<{reset} +{red_light}<fan{reset} +{green_light}>mug{reset} +"#, + red_light = RED_LIGHT, + green_light = GREEN_LIGHT, + reset = RESET, + ); + + check_printer(write_lines, left, right, &expected); + } + + #[test] + fn trailing_added() { + let left = "fan"; + let right = "mug\n"; + let expected = format!( + r#"{red_light}<fan{reset} +{green_light}>mug{reset} +{green_light}>{reset} +"#, + red_light = RED_LIGHT, + green_light = GREEN_LIGHT, + reset = RESET, + ); + + check_printer(write_lines, left, right, &expected); + } + + /// Regression test for double abort + /// + /// See: https://github.com/rust-pretty-assertions/rust-pretty-assertions/issues/96 + #[test] + fn trailing_deleted() { + // The below inputs caused an abort via double panic + // we panicked at 'insertion followed by deletion' + let left = "fan\n"; + let right = "mug"; + let expected = format!( + r#"{red_light}<{reset}{red_heavy}fan{reset} +{green_light}>{reset}{green_heavy}mug{reset} +{red_light}<{reset} +"#, + red_light = RED_LIGHT, + red_heavy = RED_HEAVY, + green_light = GREEN_LIGHT, + green_heavy = GREEN_HEAVY, + reset = RESET, + ); + + check_printer(write_lines, left, right, &expected); + } + } } |