I'm writing some tests for a language tokenizer and I'm comparing a JSON-serialized version of the tokenization produced by the tokenizer with a serialization of a known-good tokenization. So I have some tests like this:
#[test]
fn test_tokenize() {
let actual_token_json = /* string */;
let expected_token_json = /* string */;
assert_eq!(actual_token_json, expected_token_json);
}
However, when those tests fail, cargo test
just says that the JSON strings weren't equal and prints them both out, which isn't that useful. Since the JSON strings are both pretty-printed, it would be more helpful if cargo test
printed out a line diff of the two strings. Is there any way I could do this?
Update: Someone edited the title of this post but deleted an important piece of information: I'm looking for a line diff when two strings aren't equal. One of the answers I'm seeing here is for the more general question of getting a line and character diff of the debug representations of two values when they're not equal. That's either more than I need or not what I need. For example, the diff of the debug representations of two strings won't give me a line diff but a large, convoluted character diff (since the lines show up in the debug representation as escaped "\n" tokens).
Yes, but not with the assert_eq
macro provided by the standard library†. You could use the pretty_assertions
crate which was designed to do exactly what you are looking for.
† Actually, the built-in macro could take more than two arguments to provide more information about the assertion by extending it with a custom message. So technically, if you provide some sort of diff'ing implementation yourself or an external one, which is either Display
or Debug
, you could then pass it to the macro. Strictly speaking in some ways this macro is also usable for such a thing.
See the update in my post as to why pretty_assertions
doesn't quite work for my particular problem. Instead, I ended up just using the difference
library that pretty_assertions
uses internally. I just made a wrapper struct for difference::Changeset
so that I could override its fmt::Display
implementation:
fn prefix_lines(prefix: &str, lines: &str) -> String {
lines
.lines()
.map(|i| [prefix, i].concat())
.collect::<Vec<String>>()
.join("\n")
}
pub struct Diff(difference::Changeset);
impl Diff {
pub fn new(left: &str, right: &str) -> Self {
Self(difference::Changeset::new(left, right, "\n"))
}
}
impl fmt::Display for Diff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for d in &self.0.diffs {
match *d {
difference::Difference::Same(ref x) => {
write!(f, "{}{}", prefix_lines(" ", x), self.0.split)?;
}
difference::Difference::Add(ref x) => {
write!(f, "\x1b[92m{}\x1b[0m{}", prefix_lines("+", x), self.0.split)?;
}
difference::Difference::Rem(ref x) => {
write!(f, "\x1b[91m{}\x1b[0m{}", prefix_lines("-", x), self.0.split)?;
}
}
}
Ok(())
}
}
Then I just have a macro, as in the pretty_assertions
implementation, that creates an instance of that struct and string formats it inside of a panic message when the assertion fails.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With