Home | History | Annotate | Download | only in docs
      1 <a id="top"></a>
      2 # Matchers
      3 
      4 Matchers are an alternative way to do assertions which are easily extensible and composable.
      5 This makes them well suited to use with more complex types (such as collections) or your own custom types.
      6 Matchers were first popularised by the [Hamcrest](https://en.wikipedia.org/wiki/Hamcrest) family of frameworks.
      7 
      8 ## In use
      9 
     10 Matchers are introduced with the `REQUIRE_THAT` or `CHECK_THAT` macros, which take two arguments.
     11 The first argument is the thing (object or value) under test. The second part is a match _expression_,
     12 which consists of either a single matcher or one or more matchers combined using `&&`, `||` or `!` operators.
     13 
     14 For example, to assert that a string ends with a certain substring:
     15  
     16  ```c++
     17 using Catch::Matchers::EndsWith; // or Catch::EndsWith
     18 std::string str = getStringFromSomewhere();
     19 REQUIRE_THAT( str, EndsWith( "as a service" ) ); 
     20  ```
     21 
     22 The matcher objects can take multiple arguments, allowing more fine tuning.
     23 The built-in string matchers, for example, take a second argument specifying whether the comparison is
     24 case sensitive or not:
     25 
     26 ```c++
     27 REQUIRE_THAT( str, EndsWith( "as a service", Catch::CaseSensitive::No ) ); 
     28  ```
     29 
     30 And matchers can be combined:
     31 
     32 ```c++
     33 REQUIRE_THAT( str, 
     34     EndsWith( "as a service" ) || 
     35     (StartsWith( "Big data" ) && !Contains( "web scale" ) ) ); 
     36 ```
     37 
     38 ## Built in matchers
     39 Catch currently provides some matchers, they are in the `Catch::Matchers` and `Catch` namespaces.
     40 
     41 ### String matchers
     42 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.
     43 
     44 Each of the provided `std::string` matchers also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive).
     45 
     46 
     47 ### Vector matchers
     48 The vector matchers are `Contains`, `VectorContains` and `Equals`. `VectorContains` looks for a single element in the matched vector, `Contains` looks for a set (vector) of elements inside the matched vector.
     49 
     50 ### Floating point matchers
     51 The floating point matchers are `WithinULP` and `WithinAbs`. `WithinAbs` accepts floating point numbers that are within a certain margin of target. `WithinULP` performs an [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place)-based comparison of two floating point numbers and accepts them if they are less than certain number of ULPs apart.
     52 
     53 Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
     54 
     55 
     56 ### Generic matchers
     57 Catch also aims to provide a set of generic matchers. Currently this set
     58 contains only a matcher that takes arbitrary callable predicate and applies
     59 it onto the provided object.
     60 
     61 Because of type inference limitations, the argument type of the predicate
     62 has to be provided explicitly. Example:
     63 ```cpp
     64 REQUIRE_THAT("Hello olleH",
     65              Predicate<std::string>(
     66                  [] (std::string const& str) -> bool { return str.front() == str.back(); },
     67                  "First and last character should be equal")
     68 );
     69 ```
     70 
     71 The second argument is an optional description of the predicate, and is
     72 used only during reporting of the result.
     73 
     74 
     75 ## Custom matchers
     76 It's easy to provide your own matchers to extend Catch or just to work with your own types.
     77 
     78 You need to provide two things: 
     79 1. A matcher class, derived from `Catch::MatcherBase<T>` - where `T` is the type being tested.
     80 The constructor takes and stores any arguments needed (e.g. something to compare against) and you must
     81 override two methods: `match()` and `describe()`. 
     82 2. A simple builder function. This is what is actually called from the test code and allows overloading.
     83 
     84 Here's an example for asserting that an integer falls within a given range
     85 (note that it is all inline for the sake of keeping the example short):
     86 
     87 ```c++
     88 // The matcher class
     89 class IntRange : public Catch::MatcherBase<int> {
     90     int m_begin, m_end;
     91 public:
     92     IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {}
     93 
     94     // Performs the test for this matcher
     95     virtual bool match( int const& i ) const override {
     96         return i >= m_begin && i <= m_end;
     97     }
     98 
     99     // Produces a string describing what this matcher does. It should
    100     // include any provided data (the begin/ end in this case) and
    101     // be written as if it were stating a fact (in the output it will be
    102     // preceded by the value under test).
    103     virtual std::string describe() const {
    104         std::ostringstream ss;
    105         ss << "is between " << m_begin << " and " << m_end;
    106         return ss.str();
    107     }
    108 };
    109 
    110 // The builder function
    111 inline IntRange IsBetween( int begin, int end ) {
    112     return IntRange( begin, end );
    113 }
    114 
    115 // ...
    116 
    117 // Usage
    118 TEST_CASE("Integers are within a range")
    119 {
    120     CHECK_THAT( 3, IsBetween( 1, 10 ) );
    121     CHECK_THAT( 100, IsBetween( 1, 10 ) );
    122 }
    123 ```
    124 
    125 Running this test gives the following in the console:
    126  
    127 ```
    128 /**/TestFile.cpp:123: FAILED:
    129   CHECK_THAT( 100, IsBetween( 1, 10 ) )
    130 with expansion:
    131   100 is between 1 and 10
    132 ```
    133 
    134 ---
    135 
    136 [Home](Readme.md#top)
    137