macro_rules! matches_pattern {
($($t:tt)*) => { ... };
}Expand description
Matches a value according to a pattern of matchers.
This takes as an argument a specification similar to a struct or enum
initialiser, where each value is a Matcher
which is applied to the corresponding field.
This can be used to match arbitrary combinations of fields on structures using arbitrary matchers:
#[derive(Debug)]
struct MyStruct {
a_field: String,
another_field: String,
}
let my_struct = MyStruct {
a_field: "Something to believe in".into(),
another_field: "Something else".into()
};
verify_that!(my_struct, matches_pattern!(MyStruct {
a_field: starts_with("Something"),
another_field: ends_with("else"),
}))If any fields are provided in the pattern, then all fields must be
specified, or the pattern must end with .., just like regular match
patterns. Omitted fields have no effect on the output of the matcher.
The .. is unnecessary when no fields are provided and only method
values are checked.
verify_that!(my_struct, matches_pattern!(MyStruct {
a_field: starts_with("Something"),
.. // another_field is missing, so it may be anything.
}))One can use it recursively to match nested structures:
#[derive(Debug)]
struct MyStruct {
a_nested_struct: MyInnerStruct,
}
#[derive(Debug)]
struct MyInnerStruct {
a_field: String,
}
let my_struct = MyStruct {
a_nested_struct: MyInnerStruct { a_field: "Something to believe in".into() },
};
verify_that!(my_struct, matches_pattern!(MyStruct {
a_nested_struct: matches_pattern!(MyInnerStruct {
a_field: starts_with("Something"),
}),
}))One can use the alias pat to make this less
verbose:
verify_that!(my_struct, matches_pattern!(MyStruct {
a_nested_struct: pat!(MyInnerStruct {
a_field: starts_with("Something"),
}),
}))In addition to fields, one can match on the outputs of methods (“properties”):
#[derive(Debug)]
struct MyStruct {
a_field: String,
}
impl MyStruct {
fn get_a_field(&self) -> String { self.a_field.clone() }
}
let my_struct = MyStruct { a_field: "Something to believe in".into() };
verify_that!(my_struct, matches_pattern!(MyStruct {
get_a_field(): starts_with("Something"),
}))If an inner matcher is eq(...), it can be omitted:
#[derive(Debug)]
struct MyStruct {
a_field: String,
another_field: String,
}
let my_struct = MyStruct {
a_field: "this".into(),
another_field: "that".into()
};
verify_that!(my_struct, matches_pattern!(MyStruct {
a_field: "this",
another_field: "that",
}))Important: The method should be pure function with a deterministic output and no side effects. In particular, in the event of an assertion failure, it will be invoked a second time, with the assertion failure output reflecting the second invocation.
These may also include extra litteral parameters you pass in:
impl MyStruct {
fn append_to_a_field(&self, suffix: &str) -> String { self.a_field.clone() + suffix }
}
verify_that!(my_struct, matches_pattern!(&MyStruct {
append_to_a_field("a suffix"): ref ends_with("a suffix"),
}))You can precede both field and property matchers with a ref to match the
result by reference:
impl MyStruct {
fn get_a_field_ref(&self) -> String { self.a_field.clone() }
}
verify_that!(my_struct, matches_pattern!(&MyStruct {
get_a_field_ref(): ref starts_with("Something"),
}))Note that if the actual is of type &ActualT and the pattern type is
ActualT, this is automatically performed. This behavior is similar to the
reference binding mode in pattern matching.
impl MyStruct {
fn get_a_field_ref(&self) -> String { self.a_field.clone() }
}
verify_that!(my_struct, matches_pattern!(MyStruct {
get_a_field_ref(): starts_with("Something"),
}))One can also match tuple structs with up to 10 fields. In this case, all fields must have matchers:
#[derive(Debug)]
struct MyTupleStruct(String, String);
let my_struct = MyTupleStruct("Something".into(), "Some other thing".into());
verify_that!(
my_struct,
matches_pattern!(&MyTupleStruct(ref eq("Something"), ref eq("Some other thing")))
)The macro also allows matching on specific enum values and supports wildcard
patterns like MyEnum::Case(_).
#[derive(Debug)]
enum MyEnum {
A(u32),
B,
}
verify_that!(MyEnum::A(123), matches_pattern!(&MyEnum::A(eq(123))))?; // Passes
verify_that!(MyEnum::A(123), matches_pattern!(MyEnum::A(_)))?; // Passes
verify_that!(MyEnum::B, matches_pattern!(&MyEnum::A(eq(123))))?; // Fails - wrong enum variantThis macro does not support plain (non-struct) tuples. But it should not be
necessary as tuple of matchers are matchers of tuple. In other words, if
MatcherU: Matcher<U> and MatcherT: Matcher<T>, then (MatcherU, MatcherT): Matcher<(U, T)>.
Trailing commas are allowed (but not required) in both ordinary and tuple structs.
Note that the default format (rustfmt) can format macros if the macro argument is parseable Rust code. This is mostly true for this macro with two exceptions:
- property matching
refkeyword with named fields
An option for formatting large is to avoid these exceptions (by removing the
parenthesis of properties and the ref keywords), run rustfmt and add
them back.