macro_rules! define_matcher {
(
$(#[$meta:meta])*
$vis:vis fn $name:ident for $target:ty {
expects: $expects:expr,
matches: | $actual:ident | $body:expr $(,)?
}
) => { ... };
(
$(#[$meta:meta])*
$vis:vis fn $name:ident ( $( $param:ident : $pty:ty ),* $(,)? ) for $target:ty {
expects: $expects:expr,
matches: | $actual:ident | $body:expr $(,)?
}
) => { ... };
(
@build
$(#[$meta:meta])*
$vis:vis fn $name:ident ( $( $param:ident : $pty:ty ),* ) for $target:ty {
expects: $expects:expr,
matches: | $actual:ident | $body:expr
}
) => { ... };
}Expand description
Defines a custom matcher from a predicate and a description.
This is the declarative shortcut for the most common custom matcher: one
that inspects a value of a concrete type and answers yes or no, with a
fixed human-readable account of what it expected. Anything richer (a diff,
an inner matcher, a borrowed projection) is written by hand as an
impl Matcher<T>.
§Syntax
(These examples name test_better_matchers directly because they are this
crate’s own doc tests; a user crate writes use test_better::prelude::*;
and use test_better::define_matcher; instead.)
use test_better_matchers::define_matcher;
define_matcher! {
/// Matches an even integer.
pub fn is_even for i32 {
expects: "an even integer",
matches: |n| n % 2 == 0,
}
}The matcher may take constructor parameters; each is in scope inside both
expects and matches as a value of its declared type, so the parameter
types must be Clone:
use test_better_core::TestResult;
use test_better_matchers::{define_matcher, check};
define_matcher! {
/// Matches a string that ends with `suffix`.
pub fn has_suffix(suffix: &'static str) for String {
expects: format!("a string ending in {suffix:?}"),
matches: |actual| actual.ends_with(suffix),
}
}
fn main() -> TestResult {
check!(String::from("report.csv")).satisfies(has_suffix(".csv"))?;
Ok(())
}§Requirements
- The target type must implement
Debug: a failure reports the actual value through{:?}. expectsis any expression that converts into the matcher’s description text (a string literal or aformat!are the usual choices).matchesis written like a closure,|binding| expression, but it is not a real closure:bindingnames the borrowed actual value and the expression is itsboolbody, evaluated with the constructor parameters in scope.