//! # Pretty Assertions //! //! When writing tests in Rust, you'll probably use `assert_eq!(a, b)` _a lot_. //! //! If such a test fails, it will present all the details of `a` and `b`. //! 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) //! //! 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) //! //! Yep — and you only need **one line of code** to make it happen: //! //! ```rust //! use pretty_assertions::{assert_eq, assert_ne}; //! ``` //! //!
//! Show the example behind the screenshots above. //! //! ```rust,should_panic //! // 1. add the `pretty_assertions` dependency to `Cargo.toml`. //! // 2. insert this line at the top of each module, as needed //! use pretty_assertions::{assert_eq, assert_ne}; //! //! #[derive(Debug, PartialEq)] //! struct Foo { //! lorem: &'static str, //! ipsum: u32, //! dolor: Result, //! } //! //! let x = Some(Foo { lorem: "Hello World!", ipsum: 42, dolor: Ok("hey".to_string())}); //! let y = Some(Foo { lorem: "Hello Wrold!", ipsum: 42, dolor: Ok("hey ho!".to_string())}); //! //! assert_eq!(x, y); //! ``` //!
//! //! ## Tip //! //! Specify it as [`[dev-dependencies]`](http://doc.crates.io/specifying-dependencies.html#development-dependencies) //! and it will only be used for compiling tests, examples, and benchmarks. //! This way the compile time of `cargo build` won't be affected! //! //! Also add `#[cfg(test)]` to your `use` statements, like this: //! //! ```rust //! #[cfg(test)] //! use pretty_assertions::{assert_eq, assert_ne}; //! ``` //! //! ## Note //! //! * Since `Rust 2018` edition, you need to declare //! `use pretty_assertions::{assert_eq, assert_ne};` per module. //! Before you would write `#[macro_use] extern crate pretty_assertions;`. //! * The replacement is only effective in your own crate, not in other libraries //! you include. //! * `assert_ne` is also switched to multi-line presentation, but does _not_ show //! a diff. #![deny(clippy::all, missing_docs, unsafe_code)] pub use ansi_term::Style; use std::fmt::{self, Debug, Display}; mod printer; #[cfg(windows)] use ctor::*; #[cfg(windows)] #[ctor] fn init() { output_vt100::try_init().ok(); // Do not panic on fail } /// A comparison of two values. /// /// Where both values implement `Debug`, the comparison can be displayed as a pretty diff. /// /// ``` /// use pretty_assertions::Comparison; /// /// print!("{}", Comparison::new(&123, &134)); /// ``` /// /// The values may have different types, although in practice they are usually the same. pub struct Comparison<'a, TLeft, TRight> where TLeft: ?Sized, TRight: ?Sized, { left: &'a TLeft, right: &'a TRight, } impl<'a, TLeft, TRight> Comparison<'a, TLeft, TRight> where TLeft: ?Sized, TRight: ?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) -> Comparison<'a, TLeft, TRight> { Comparison { left, right } } } impl<'a, TLeft, TRight> Display for Comparison<'a, TLeft, TRight> where TLeft: Debug + ?Sized, TRight: Debug + ?Sized, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // To diff arbitary types, render them as debug strings let left_debug = format!("{:#?}", self.left); let right_debug = format!("{:#?}", self.right); // And then diff the debug output printer::write_header(f)?; printer::write_lines(f, &left_debug, &right_debug) } } /// 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!`]. /// You can provide a custom panic message if desired. /// /// # Examples /// /// ``` /// use pretty_assertions::assert_eq; /// /// let a = 3; /// let b = 1 + 2; /// assert_eq!(a, b); /// /// assert_eq!(a, b, "we are testing addition with {} and {}", a, b); /// ``` #[macro_export] macro_rules! assert_eq { ($left:expr , $right:expr,) => ({ $crate::assert_eq!($left, $right) }); ($left:expr , $right:expr) => ({ 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)) } } } }); ($left:expr , $right: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)) } } } }); } /// Asserts that two expressions are not equal to each other (using [`PartialEq`]). /// /// 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!`]. /// You can provide a custom panic message if desired. /// /// # Examples /// /// ``` /// use pretty_assertions::assert_ne; /// /// let a = 3; /// let b = 2; /// assert_ne!(a, b); /// /// assert_ne!(a, b, "we are testing that the values are not equal"); /// ``` #[macro_export] macro_rules! assert_ne { ($left:expr, $right:expr) => ({ $crate::assert_ne!(@ $left, $right, "", ""); }); ($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)+) => ({ 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)`{}{}\ \n\ \n{}:\ \n{:#?}\ \n\ \n", $maybe_semicolon, format_args!($($arg)+), $crate::Style::new().bold().paint("Both sides"), 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)` Diff < left / right > : <666 >999 "#)] fn fails() { crate::assert_eq!(666, 999); } #[test] #[should_panic(expected = r#"assertion failed: `(left == right)` Diff < left / right > : <666 >999 "#)] fn fails_trailing_comma() { crate::assert_eq!(666, 999,); } #[test] #[should_panic(expected = r#"assertion failed: `(left == right)` Diff < left / right > : [ 101, > 101, ] "#)] fn fails_unsized() { let a: &[u8] = b"e"; let b: &[u8] = b"ee"; crate::assert_eq!(*a, *b); } #[test] #[should_panic( expected = r#"assertion failed: `(left == right)`: custom panic message Diff < left / right > : <666 >999 "# )] fn fails_custom() { crate::assert_eq!(666, 999, "custom panic message"); } #[test] #[should_panic( expected = r#"assertion failed: `(left == right)`: custom panic message Diff < left / right > : <666 >999 "# )] fn fails_custom_trailing_comma() { crate::assert_eq!(666, 999, "custom panic message",); } } mod assert_ne { use ::std::string::{String, ToString}; #[test] fn passes() { let a = "a"; let b = "b"; crate::assert_ne!(a, b); } #[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)` Both sides: 666 "#)] fn fails() { crate::assert_ne!(666, 666); } #[test] #[should_panic(expected = r#"assertion failed: `(left != right)` Both sides: 666 "#)] fn fails_trailing_comma() { crate::assert_ne!(666, 666,); } #[test] #[should_panic(expected = r#"assertion failed: `(left != right)` Both sides: [ 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 Both sides: 666 "# )] fn fails_custom() { crate::assert_ne!(666, 666, "custom panic message"); } #[test] #[should_panic( expected = r#"assertion failed: `(left != right)`: custom panic message Both sides: 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)` Diff < left / right > : <-0.0 >0.0 Note: 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); } } }