• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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