mimic++ v9.2.1
Loading...
Searching...
No Matches
matchers

Matchers check various argument properties. More...

Collaboration diagram for matchers:

Topics

 range matchers
 Range specific matchers.
 
 string matchers
 String specific matchers.
 

Classes

class  mimicpp::PredicateMatcher< Predicate, AdditionalArgs >
 Generic matcher and the basic building block of most of the built-in matchers. More...
 
class  mimicpp::WildcardMatcher
 Matcher, which never fails. More...
 
class  mimicpp::TypeMatcher< T >
 Matcher, which can be used to disambiguate between similar overloads. More...
 

Functions

consteval auto mimicpp::matches::NaN () noexcept
 Tests, whether the floating-point target is NaN.
 
constexpr auto mimicpp::matches::approx_abs (const std::floating_point auto value, const std::floating_point auto epsilon)
 Tests, whether the floating-point target is approximately equal to value.
 
constexpr auto mimicpp::matches::approx_rel (const std::floating_point auto value, const std::floating_point auto relEpsilon)
 Tests, whether the floating-point target is approximately equal to value.
 
template<std::floating_point Float>
constexpr auto mimicpp::matches::approx_rel (const Float value)
 Tests, whether the floating-point target is approximately equal to value.
 
template<typename T>
constexpr auto mimicpp::matches::eq (T &&value)
 Tests, whether the target compares equal to the expected value.
 
template<typename T>
constexpr auto mimicpp::matches::ne (T &&value)
 Tests, whether the target compares not equal to the expected value.
 
template<typename T>
constexpr auto mimicpp::matches::lt (T &&value)
 Tests, whether the target is less than the expected value.
 
template<typename T>
constexpr auto mimicpp::matches::le (T &&value)
 Tests, whether the target is less than or equal to the expected value.
 
template<typename T>
constexpr auto mimicpp::matches::gt (T &&value)
 Tests, whether the target is greater than the expected value.
 
template<typename T>
constexpr auto mimicpp::matches::ge (T &&value)
 Tests, whether the target is greater than or equal to the expected value.
 
template<typename UnaryPredicate>
constexpr auto mimicpp::matches::predicate (UnaryPredicate &&predicate, StringViewT description="passes predicate", StringViewT invertedDescription="fails predicate")
 Tests, whether the target fulfills the given predicate.
 
template<util::satisfies< std::is_lvalue_reference > T>
constexpr auto mimicpp::matches::instance (T &&instance)
 Tests, whether the target is the expected instance.
 

Variables

constexpr WildcardMatcher mimicpp::matches::_ {}
 The wildcard matcher, always matching.
 
template<typename T>
constexpr TypeMatcher< T > mimicpp::matches::type {}
 Matcher, which can be used as a last resort to disambiguate similar overloads.
 

Detailed Description

Matchers check various argument properties.

Matchers can be used to check various argument properties and are highly customizable. In general, they simply compare their arguments with a pre-defined predicate, but also provide a meaningful description.

Attention
Matchers receive their arguments as possibly non-const, which is due to workaround some restrictions on const qualified views. Either way, matchers should never modify any of their arguments.

Matching arguments

In general matchers can be applied via the expect::arg<n> factory, but they can also be directly used at the expect statement.

namespace matches = mimicpp::matches;
namespace expect = mimicpp::expect;
mimicpp::Mock<void(int)> mock{};
SCOPED_EXP mock.expect_call(_)
and expect::arg<0>(matches::gt(42))
and expect::arg<0>(matches::lt(1338));
mock(1337);
namespace matches = mimicpp::matches;
mimicpp::Mock<void(int)> mock{};
SCOPED_EXP mock.expect_call(matches::eq(42));
mock(42);

For equality testing, there exists an even shorter syntax.

mimicpp::Mock<void(int)> mock{};
SCOPED_EXP mock.expect_call(42);
mock(42);

Most of the built-in matchers support the inversion operator (operator !), which then tests for the opposite condition.

namespace matches = mimicpp::matches;
namespace expect = mimicpp::expect;
mimicpp::Mock<void(int)> mock{};
SCOPED_EXP mock.expect_call(_) // in fact, the _ is the only built-in matcher, which isn't invertible
and expect::arg<0>(!matches::le(42)); // note the !, as this makes it an actual > test
mock(1337);

Custom Matcher

Matchers are highly customizable. In fact, any type which satisfies matcher_for concept can be used. There exists no base or interface type, but the PredicateMatcher servers as a convenient generic type, which simply contains a predicate, a format string and optional additional arguments.

A very straight-forward custom matcher may look like this:

[[nodiscard]]
constexpr auto Contains(int expectedElement)
{
// This is the actual predicate.
// The first argument is the actual input and the other are the stored tuple-elements.
[](auto const& argument, auto const& element) {
return std::ranges::find(argument, element) != std::ranges::end(argument);
},
"contains element {}", // This is the description format-string.
"contains not element {}", // This is the description string for the negated matcher (i.e. when `!Contains` is used).
// Capture additional data, which will be forwarded to both, the predicate and the description.
std::make_tuple(expectedElement)};
}
mimicpp::Mock<void(std::span<int const>)> mock{};
std::vector const collection{42, 1337};
SCOPED_EXP mock.expect_call(Contains(42));
mock(collection);
// Negating the matcher is directly supported. In this case this means:
// "input-array does not contain the element `-42`"
SCOPED_EXP mock.expect_call(!Contains(-42));
mock(collection);

In fact, the PredicateMatcher is very flexible and can most likely tailored to your needs. For example, you can store any additional data. In this case the internal formatter requires the raw-pattern string, but the actual predicate needs a std::regex.

[[nodiscard]]
auto MatchesRegex(std::string pattern)
{
// This is the actual predicate.
// The first argument is the actual input and the other are the stored tuple-elements.
[](std::ranges::range auto&& input, [[maybe_unused]] std::string const& patternString, std::regex const& regex) {
return std::regex_match(
std::ranges::begin(input),
std::ranges::end(input),
regex);
},
"matches regex {}", // This is the description format-string.
"does not match regex {}", // This is the description string for the negated matcher (i.e. when `!MatchesRegex` is used).
// PredicateMatcher accepts arbitrary additional date, wrapped as std::tuple.
// Each tuple-element will internally be applied to the predicate function and both format-strings.
// Note: It is allowed to store more elements than actually referenced by the format-strings.
// The formatter will consume the arguments in the stored order.
std::make_tuple(pattern, std::regex{pattern})};
}
mimicpp::Mock<void(std::string const&)> mock{};
// Let's build an expectation where the argument-string must exactly contain 4 digits.
SCOPED_EXP mock.expect_call(MatchesRegex(R"(\d{4})"));
mock("1337");
// And another expectation where the argument must not match the regex (note the preceding `!`).
SCOPED_EXP mock.expect_call(!MatchesRegex(R"(\d*)"));
mock("Hello, World!");

Variadic matchers are also directly supported. In this case, the matcher requires two inputs and checks whether the sum of both matches the specified value.

[[nodiscard]]
constexpr auto MatchesSum(int const expectedSum)
{
// This is the actual predicate.
// The first two arguments are the input from the call and the last input is the set expectation.
[](int const firstArg, int const secondArg, int const expected) {
return firstArg + secondArg == expected;
},
"matches sum {}", // This is the description format-string.
"does not match sum {}", // This is the description string for the negated matcher (i.e. when `!MatchesSum` is used).
std::make_tuple(expectedSum)};
}
namespace matches = mimicpp::matches;
namespace expect = mimicpp::expect;
using matches::_;
mimicpp::Mock<void(int, int)> mock{};
SCOPED_EXP mock.expect_call(_, _)
// This policy applies all arguments at a whole onto the specified matcher.
// In this case, we expect that the sum of the two is equal to `1337`.
and expect::all_args(MatchesSum(1337));
mock(42, 1295);

When there are very special needs, users can also just define their own matcher type without any base-class.

class IsEvenMatcher
{
public:
[[nodiscard]]
bool matches(int const input) const
{
return 0 == input % 2;
}
[[nodiscard]]
std::string_view describe() const
{
return "is an even number.";
}
};
// Let's see, whether we actually satisfy all constraints.
// This checks, that `IsEvenNumber` is a matcher for a single `int` argument.
mimicpp::Mock<void(int)> mock{};
// This expects the input to be an even number.
SCOPED_EXP mock.expect_call(IsEvenMatcher{});
mock(42);
// Note: It's the users responsibility to add additional feature, like negation.
// The `matcher_for` concept does only require the absolute minimal feature-set (a `matches` and `describe` function).
// So, in this case `!IsEvenMatcher{}` will not work.

Function Documentation

◆ approx_abs()

auto mimicpp::matches::approx_abs ( const std::floating_point auto value,
const std::floating_point auto epsilon )
nodiscardconstexpr

Tests, whether the floating-point target is approximately equal to value.

Parameters
valueThe value to compare to.
epsilonThe maximum absolute difference.
Exceptions
std::runtime_errorWhen value is NaN or infinity.
std::runtime_errorWhen epsilon is NaN, infinity or non-positive.
Returns
The newly created matcher.

◆ approx_rel() [1/2]

template<std::floating_point Float>
auto mimicpp::matches::approx_rel ( const Float value)
nodiscardconstexpr

Tests, whether the floating-point target is approximately equal to value.

Parameters
valueThe value to compare against.
Returns
The newly created matcher.
Exceptions
std::runtime_errorWhen value is NaN or infinity.

This overload sets 100 * std::numeric_limits<Float>::epsilon() as the relative epsilon value. This seems like a reasonable choice, which is also used by the catch2's WithinRel matcher.

See also
https://github.com/catchorg/Catch2/blob/devel/docs/comparing-floating-point-numbers.md#withinrel

For detailed information about the underlying algorithm, have a look at the primary overload.

See also
approx_rel(std::floating_point auto, std::floating_point auto)
Here is the call graph for this function:

◆ approx_rel() [2/2]

auto mimicpp::matches::approx_rel ( const std::floating_point auto value,
const std::floating_point auto relEpsilon )
nodiscardconstexpr

Tests, whether the floating-point target is approximately equal to value.

Parameters
valueThe value to compare against.
relEpsilonThe maximum relative difference.
Returns
The newly created matcher.
Exceptions
std::runtime_errorWhen value is NaN or infinity.
std::runtime_errorWhen relEpsilon is NaN, infinity or non-positive.

This functions compares both floating-point values with a scaled epsilon. In fact:

|a-b| <= eps * max(|a|, |b|),

where a and b are the operands and eps denotes the factor of the maximum input by which a and b may differ.

Note
This algorithm was published by Donald Knuth in his book “The Art of Computer Programming, Volume II: Seminumerical Algorithms (Addison-Wesley, 1969)”.
Here is the caller graph for this function:

◆ eq()

template<typename T>
auto mimicpp::matches::eq ( T && value)
nodiscardconstexpr

Tests, whether the target compares equal to the expected value.

Template Parameters
TExpected type.
Parameters
valueExpected value.

◆ ge()

template<typename T>
auto mimicpp::matches::ge ( T && value)
nodiscardconstexpr

Tests, whether the target is greater than or equal to the expected value.

Template Parameters
TExpected type.
Parameters
valueExpected value.

◆ gt()

template<typename T>
auto mimicpp::matches::gt ( T && value)
nodiscardconstexpr

Tests, whether the target is greater than the expected value.

Template Parameters
TExpected type.
Parameters
valueExpected value.

◆ instance()

template<util::satisfies< std::is_lvalue_reference > T>
auto mimicpp::matches::instance ( T && instance)
nodiscardconstexpr

Tests, whether the target is the expected instance.

Template Parameters
TInstance type.
Parameters
instanceThe instance to be compared to.
namespace matches = mimicpp::matches;
mimicpp::Mock<void(const int&)> mock{};
int myInt{};
SCOPED_EXP mock.expect_call(matches::instance(myInt));
mock(myInt);
Here is the call graph for this function:
Here is the caller graph for this function:

◆ le()

template<typename T>
auto mimicpp::matches::le ( T && value)
nodiscardconstexpr

Tests, whether the target is less than or equal to the expected value.

Template Parameters
TExpected type.
Parameters
valueExpected value.

◆ lt()

template<typename T>
auto mimicpp::matches::lt ( T && value)
nodiscardconstexpr

Tests, whether the target is less than the expected value.

Template Parameters
TExpected type.
Parameters
valueExpected value.

◆ NaN()

auto mimicpp::matches::NaN ( )
nodiscardconstevalnoexcept

Tests, whether the floating-point target is NaN.

◆ ne()

template<typename T>
auto mimicpp::matches::ne ( T && value)
nodiscardconstexpr

Tests, whether the target compares not equal to the expected value.

Template Parameters
TExpected type.
Parameters
valueExpected value.

◆ predicate()

template<typename UnaryPredicate>
auto mimicpp::matches::predicate ( UnaryPredicate && predicate,
StringViewT description = "passes predicate",
StringViewT invertedDescription = "fails predicate" )
nodiscardconstexpr

Tests, whether the target fulfills the given predicate.

Template Parameters
UnaryPredicatePredicate type.
Parameters
predicateThe predicate to test.
descriptionThe formatting string.
invertedDescriptionThe formatting string for the inversion.
namespace matches = mimicpp::matches;
namespace expect = mimicpp::expect;
mimicpp::Mock<void(int)> mock{};
constexpr auto isOdd = [](int val) { return 0 != val % 2; };
SCOPED_EXP mock.expect_call(_)
and expect::arg<0>(matches::predicate(isOdd));
mock(1337);
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ _

WildcardMatcher mimicpp::matches::_ {}
inlineconstexpr

The wildcard matcher, always matching.

mimicpp::Mock<void(int)> mock{};
SCOPED_EXP mock.expect_call(_);
mock(1337);

◆ type

template<typename T>
TypeMatcher<T> mimicpp::matches::type {}
inlineconstexpr

Matcher, which can be used as a last resort to disambiguate similar overloads.

Template Parameters
TThe exact argument type.
namespace matches = mimicpp::matches;
mimicpp::Mock<void(int&&), void(int const&)> mock{};
SECTION("Selecting void(int&&)")
{
MIMICPP_SCOPED_EXPECTATION mock.expect_call(matches::type<int&&>);
mock(42);
}
SECTION("Selecting void(int const&)")
{
MIMICPP_SCOPED_EXPECTATION mock.expect_call(matches::type<int const&>);
int constexpr i{42};
mock(i);
}