📣 `assert_eq!` with colorful diff (drop-in replacement)


#1

Welcome: 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:

Wouldn’t that task be much easier with a colorful diff?

Yep — and you only need one line of code to make it happen:

#[macro_use] extern crate pretty_assertions;
Show the example behind the screenshots above.
// 1. add the `pretty_assertions` dependency to `Cargo.toml`.
// 2. insert this line at the top of your crate root or integration test
#[macro_use] extern crate pretty_assertions;

fn main() {
    #[derive(Debug, PartialEq)]
    struct Foo {
        lorem: &'static str,
        ipsum: u32,
        dolor: Result<String, String>,
    }

    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-dependency] and it will only be used for compiling tests, examples, and benchmarks. This way the compile time of cargo build won’t be affected!

In your crate root, also add #[cfg(test)] to the crate import, like this:

#[cfg(test)] // <-- not needed in examples + integration tests
#[macro_use]
extern crate pretty_assertions;

Note

  • Each example and integration test also needs #[macro_use] extern crate pretty_assertions, if you want colorful diffs there.
  • The replacement is only effective in your own crate, not in other libraries you include.
  • pretty_assertions is an ultra-thin wrapper around the
    difference crate, which does the heavy lifting. All that pretty_assertions does is to replace theassert_eq! macro with just about 22 lines of code.

#2

PS: If you like pretty_assertions, you will probably also like the assert_cli crate by @killercup — which was the source of inspiration here and also provides colorful diffs. :slight_smile:


#3

omg. as someone who is working on a project with huge data structures being used in tests, I am very excited about trying this out. Thanks for putting it together!


#4

Do the colors show under Windows?


#5

Good question. That might depend on whether you use powershell or command prompt, but I don’t know. I’d be happy to hear it from someone. :slight_smile:


#6

It doesn’t seem so, because the underlying difference crate simply prints ANSI escape codes. It should be converted to use term to be cross-platform.


#7

Thx for the hint. I created a ticket for cross-platform support + no-color-fallback. :slight_smile:


#8

I think Windows 10 handles ANSI code colors. But I never tried.
EDIT: Apparently it works.


#9

I saw this and bookmarked it for later. Looked cool and if I really needed this, I would come back to it and use it.
I refactored some functions to return different structs in my project.
Took one look at the struct assertions and noped right back to this page.
This made it so much faster and easier to update my unit tests.

Thank you for creating this and sharing it.


#10

:fireworks: Multi-line Display :fireworks:

Rust built-in assert_eq macro will soon introduce multi-line display via RFC #1866.

With pretty_assertions (v0.2) you can have that today:


#11

:champagne: pretty, prettier, …v0.3.0 :clinking_glasses:

pretty_assertions (v0.3) switches to a new format, which is basically a line-based diff of the pretty printed Debug format. Especially for nested structs this should hopefully be even more helpful:

Let me know, if you want to switch between different formats, or have any other suggestion.

Kudos to github.com/fflorent.


#12

I’m quite impressed with the compactness of v0.2.0, but the multi-line, formatted style of v0.3.0 is very tempting…

My only concern is that it requires “skill” in reading version-control diffs…
Then again programming without that skill would be like a carpenter who didn’t know how to hold a screwdriver…

I do have one improvement suggestion though: the “+/-” makes a lot of sense in VCS diffs, because the timeline has an intrinsic “added/removed since previous version” semantic.
With assertions however, there is very much an equality: It would make just as much sense if you flipped the signs…
(You can see this in the legend you have just after “Diff”: you have to explain that minus==left/plus==right)

how about “</>” instead? (or even, embracing Rust’s unicode fanciness: “⏵⏴”, “⭨⭩”)
That associates better with the “left/right” variable names you use in the example, and it’s intuitive enough that you could even skip the +/- legend after “Diff” (minimalism!)


#13

I would agree with juleskers that the (+/-) idiom although probably well known to all of us is maybe not the right one here as there is nothing to be added or was removed. I would even go for just Diff(left|right) in the right colours.
Otherwise, it really looks cool and the multi-line looks so beautiful that this maybe some day should be part of the native cargo test.


#14

Great idea, I replaced the -/+ signs with ⮜/⮞. That should improve the readability further. And in case some terminal or font doesn’t support these, there is still the coloring.

v0.3.1 now looks like this


#15

:smiley: might be pretentious but I would do (< left / right >) … or maybe is my inner symmetry self-speaking.


#16

ok, done. :slight_smile:


#17

Ooh, looks great in the picture! :heart:

Funnily enough, my mobile seems to have trouble with all of my fancy unicode suggestions: in the email notifications they were crossed-out squares, in web-view they just look like solid black blocks.

I wonder how unicode-compliant most terminals are… it would be nice to ensure a nice fallback, if even modern phones using the latest Firefox/Gmail are struggling…


#18

Yep, I’ll play wait and see here. :wink:

If it reigns complaints it will be easy to try different symbols. Plus, the signs are redundant with the coloring.


#19

Just out of curiosity, is there any hope of this beautiful thing being eventually integrated into the standard library assertion mechanism? :slight_smile:


#20

Hm, I don’t know. :slight_smile:

This would require an RFC first, like this one: 1866.

Some questions around integrating this might be:

  • Should this be opt-in, or the default?
  • Is this always an improvement, or are there use cases when showing a diff only is actually a disadvantage?
  • Does it still look nice, if the lines get very long, the structs deeply nested, etc.?
  • Should the output be different, when printing in JSON format (-> RLS / IDEs) instead of human readable format?