| <a id="top"></a> |
| # Matchers |
| |
| Matchers are an alternative way to do assertions which are easily extensible and composable. |
| This makes them well suited to use with more complex types (such as collections) or your own custom types. |
| Matchers were first popularised by the [Hamcrest](https://en.wikipedia.org/wiki/Hamcrest) family of frameworks. |
| |
| ## In use |
| |
| Matchers are introduced with the `REQUIRE_THAT` or `CHECK_THAT` macros, which take two arguments. |
| The first argument is the thing (object or value) under test. The second part is a match _expression_, |
| which consists of either a single matcher or one or more matchers combined using `&&`, `||` or `!` operators. |
| |
| For example, to assert that a string ends with a certain substring: |
| |
| ```c++ |
| using Catch::Matchers::EndsWith; // or Catch::EndsWith |
| std::string str = getStringFromSomewhere(); |
| REQUIRE_THAT( str, EndsWith( "as a service" ) ); |
| ``` |
| |
| The matcher objects can take multiple arguments, allowing more fine tuning. |
| The built-in string matchers, for example, take a second argument specifying whether the comparison is |
| case sensitive or not: |
| |
| ```c++ |
| REQUIRE_THAT( str, EndsWith( "as a service", Catch::CaseSensitive::No ) ); |
| ``` |
| |
| And matchers can be combined: |
| |
| ```c++ |
| REQUIRE_THAT( str, |
| EndsWith( "as a service" ) || |
| (StartsWith( "Big data" ) && !Contains( "web scale" ) ) ); |
| ``` |
| |
| _The combining operators do not take ownership of the matcher objects. |
| This means that if you store the combined object, you have to ensure that |
| the matcher objects outlive its last use. What this means is that code |
| like this leads to a use-after-free and (hopefully) a crash:_ |
| |
| ```cpp |
| TEST_CASE("Bugs, bugs, bugs", "[Bug]"){ |
| std::string str = "Bugs as a service"; |
| |
| auto match_expression = Catch::EndsWith( "as a service" ) || |
| (Catch::StartsWith( "Big data" ) && !Catch::Contains( "web scale" ) ); |
| REQUIRE_THAT(str, match_expression); |
| } |
| ``` |
| |
| |
| ## Built in matchers |
| Catch2 provides some matchers by default. They can be found in the |
| `Catch::Matchers::foo` namespace and are imported into the `Catch` |
| namespace as well. |
| |
| There are two parts to each of the built-in matchers, the matcher |
| type itself and a helper function that provides template argument |
| deduction when creating templated matchers. As an example, the matcher |
| for checking that two instances of `std::vector` are identical is |
| `EqualsMatcher<T>`, but the user is expected to use the `Equals` |
| helper function instead. |
| |
| |
| ### String matchers |
| The string matchers are `StartsWith`, `EndsWith`, `Contains`, `Equals` and `Matches`. The first four match a literal (sub)string against a result, while `Matches` takes and matches an ECMAScript regex. Do note that `Matches` matches the string as a whole, meaning that "abc" will not match against "abcd", but "abc.*" will. |
| |
| Each of the provided `std::string` matchers also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive). |
| |
| |
| ### Vector matchers |
| Catch2 currently provides 5 built-in matchers that work on `std::vector`. |
| These are |
| |
| * `Contains` which checks whether a specified vector is present in the result |
| * `VectorContains` which checks whether a specified element is present in the result |
| * `Equals` which checks whether the result is exactly equal (order matters) to a specific vector |
| * `UnorderedEquals` which checks whether the result is equal to a specific vector under a permutation |
| * `Approx` which checks whether the result is "approx-equal" (order matters, but comparison is done via `Approx`) to a specific vector |
| > Approx matcher was [introduced](https://github.com/catchorg/Catch2/issues/1499) in Catch 2.7.2. |
| |
| |
| ### Floating point matchers |
| Catch2 provides 3 matchers for working with floating point numbers. These |
| are `WithinAbsMatcher`, `WithinUlpsMatcher` and `WithinRelMatcher`. |
| |
| The `WithinAbsMatcher` matcher accepts floating point numbers that are |
| within a certain distance of target. It should be constructed with the |
| `WithinAbs(double target, double margin)` helper. |
| |
| The `WithinUlpsMatcher` matcher accepts floating point numbers that are |
| within a certain number of [ULPs](https://en.wikipedia.org/wiki/Unit_in_the_last_place) |
| of the target. Because ULP comparisons need to be done differently for |
| `float`s and for `double`s, there are two overloads of the helpers for |
| this matcher, `WithinULP(float target, int64_t ULPs)`, and |
| `WithinULP(double target, int64_t ULPs)`. |
| |
| The `WithinRelMatcher` matcher accepts floating point numbers that are |
| _approximately equal_ with the target number with some specific tolerance. |
| In other words, it checks that `|lhs - rhs| <= epsilon * max(|lhs|, |rhs|)`, |
| with special casing for `INFINITY` and `NaN`. There are _4_ overloads of |
| the helpers for this matcher, `WithinRel(double target, double margin)`, |
| `WithinRel(float target, float margin)`, `WithinRel(double target)`, and |
| `WithinRel(float target)`. The latter two provide a default epsilon of |
| machine epsilon * 100. |
| |
| > `WithinRel` matcher was introduced in Catch 2.10.0 |
| |
| ### Generic matchers |
| Catch also aims to provide a set of generic matchers. Currently this set |
| contains only a matcher that takes arbitrary callable predicate and applies |
| it onto the provided object. |
| |
| Because of type inference limitations, the argument type of the predicate |
| has to be provided explicitly. Example: |
| ```cpp |
| REQUIRE_THAT("Hello olleH", |
| Predicate<std::string>( |
| [] (std::string const& str) -> bool { return str.front() == str.back(); }, |
| "First and last character should be equal") |
| ); |
| ``` |
| |
| The second argument is an optional description of the predicate, and is |
| used only during reporting of the result. |
| |
| |
| ### Exception matchers |
| Catch2 also provides an exception matcher that can be used to verify |
| that an exception's message exactly matches desired string. The matcher |
| is `ExceptionMessageMatcher`, and we also provide a helper function |
| `Message`. |
| |
| The matched exception must publicly derive from `std::exception` and |
| the message matching is done _exactly_, including case. |
| |
| > `ExceptionMessageMatcher` was introduced in Catch 2.10.0 |
| |
| Example use: |
| ```cpp |
| REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("DerivedException::what")); |
| ``` |
| |
| ## Custom matchers |
| It's easy to provide your own matchers to extend Catch or just to work with your own types. |
| |
| You need to provide two things: |
| 1. A matcher class, derived from `Catch::MatcherBase<T>` - where `T` is the type being tested. |
| The constructor takes and stores any arguments needed (e.g. something to compare against) and you must |
| override two methods: `match()` and `describe()`. |
| 2. A simple builder function. This is what is actually called from the test code and allows overloading. |
| |
| Here's an example for asserting that an integer falls within a given range |
| (note that it is all inline for the sake of keeping the example short): |
| |
| ```c++ |
| // The matcher class |
| class IntRange : public Catch::MatcherBase<int> { |
| int m_begin, m_end; |
| public: |
| IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {} |
| |
| // Performs the test for this matcher |
| bool match( int const& i ) const override { |
| return i >= m_begin && i <= m_end; |
| } |
| |
| // Produces a string describing what this matcher does. It should |
| // include any provided data (the begin/ end in this case) and |
| // be written as if it were stating a fact (in the output it will be |
| // preceded by the value under test). |
| virtual std::string describe() const override { |
| std::ostringstream ss; |
| ss << "is between " << m_begin << " and " << m_end; |
| return ss.str(); |
| } |
| }; |
| |
| // The builder function |
| inline IntRange IsBetween( int begin, int end ) { |
| return IntRange( begin, end ); |
| } |
| |
| // ... |
| |
| // Usage |
| TEST_CASE("Integers are within a range") |
| { |
| CHECK_THAT( 3, IsBetween( 1, 10 ) ); |
| CHECK_THAT( 100, IsBetween( 1, 10 ) ); |
| } |
| ``` |
| |
| Running this test gives the following in the console: |
| |
| ``` |
| /**/TestFile.cpp:123: FAILED: |
| CHECK_THAT( 100, IsBetween( 1, 10 ) ) |
| with expansion: |
| 100 is between 1 and 10 |
| ``` |
| |
| --- |
| |
| [Home](Readme.md#top) |