Assert! and destructuring


#1

More than once, I come across the situation where I want to test multiple fields of some struct, but not all of them.

Say we have the following code.

struct MyStruct {
    x: u8,
    y: u8,
    z: u8,
    b: BigStruct,
}

struct BigStruct;

fn f() -> MyStruct {
    MyStruct { x: 0, y: 1, z: 42, b: BigStruct }
}

Now, we want to assert the x, y and z fields of the return value of f() without comparing the b field (either because it’s too much of a hassle to create it for the purpose of this test or it’s not worth testing or some other reason).
I can think of three ways of doing this.

let r = f();
assert!(r.x == 0);
assert!(r.y == 1);
assert!(r.z == 42);
if let MyStruct { x: 0, y: 1, z: 42, .. } = f() {
} else {
    panic!("assertion failed: let MyStruct { x: 0, y: 1, z: 42, .. } = f()");
}
match f() {
    MyStruct { x: 0, y: 1, z: 42, .. } => (),
    _ => panic!("assertion failed: MyStruct { x: 0, y: 1, z: 42, .. } == f()"),
}

All of these options feel a bit cumbersome as they all take up 4 lines. I was wondering whether perhaps a macro or another clean solution exists for this. Something like (although this makes no syntactic sense):

assert!(let MyStruct { x: 0, y: 1, z: 42, .. } = f())

Example on Rust Playground


#2

I don’t think something exists, but you could write one if you need this (and don’t care about knowing which part of assertion failed ).


#3

You’re right. After writing this, I implemented the following macro

macro_rules! assert_let {
    ($left:pat = $right:expr) => (
        if let $left = $right {} else {
            panic!("assertion failed: let {:?} = {:?}", stringify!($left), stringify!($right))
        }
    )
}

It can be used as assert_let!(MyStruct { x: 0, y: 1, z: 42, .. } = f()).
Does this look all right?

I am wondering if there are others who feel this same need. Or if not, I wonder why.


#4

The need certainly exists. There are various assert_matches! or similar name macros in crates.io. https://crates.io/crates/assert_matches


#5

Thank you, @bluss! That crate does indeed exactly that.

(It is the only one that I can find that does that. Maybe I overlooked something.)