1<a id="top"></a> 2# Matchers 3 4Matchers are an alternative way to do assertions which are easily extensible and composable. 5This makes them well suited to use with more complex types (such as collections) or your own custom types. 6Matchers were first popularised by the [Hamcrest](https://en.wikipedia.org/wiki/Hamcrest) family of frameworks. 7 8## In use 9 10Matchers are introduced with the `REQUIRE_THAT` or `CHECK_THAT` macros, which take two arguments. 11The first argument is the thing (object or value) under test. The second part is a match _expression_, 12which consists of either a single matcher or one or more matchers combined using `&&`, `||` or `!` operators. 13 14For example, to assert that a string ends with a certain substring: 15 16 ```c++ 17using Catch::Matchers::EndsWith; // or Catch::EndsWith 18std::string str = getStringFromSomewhere(); 19REQUIRE_THAT( str, EndsWith( "as a service" ) ); 20``` 21 22The matcher objects can take multiple arguments, allowing more fine tuning. 23The built-in string matchers, for example, take a second argument specifying whether the comparison is 24case sensitive or not: 25 26```c++ 27REQUIRE_THAT( str, EndsWith( "as a service", Catch::CaseSensitive::No ) ); 28 ``` 29 30And matchers can be combined: 31 32```c++ 33REQUIRE_THAT( str, 34 EndsWith( "as a service" ) || 35 (StartsWith( "Big data" ) && !Contains( "web scale" ) ) ); 36``` 37 38_The combining operators do not take ownership of the matcher objects. 39This means that if you store the combined object, you have to ensure that 40the matcher objects outlive its last use. What this means is that code 41like this leads to a use-after-free and (hopefully) a crash:_ 42 43```cpp 44TEST_CASE("Bugs, bugs, bugs", "[Bug]"){ 45 std::string str = "Bugs as a service"; 46 47 auto match_expression = Catch::EndsWith( "as a service" ) || 48 (Catch::StartsWith( "Big data" ) && !Catch::Contains( "web scale" ) ); 49 REQUIRE_THAT(str, match_expression); 50} 51``` 52 53 54## Built in matchers 55Catch2 provides some matchers by default. They can be found in the 56`Catch::Matchers::foo` namespace and are imported into the `Catch` 57namespace as well. 58 59There are two parts to each of the built-in matchers, the matcher 60type itself and a helper function that provides template argument 61deduction when creating templated matchers. As an example, the matcher 62for checking that two instances of `std::vector` are identical is 63`EqualsMatcher<T>`, but the user is expected to use the `Equals` 64helper function instead. 65 66 67### String matchers 68The 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. 69 70Each of the provided `std::string` matchers also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive). 71 72 73### Vector matchers 74Catch2 currently provides 5 built-in matchers that work on `std::vector`. 75These are 76 77 * `Contains` which checks whether a specified vector is present in the result 78 * `VectorContains` which checks whether a specified element is present in the result 79 * `Equals` which checks whether the result is exactly equal (order matters) to a specific vector 80 * `UnorderedEquals` which checks whether the result is equal to a specific vector under a permutation 81 * `Approx` which checks whether the result is "approx-equal" (order matters, but comparison is done via `Approx`) to a specific vector 82> Approx matcher was [introduced](https://github.com/catchorg/Catch2/issues/1499) in Catch 2.7.2. 83 84 85### Floating point matchers 86Catch2 provides 3 matchers for working with floating point numbers. These 87are `WithinAbsMatcher`, `WithinUlpsMatcher` and `WithinRelMatcher`. 88 89The `WithinAbsMatcher` matcher accepts floating point numbers that are 90within a certain distance of target. It should be constructed with the 91`WithinAbs(double target, double margin)` helper. 92 93The `WithinUlpsMatcher` matcher accepts floating point numbers that are 94within a certain number of [ULPs](https://en.wikipedia.org/wiki/Unit_in_the_last_place) 95of the target. Because ULP comparisons need to be done differently for 96`float`s and for `double`s, there are two overloads of the helpers for 97this matcher, `WithinULP(float target, int64_t ULPs)`, and 98`WithinULP(double target, int64_t ULPs)`. 99 100The `WithinRelMatcher` matcher accepts floating point numbers that are 101_approximately equal_ with the target number with some specific tolerance. 102In other words, it checks that `|lhs - rhs| <= epsilon * max(|lhs|, |rhs|)`, 103with special casing for `INFINITY` and `NaN`. There are _4_ overloads of 104the helpers for this matcher, `WithinRel(double target, double margin)`, 105`WithinRel(float target, float margin)`, `WithinRel(double target)`, and 106`WithinRel(float target)`. The latter two provide a default epsilon of 107machine epsilon * 100. 108 109> `WithinRel` matcher was introduced in Catch 2.10.0 110 111### Generic matchers 112Catch also aims to provide a set of generic matchers. Currently this set 113contains only a matcher that takes arbitrary callable predicate and applies 114it onto the provided object. 115 116Because of type inference limitations, the argument type of the predicate 117has to be provided explicitly. Example: 118```cpp 119REQUIRE_THAT("Hello olleH", 120 Predicate<std::string>( 121 [] (std::string const& str) -> bool { return str.front() == str.back(); }, 122 "First and last character should be equal") 123); 124``` 125 126The second argument is an optional description of the predicate, and is 127used only during reporting of the result. 128 129 130### Exception matchers 131Catch2 also provides an exception matcher that can be used to verify 132that an exception's message exactly matches desired string. The matcher 133is `ExceptionMessageMatcher`, and we also provide a helper function 134`Message`. 135 136The matched exception must publicly derive from `std::exception` and 137the message matching is done _exactly_, including case. 138 139> `ExceptionMessageMatcher` was introduced in Catch 2.10.0 140 141Example use: 142```cpp 143REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("DerivedException::what")); 144``` 145 146## Custom matchers 147It's easy to provide your own matchers to extend Catch or just to work with your own types. 148 149You need to provide two things: 1501. A matcher class, derived from `Catch::MatcherBase<T>` - where `T` is the type being tested. 151The constructor takes and stores any arguments needed (e.g. something to compare against) and you must 152override two methods: `match()` and `describe()`. 1532. A simple builder function. This is what is actually called from the test code and allows overloading. 154 155Here's an example for asserting that an integer falls within a given range 156(note that it is all inline for the sake of keeping the example short): 157 158```c++ 159// The matcher class 160class IntRange : public Catch::MatcherBase<int> { 161 int m_begin, m_end; 162public: 163 IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {} 164 165 // Performs the test for this matcher 166 bool match( int const& i ) const override { 167 return i >= m_begin && i <= m_end; 168 } 169 170 // Produces a string describing what this matcher does. It should 171 // include any provided data (the begin/ end in this case) and 172 // be written as if it were stating a fact (in the output it will be 173 // preceded by the value under test). 174 virtual std::string describe() const override { 175 std::ostringstream ss; 176 ss << "is between " << m_begin << " and " << m_end; 177 return ss.str(); 178 } 179}; 180 181// The builder function 182inline IntRange IsBetween( int begin, int end ) { 183 return IntRange( begin, end ); 184} 185 186// ... 187 188// Usage 189TEST_CASE("Integers are within a range") 190{ 191 CHECK_THAT( 3, IsBetween( 1, 10 ) ); 192 CHECK_THAT( 100, IsBetween( 1, 10 ) ); 193} 194``` 195 196Running this test gives the following in the console: 197 198``` 199/**/TestFile.cpp:123: FAILED: 200 CHECK_THAT( 100, IsBetween( 1, 10 ) ) 201with expansion: 202 100 is between 1 and 10 203``` 204 205--- 206 207[Home](Readme.md#top) 208