Allow renaming left/right label in assert_eq!

Now that assert_eq! output has been cleaned up, I would like to propose that we allow renaming of the labels left and right into something more meaningful. Some design ideas:

assert_eq2!(# expected = 1, actual = 2);
assert_eq2!(@ left = "expected value", right = "  actual value", 1, 2);

Output:

assertion `left == right` failed
expected: 1
actual: 2
assertion `left == right` failed
expected value: 1
  actual value: 2

Possible implementation, renamed for testing purposes

macro_rules! assert_eq2 {
    (# $left_label:ident = $left:expr, $right_label:ident = $right:expr $(,)?) => {{
        assert_eq!($left, $right, "{} != {}", stringify!($left_label), stringify!($right_label))
    }};
    (@ left = $left_label:literal, right = $right_label:literal, $left:expr, $right:expr $(,)?) => {{
        assert_eq!($left, $right, "{} != {}", $left_label, $right_label)
    }};
    ($($arg:tt)*) => {{
        assert_eq!($($arg)+)
    }};
}

Is there a situation where the expected vs. actual isn't clear when looking at the source code of the test? And if there is, should there be?

A cleverer and automatic option would be to print the identifiers given to the macro, if noncomplex expressions are provided. I.e. if you say assert_eq!(expected, actual), have the error be

thread 'main' panicked at src/main.rs:4:5:
assertion `expected == actual` failed
 expected: 1
   actual: 2
1 Like

@CAD97 I tried that as part of the https://github.com/rust-lang/rust/pull/111030 -- it caused compiling performance regression by 1.1% - not something we would like to have just for the prettier names

1 Like

I'd expect (heh) that manually repeating "expected" and "actual" in every assert_eq call would get old pretty fast when writing tests, prompting people to write their own shortcut macros anyway (expect_eq?) Half the people would probably prefer (expected, actual) and the other half (actual, expected), though…

1 Like

In practice, a lot of asserts in my nearest code base already look like:

assert_eq!(computed_value, "Hand-written value that should be the same");

or

const expected: &str = "Hand-written value that should be the same");
/* More code here */
assert_eq!(expected, task.output);

If it could be done cheaply enough (and @nyurik's attempt suggests it can't), then it'd be nice to have the first line of those classes of assert become:

assertion `computed_value == <literal>` failed

and

assertion `expected == task.output` failed

But that depends on it being cheap enough - I'd have to look at the code anyway to diagnose the problem, and once I'm used to left == right, it's easy enough to spot the error.

1 Like

In my experience, it is valuable in large code bases for test failures to be at least somewhat comprehensible without reference to the source code. This way you can read a list of test failures (which may be in modules quite distant from what you were editing) and assemble from them an understanding of what property you broke, without having to read the code of each of those tests (which may push what you were working on out of short term memory).

4 Likes

I wonder if it would be possible for assert_eq! to match the parameter variable names as keywords, and act accordingly?

  • assert_eq!(expected, <expr>)
  • assert_eq!(expect, <expr>)
  • assert_eq!(actual, <expr>)
  • assert_eq!(<expr>, expected)
  • assert_eq!(<expr>, expect)
  • assert_eq!(<expr>, actual)

So if any of the above patterns are used, assert_eq! would use those instead of left vs right. This would only solve the common case of expected vs actual values.

The issue with the above is that if a macro treats expected as a keyword parameter, I have no way for the macro content to use that as a variable I think

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.