Skip to main content

define_matcher

Macro define_matcher 

Source
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 {:?}.
  • expects is any expression that converts into the matcher’s description text (a string literal or a format! are the usual choices).
  • matches is written like a closure, |binding| expression, but it is not a real closure: binding names the borrowed actual value and the expression is its bool body, evaluated with the constructor parameters in scope.