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