Macro cool_asserts::assert_matches
source · [−]macro_rules! assert_matches {
(
$expression:expr,
[
$($($name:ident)+ @)? .. $(if $guard:expr)? $(=> $block:expr)? $(,)?
] $($tail:tt)*
) => { ... };
(
$expression:expr,
[
$($patterns:tt)*
] $(if $guard:expr)? => $block:expr
$(, $( $fmt_pattern:literal $($fmt_arg:tt)* )? )?
) => { ... };
(
$expression:expr,
[
$($patterns:tt)*
]
$(, $( $fmt_pattern:literal $($fmt_arg:tt)* )? )?
) => { ... };
(
$expression:expr,
$pattern:pat $(if $guard:expr)? $(=> $block:expr)?
$(, $( $fmt_pattern:literal $($fmt_arg:tt)* )? )?
) => { ... };
}
Expand description
Assert that the value of an expression matches a given pattern.
This assertion checks that the value of an expression matches a pattern. It panics if the expression does not match.
Optionally, provide a block with => { <block> }
; the block will be run
with the matched pattern if the match was successful. This allows running
additional assertions on the matched pattern, or returning values to the
caller of assert_matches
You can also add a trailing format message that will be included with
the panic in the event of an assertion failure, just like with
assert_eq!
.
Example
use cool_asserts::{assert_matches, assert_panics};
assert_panics!{
assert_matches!(Some(10), None),
includes("value does not match pattern"),
}
assert_matches!(Some(10), Some(x) => {
assert_eq!(x, 10);
});
// assert_matches can return a value
let x = assert_matches!(Some(10), Some(x) => x);
assert_eq!(x, 10);
Iteratables
assert_matches
can handle matching on iterables. If the pattern is a [..]
slice pattern, the test value is treated as an iterable, and each item in the
iterator is matched against the corresponding item in the pattern:
use cool_asserts::assert_matches;
let data = vec![5, 5].into_iter().chain(Some(4)).enumerate();
assert_matches!(data, [(0, 5), (1, 5), (2, 4)]);
In addition to matching the patterns themselves, the iterator must also
precisely match the length of the [ .. ]
iterator pattern. If the iterator
is too long, assert_matches
will helpfully include the first item that was
in excess of the pattern’s length, as well as the total length of the iterator
use cool_asserts::{assert_matches, assert_panics};
assert_panics!(
assert_matches!(vec!['a', 'b', 'c', 'd'], ['a', 'b']),
includes("too long"),
includes("actual_length: 4"),
includes("expected_length: 2"),
includes("first_overflow: 'c'"),
);
assert_panics!(
assert_matches!(vec!['a'], ['a', 'b', 'c']),
includes("too short"),
includes("actual_length: 1"),
includes("expected_length: 3"),
);
When used in this way, you can use multiple => { block }
arms inside
the iterator pattern. Each block will be evaluated in order, and a tuple
containing all the block results will be returned from assert_matches!
. Like
with a regular pattern, you can also include an if
guard:
use cool_asserts::assert_matches;
let data = 1..6;
let (a, (), c) = assert_matches!(data, [
a => a + 1,
b => { assert_eq!(b, 2); },
3,
4,
c if c > 2 => c,
]);
assert_eq!(a, 2);
assert_eq!(c, 5);
Just like with regular slice patterns, you can use ..
inside the pattern to
match all the items except for those at the beginning and end:
use std::iter;
use cool_asserts::assert_matches;
assert_matches!(vec![0, 1, 2, 3, 4, 5], [0, .., 5]);
assert_matches!(vec![0, 1, 2, 3, 4, 5], [.., 4, 5]);
// It supports infinite iterators as long as the
// last pattern in the match is ..
assert_matches!(iter::repeat(3), [3, 3, 3, ..]);
Also like with regular slice patterns, you can bind a name to this middle
pattern and use it in the => block
. However, because assert_matches!
is
matching any iterable rather than a slice, the value will itself be an
Iterator
containing all the middle elements, rather than a subslice:
use cool_asserts::assert_matches;
let data = vec![1, 1, 2, 2, 2, 2, 3, 3];
let (middle_sum,) = assert_matches!(
data,
[
1,
1,
middle @ .. => middle.reduce(|a, b| a + b),
3,
3,
]
);
assert_eq!(middle_sum, Some(8));