blob: bee2159ba0607dd9f3904852c1e2b591431be474 [file] [log] [blame]
//! This crate defines a collection of useful utilities for testing rust code.
/// Asserts that an expression matches some expected pattern. The pattern may
/// be any valid rust pattern, which includes multiple patterns (`Foo | Bar`)
/// and an arm guard (`Foo::Bar(ref val) if val == "foo"`).
///
/// On panic, this macro will print the value of the input expression
/// using its debug representation, along with the expected pattern.
///
/// # Examples
///
/// ```
/// ##[derive(Debug)]
/// enum Foo {
/// Bar(String),
/// Baz,
/// }
///
/// # fn main() {
/// let a = Foo::Baz;
/// assert_matches!(a, Foo::Baz);
///
/// let b = Foo::Bar("foo".to_owned());
/// assert_matches!(b, Foo::Bar(ref val) if val == "foo");
/// # }
#[macro_export]
macro_rules! assert_matches {
($input:expr, $($pat:pat)|+) => {
match $input {
$($pat)|* => (),
_ => panic!(
r#"assertion failed: `(actual matches expected)`
actual: `{:?}`,
expected: `{}`"#,
&$input,
stringify!($($pat)|*)
),
};
};
($input:expr, $($pat:pat)|+ if $arm_guard:expr) => {
match $input {
$($pat)|* if $arm_guard => (),
_ => panic!(
r#"assertion failed: `(actual matches expected)`
actual: `{:?}`,
expected: `{} if {}`"#,
&$input,
stringify!($($pat)|*),
stringify!($arm_guard)
),
};
};
}
#[cfg(test)]
mod tests {
#[derive(Debug)]
enum Foo {
Bar(String),
Baz,
Bat,
}
#[test]
fn test_simple_match_passes() {
let input = Foo::Bar("foo".to_owned());
assert_matches!(input, Foo::Bar(_));
}
#[test]
#[should_panic]
fn test_simple_match_fails() {
let input = Foo::Baz;
assert_matches!(input, Foo::Bar(_));
}
#[test]
fn test_match_with_arm_guard_passes() {
let input = Foo::Bar("foo".to_owned());
assert_matches!(input, Foo::Bar(ref val) if val == "foo");
}
#[test]
#[should_panic]
fn test_match_with_arm_guard_fails() {
let input = Foo::Bar("foo".to_owned());
assert_matches!(input, Foo::Bar(ref val) if val == "bar");
}
#[test]
fn test_match_with_multiple_patterns_passes() {
let input = Foo::Bar("foo".to_owned());
assert_matches!(input, Foo::Bar(_) | Foo::Baz);
}
#[test]
#[should_panic]
fn test_match_with_multiple_patterns_fails() {
let input = Foo::Bat;
assert_matches!(input, Foo::Bar(_) | Foo::Baz);
}
#[test]
fn test_match_with_multiple_patterns_and_arm_guard_passes() {
let input = Foo::Bar("foo".to_owned());
assert_matches!(input, Foo::Bar(_) | Foo::Baz if true);
}
#[test]
#[should_panic]
fn test_match_with_multiple_patterns_and_arm_guard_fails() {
let input = Foo::Bat;
assert_matches!(input, Foo::Bar(_) | Foo::Baz if false);
}
#[test]
fn test_assertion_does_not_consume_input() {
let input = Foo::Bar("foo".to_owned());
assert_matches!(input, Foo::Bar(_));
if let Foo::Bar(ref val) = input {
assert_eq!(val, "foo");
}
}
}