-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add custom message parameter to assert_eq!
#33976
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @brson (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Nice! Squash your commits please. |
25efb26
to
a460e49
Compare
@GuillaumeGomez Thanks. Squashed them. |
It's good for me but I'd prefer to let someone from @rust-lang/core team to review it as well. |
Yes, @rust-lang/lang and @rust-lang/libs should probably sign off on something like this. |
related rfc issue: rust-lang/rfcs#1604 |
Oops. I should've checked the issue... |
Is there any reason to use: assert_eq!("b", xs[i], "xs[{}] should be \"b\" but {}", i, xs[i]); rather than: assert!("b" == xs[i], "xs[{}] should be \"b\" but {}", i, xs[i]); ? |
@ollie27 Not that I can think of, since the reason |
@ollie27 I prefer In major unit test libraries (e.g. JUnit in Java, OUnit in OCaml and Test::Unit in Ruby) in other languages, there are |
+1 |
@brson @GuillaumeGomez Well, should I close this PR...? |
I agree with @brson, it's simplest to just use |
Like @komamitsu, I have mostly used |
Well, maybe another way to put it is that I got in the habit of using |
@nikomatsakis good point that having the error message reduces the surprise factor |
to clarify, +1 to the PR itself - while I understand the argument that assert_eq should do its own thing for the error message, I don't see that as the point of the macro - aiui, assert_eq just saves you writing |
As I wrote in rust-lang/rfcs#1604, I think the panic message given to IMO the point of |
OK, @nikomatsakis makes a convincing case that it's worth adding something here. @SimonSapin's suggestion makes sense for added value. cc @rust-lang/libs |
I feel that as-is this may not add too much value as it's shorter even to use |
Thanks for the feedbacks. I agree to appending a custom message to the default one. I have two ideas to do that. macro_rules! assert_eq {
($left:expr , $right:expr) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!("assertion failed: `(left == right)` \
(left: `{:?}`, right: `{:?}`)", left_val, right_val)
}
}
}
});
($left:expr , $right:expr, $msg:expr) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!("assertion failed: `(left == right)` \
(left: `{:?}`, right: `{:?}`): {}", left_val, right_val, $msg)
}
}
}
});
($left:expr , $right:expr, $fmt:expr, $($arg:tt)*) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!(concat!("assertion failed: `(left == right)` \
(left: `{:?}`, right: `{:?}`): ", $fmt),
left_val, right_val, $($arg)*)
}
}
}
});
}
// assert_eq!(1, 2); >>> assertion failed: `(left == right)` (left: `1`, right: `2`)
// assert_eq!(1, 2, "Type is u32");
// >>> assertion failed: `(left == right)` (left: `1`, right: `2`): Type is u32
// assert_eq!(1, 2, "concurrency = {concurrency}, counter = {counter}",
// concurrency = c, counter = i);
// >>> assertion failed: `(left == right)` (left: `1`, right: `2`): concurrency = 8, counter = 65536 macro_rules! assert_eq {
($left:expr , $right:expr) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!("assertion failed: `(left == right)` \
(left: `{:?}`, right: `{:?}`)", left_val, right_val)
}
}
}
});
($left:expr , $right:expr, $msg:expr) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!("assertion failed: `(left == right)` \
(left: `{:?}`, right: `{:?}`): {}", left_val, right_val, $msg)
}
}
}
});
}
// assert_eq!(1, 2); >>> assertion failed: `(left == right)` (left: `1`, right: `2`)
// assert_eq!(1, 2, "Type is u32");
// >>> assertion failed: `(left == right)` (left: `1`, right: `2`): Type is u32
// assert_eq!(1, 2, format!("concurrency = {concurrency}, counter = {counter}",
// concurrency = c, counter = i));
// >>> assertion failed: `(left == right)` (left: `1`, right: `2`): concurrency = 8, counter = 65536 The first one can format strings by itself, but it's a bit verbose. The implementation of the second one is simpler, but it doesn't support formatting. I'm wondering which one is better... |
Ah yeah I'd vote for the first where the message itself can have more arguments and such like |
a460e49
to
7e0aa04
Compare
Updated the PR |
(left_val, right_val) => { | ||
if !(*left_val == *right_val) { | ||
panic!("assertion failed: `(left == right)` \ | ||
(left: `{:?}`, right: `{:?}`): {}", left_val, right_val, $msg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be worth using concat!
here as well to ensure that a $msg
which looks like "foo {}"
gives an error saying that it expected an argument rather than being accepted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this was trying to match unreachable!
which can also be given a single argument which implements Display
and use that. If we don't want that behaviour and only accept valid format strings I think we can use a single extra rule like:
($left:expr , $right:expr, $($arg:tt)*) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!("assertion failed: `(left == right)` \
(left: `{:?}`, right: `{:?}`): {}", left_val, right_val, format_args!($($arg)*))
}
}
}
});
This will also accept things like assert_eq!(1, 2, "{0}", 3)
which I think we do want to accept.
(also we definitely don't want to use concat!
as we'll just run into #30143 again)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That definition looks good to me!
The libs team got a chance to discuss this PR during triage today and the conclusion was to merge. @komamitsu if you want to update with @ollie27's suggestion, I'll r+! |
7e0aa04
to
45a63d3
Compare
@ollie27 Thanks. That's what I wanted to do. @alexcrichton Okay. Updated the PR |
@bors: retry force clean
|
💣 Buildbot returned an error: |
⌛ Testing commit 45a63d3 with merge a32aaea... |
@bors: retry force clean
|
Add custom message parameter to `assert_eq!` `assert!` macro accepts a custom message parameter and it's sometimes useful. But `assert_eq!` doesn't have it and users need to use `assert!` instead of `assert_eq!` when they want to output a custom message even if the assertion just compares two values. This pull request will resolve those cases.
@alexcrichton Thanks! |
Is this mentioned somewhere in the docs? I looked here and thought it would not be possible to append a custom message. I'm glad it is possible. |
@donaldpipowitch: You must look into the nightly docs: https://doc.rust-lang.org/nightly/std/macro.assert_eq.html |
Okay, Thank you. |
assert!
macro accepts a custom message parameter and it's sometimes useful. Butassert_eq!
doesn't have it and users need to useassert!
instead ofassert_eq!
when they want to output a custom message even if the assertion just compares two values. This pull request will resolve those cases.