1 //! # Pretty Assertions
2 //!
3 //! When writing tests in Rust, you'll probably use `assert_eq!(a, b)` _a lot_.
4 //!
5 //! If such a test fails, it will present all the details of `a` and `b`.
6 //! But you have to spot the differences yourself, which is not always straightforward,
7 //! like here:
8 //!
9 //! ![standard assertion](https://raw.githubusercontent.com/colin-kiegel/rust-pretty-assertions/1a7feb17e1dfbeabfac91b0d5a9cb78dfb1bc065/examples/standard_assertion.png)
10 //!
11 //! Wouldn't that task be _much_ easier with a colorful diff?
12 //!
13 //! ![pretty assertion](https://raw.githubusercontent.com/colin-kiegel/rust-pretty-assertions/1a7feb17e1dfbeabfac91b0d5a9cb78dfb1bc065/examples/pretty_assertion.png)
14 //!
15 //! Yep — and you only need **one line of code** to make it happen:
16 //!
17 //! ```rust,ignore
18 //! use pretty_assertions::{assert_eq, assert_ne};
19 //! ```
20 //!
21 //! <details>
22 //! <summary>Show the example behind the screenshots above.</summary>
23 //!
24 //! ```rust,ignore
25 //! // 1. add the `pretty_assertions` dependency to `Cargo.toml`.
26 //! // 2. insert this line at the top of each module, as needed
27 //! use pretty_assertions::{assert_eq, assert_ne};
28 //!
29 //! fn main() {
30 //!     #[derive(Debug, PartialEq)]
31 //!     struct Foo {
32 //!         lorem: &'static str,
33 //!         ipsum: u32,
34 //!         dolor: Result<String, String>,
35 //!     }
36 //!
37 //!     let x = Some(Foo { lorem: "Hello World!", ipsum: 42, dolor: Ok("hey".to_string())});
38 //!     let y = Some(Foo { lorem: "Hello Wrold!", ipsum: 42, dolor: Ok("hey ho!".to_string())});
39 //!
40 //!     assert_eq!(x, y);
41 //! }
42 //! ```
43 //! </details>
44 //!
45 //! ## Tip
46 //!
47 //! Specify it as [`[dev-dependencies]`](http://doc.crates.io/specifying-dependencies.html#development-dependencies)
48 //! and it will only be used for compiling tests, examples, and benchmarks.
49 //! This way the compile time of `cargo build` won't be affected!
50 //!
51 //! Also add `#[cfg(test)]` to your `use` statements, like this:
52 //!
53 //! ```rust,ignore
54 //! #[cfg(test)]
55 //! use pretty_assertions::{assert_eq, assert_ne};
56 //! ```
57 //!
58 //! ## Note
59 //!
60 //! * Since `Rust 2018` edition, you need to declare
61 //!   `use pretty_assertions::{assert_eq, assert_ne};` per module.
62 //!   Before you would write `#[macro_use] extern crate pretty_assertions;`.
63 //! * The replacement is only effective in your own crate, not in other libraries
64 //!   you include.
65 //! * `assert_ne` is also switched to multi-line presentation, but does _not_ show
66 //!   a diff.
67 
68 extern crate ansi_term;
69 extern crate difference;
70 
71 #[cfg(windows)]
72 extern crate ctor;
73 #[cfg(windows)]
74 extern crate output_vt100;
75 
76 mod format_changeset;
77 
78 use difference::Changeset;
79 use std::fmt::{self, Debug, Display};
80 
81 use crate::format_changeset::format_changeset;
82 pub use ansi_term::Style;
83 
84 #[cfg(windows)]
85 use ctor::*;
86 #[cfg(windows)]
87 #[ctor]
init()88 fn init() {
89     output_vt100::try_init().ok(); // Do not panic on fail
90 }
91 
92 #[doc(hidden)]
93 pub struct Comparison(Changeset);
94 
95 impl Comparison {
new<TLeft: Debug, TRight: Debug>(left: &TLeft, right: &TRight) -> Comparison96     pub fn new<TLeft: Debug, TRight: Debug>(left: &TLeft, right: &TRight) -> Comparison {
97         let left_dbg = format!("{:#?}", *left);
98         let right_dbg = format!("{:#?}", *right);
99         let changeset = Changeset::new(&left_dbg, &right_dbg, "\n");
100 
101         Comparison(changeset)
102     }
103 }
104 
105 impl Display for Comparison {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result106     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107         format_changeset(f, &self.0)
108     }
109 }
110 
111 #[macro_export]
112 macro_rules! assert_eq {
113     ($left:expr , $right:expr,) => ({
114         assert_eq!($left, $right)
115     });
116     ($left:expr , $right:expr) => ({
117         match (&($left), &($right)) {
118             (left_val, right_val) => {
119                 if !(*left_val == *right_val) {
120                     panic!("assertion failed: `(left == right)`\
121                           \n\
122                           \n{}\
123                           \n",
124                            $crate::Comparison::new(left_val, right_val))
125                 }
126             }
127         }
128     });
129     ($left:expr , $right:expr, $($arg:tt)*) => ({
130         match (&($left), &($right)) {
131             (left_val, right_val) => {
132                 if !(*left_val == *right_val) {
133                     panic!("assertion failed: `(left == right)`: {}\
134                           \n\
135                           \n{}\
136                           \n",
137                            format_args!($($arg)*),
138                            $crate::Comparison::new(left_val, right_val))
139                 }
140             }
141         }
142     });
143 }
144 
145 #[macro_export]
146 macro_rules! assert_ne {
147     ($left:expr, $right:expr) => ({
148         assert_ne!(@ $left, $right, "", "");
149     });
150     ($left:expr, $right:expr,) => ({
151         assert_ne!(@ $left, $right, "", "");
152     });
153     ($left:expr, $right:expr, $($arg:tt)+) => ({
154         assert_ne!(@ $left, $right, ": ", $($arg)+);
155     });
156     (@ $left:expr, $right:expr, $maybe_semicolon:expr, $($arg:tt)+) => ({
157         match (&($left), &($right)) {
158             (left_val, right_val) => {
159                 if *left_val == *right_val {
160                   let left_dbg = format!("{:?}", *left_val);
161                   let right_dbg = format!("{:?}", *right_val);
162                   if left_dbg != right_dbg {
163 
164                       panic!("assertion failed: `(left != right)`{}{}\
165                             \n\
166                             \n{}\
167                             \n{}: According to the `PartialEq` implementation, both of the values \
168                               are partially equivalent, even if the `Debug` outputs differ.\
169                             \n\
170                             \n",
171                              $maybe_semicolon,
172                              format_args!($($arg)+),
173                              $crate::Comparison::new(left_val, right_val),
174                              $crate::Style::new()
175                                  .bold()
176                                  .underline()
177                                  .paint("Note"))
178                   }
179 
180                   panic!("assertion failed: `(left != right)`{}{}\
181                         \n\
182                         \n{}:\
183                         \n{:#?}\
184                         \n\
185                         \n",
186                          $maybe_semicolon,
187                          format_args!($($arg)+),
188                          $crate::Style::new().bold().paint("Both sides"),
189                          left_val)
190                 }
191             }
192         }
193     });
194 }
195