More flexible `assert_eq` for structs in unit tests?

I'm wondering if there is a more flexible matching pattern/crate/approach for asserts in unit tests.

In particular I often have cases where I want to assert against just a few fields of a big/deep struct. And I'd like to do it in a readable way... so it's clear what the test is testing. For example say I have a vec of items represented by this debug string:

[
    Item {
        id: 1,
        children: []
        ...
    }
    Item {
        id: 2,
        children: []
        ...
    }
    ...
]

Each item might have lots of fields, but for this particular test I only care that each item has a proper id. Is there an easy to read way that I can express this for unit tests? I imagine some sort of "matches" syntax like this would be ideal:

assert_matches!(vec, [ Item { id: 1 }, Item { id: 2 } ]);

Does such a thing or some alternative exist?

Thanks,
Jesse

1 Like

To give an example:

use assert_matches::assert_matches;

#[derive(Debug)]
struct Item {
    id: i32,
    children: Vec<()>,
}

fn main() {
    let v = vec![
        Item {
            id: 1,
            children: vec![],
        },
        Item {
            id: 2,
            children: vec![],
        },
    ];

    assert_matches!(*v, [Item { id: 1, .. }, Item { id: 2, .. }]);
}
1 Like

Thank you! That's exactly what I was looking for, an even with same name, eek.

You might not believe it, but I did search around for some such thing for a while before posting. Unfortunately none of my my searches included "assert_matches". Thanks again!

Is there a syntax to match within array within struct? For example when I try:

assert_matches!(*v, [Item { id: 1, .. }, Item { id: 2, children: [ Item { id: 3, .. } ] } ]);

I get this error:

expected an array or slice, found `std::vec::Vec<()>`
pattern cannot match with input type `std::vec::Vec<()>`rustc(E0529

No, unfortunately patterns don’t support dereferencing with Deref/DerefMut traits. The best way would be to introduce a guard.

use assert_matches::assert_matches;

#[derive(Debug)]
struct Item {
    id: i32,
    children: Vec<Item>,
}

fn main() {
    let v = vec![
        Item {
            id: 1,
            children: vec![],
        },
        Item {
            id: 2,
            children: vec![Item {
                id: 3,
                children: vec![],
            }],
        },
    ];

    assert_matches!(*v, [Item { id: 1, .. }, Item { id: 2, children: ref c2 } ] if matches!(**c2, [ Item { id: 3, .. } ]));
    // or when, like above, only checking a single `children` field:
    assert_matches!(*v, [Item { id: 1, .. }, Item { id: 2, ref children } ] if matches!(**children, [ Item { id: 3, .. } ]));

    // also: lots of alternatives around `&`, `ref`, and `*` and `[..]`:
    assert_matches!(v[..], [Item { id: 1, .. }, Item { id: 2, children: ref c2 } ] if matches!(c2[..], [ Item { id: 3, .. } ]));
    assert_matches!(&v[..], [Item { id: 1, .. }, Item { id: 2, children: c2 } ] if matches!(&c2[..], [ Item { id: 3, .. } ]));
    assert_matches!(&*v, [Item { id: 1, .. }, Item { id: 2, children: c2 } ] if matches!(&**c2, [ Item { id: 3, .. } ]));
}
1 Like