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"),
}))

It is not required to include all named fields in the specification. Omitted fields have no effect on the output of the matcher.

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"),
}))

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 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"): ends_with("a suffix"),
}))

If the method returns a reference, precede it with a *:

impl MyStruct {
    fn get_a_field_ref(&self) -> &String { &self.a_field }
}

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(eq("Something"), eq("Some other thing")))
)

One can also match enum values:

#[derive(Debug)]
enum MyEnum {
    A(u32),
    B,
}

verify_that!(MyEnum::A(123), matches_pattern!(MyEnum::A(eq(123))))?; // Passes
verify_that!(MyEnum::B, matches_pattern!(MyEnum::A(eq(123))))?; // Fails - wrong enum variant

This macro does not support plain (non-struct) tuples. Use the macro tuple for that purpose.

Trailing commas are allowed (but not required) in both ordinary and tuple structs.

Unfortunately, this matcher does not work with methods returning string slices:

pub struct MyStruct {
    a_string: String,
}
impl MyStruct {
    pub fn get_a_string(&self) -> &str { &self.a_string }
}

let value = MyStruct { a_string: "A string".into() };
verify_that!(value, matches_pattern!( MyStruct {
    get_a_string(): eq("A string"),   // Does not compile
}))