mirror of
https://github.com/catchorg/Catch2.git
synced 2025-01-15 22:58:02 +00:00
Compare commits
7 Commits
121f04ffcf
...
ab0ca2f566
Author | SHA1 | Date | |
---|---|---|---|
|
ab0ca2f566 | ||
|
3a3efebd16 | ||
|
f52a58e857 | ||
|
007efc173a | ||
|
89e857349b | ||
|
c2daf468bb | ||
|
64d7f9b98a |
421
docs/matchers.md
421
docs/matchers.md
@ -1,77 +1,123 @@
|
||||
<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.
|
||||
**Contents**<br>
|
||||
[Using Matchers](#using-matchers)<br>
|
||||
[Built-in matchers](#built-in-matchers)<br>
|
||||
[Writing custom matchers (old style)](#writing-custom-matchers-old-style)<br>
|
||||
[Writing custom matchers (new style)](#writing-custom-matchers-new-style)<br>
|
||||
|
||||
## In use
|
||||
Matchers, as popularized by the [Hamcrest](https://en.wikipedia.org/wiki/Hamcrest)
|
||||
framework are an alternative way to write assertions, useful for tests
|
||||
where you work with complex types or need to assert more complex
|
||||
properties. Matchers are easily composable and users can write their
|
||||
own and combine them with the Catch2-provided matchers seamlessly.
|
||||
|
||||
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:
|
||||
## Using Matchers
|
||||
|
||||
```c++
|
||||
using Catch::Matchers::EndsWith; // or Catch::EndsWith
|
||||
std::string str = getStringFromSomewhere();
|
||||
REQUIRE_THAT( str, EndsWith( "as a service" ) );
|
||||
```
|
||||
Matchers are most commonly used in tandem with the `REQUIRE_THAT` or
|
||||
`CHECK_THAT` macros. The `REQUIRE_THAT` macro takes two arguments,
|
||||
the first one is the input (object/value) to test, the second argument
|
||||
is the matcher itself.
|
||||
|
||||
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:_
|
||||
For example, to assert that a string ends with the "as a service"
|
||||
substring, you can write the following assertion
|
||||
|
||||
```cpp
|
||||
using Catch::Matchers::EndsWith;
|
||||
|
||||
REQUIRE_THAT( getSomeString(), EndsWith("as a service") );
|
||||
```
|
||||
|
||||
Individual matchers can also be combined using the C++ logical
|
||||
operators, that is `&&`, `||`, and `!`, like so:
|
||||
|
||||
```cpp
|
||||
using Catch::Matchers::EndsWith;
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
REQUIRE_THAT( getSomeString(),
|
||||
EndsWith("as a service") && Contains("web scale"));
|
||||
```
|
||||
|
||||
The example above asserts that the string returned from `getSomeString`
|
||||
_both_ ends with the suffix "as a service" _and_ contains the string
|
||||
"web scale" somewhere.
|
||||
|
||||
|
||||
Both of the string matchers used in the examples above live in the
|
||||
`catch_matchers_string.hpp` header, so to compile the code above also
|
||||
requires `#include <catch2/matchers/catch_matchers_string.hpp>`.
|
||||
|
||||
**IMPORTANT**: The combining operators do not take ownership of the
|
||||
matcher objects being combined. This means that if you store combined
|
||||
matcher object, you have to ensure that the matchers being combined
|
||||
outlive its last use. What this means is that the following code leads
|
||||
to a use-after-free (UAF):
|
||||
|
||||
```cpp
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
|
||||
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" ) );
|
||||
auto match_expression = Catch::Matchers::EndsWith( "as a service" ) ||
|
||||
(Catch::Matchers::StartsWith( "Big data" ) && !Catch::Matchers::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.
|
||||
## Built-in matchers
|
||||
|
||||
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.
|
||||
Every matcher provided by Catch2 is split into 2 parts, a factory
|
||||
function that lives in the `Catch::Matchers` namespace, and the actual
|
||||
matcher type that is in some deeper namespace and should not be used by
|
||||
the user. In the examples above, we used `Catch::Matchers::Contains`.
|
||||
This is the factory function for the
|
||||
`Catch::Matchers::StdString::ContainsMatcher` type that does the actual
|
||||
matching.
|
||||
|
||||
Out of the box, Catch2 provides the following matchers:
|
||||
|
||||
|
||||
### 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.
|
||||
### `std::string` matchers
|
||||
|
||||
Each of the provided `std::string` matchers also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive).
|
||||
Catch2 provides 5 different matchers that work with `std::string`,
|
||||
* `StartsWith(std::string str, CaseSensitive)`,
|
||||
* `EndsWith(std::string str, CaseSensitive)`,
|
||||
* `Contains(std::string str, CaseSensitive)`,
|
||||
* `Equals(std::string str, CaseSensitive)`, and
|
||||
* `Matches(std::string str, CaseSensitive)`.
|
||||
|
||||
The first three should be fairly self-explanatory, they succeed if
|
||||
the argument starts with `str`, ends with `str`, or contains `str`
|
||||
somewhere inside it.
|
||||
|
||||
The `Equals` matcher matches a string if (and only if) the argument
|
||||
string is equal to `str`.
|
||||
|
||||
Finally, the `Matches` matcher performs an ECMASCript regex match using
|
||||
`str` against the argument string. It is important to know that
|
||||
the match is performed agains the string as a whole, meaning that
|
||||
the regex `"abc"` will not match input string `"abcd"`. To match
|
||||
`"abcd"`, you need to use e.g. `"abc.*"` as your regex.
|
||||
|
||||
The second argument sets whether the matching should be case-sensitive
|
||||
or not. By default, it is case-sensitive.
|
||||
|
||||
> `std::string` matchers live in `catch2/matchers/catch_matchers_string.hpp`
|
||||
|
||||
|
||||
### Vector matchers
|
||||
Catch2 currently provides 5 built-in matchers that work on `std::vector`.
|
||||
|
||||
_Vector matchers have been deprecated in favour of the generic
|
||||
range matchers with the same functionality._
|
||||
|
||||
Catch2 provides 5 built-in matchers that work on `std::vector`.
|
||||
|
||||
These are
|
||||
|
||||
* `Contains` which checks whether a specified vector is present in the result
|
||||
@ -81,40 +127,82 @@ These are
|
||||
* `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.
|
||||
|
||||
An example usage:
|
||||
```cpp
|
||||
std::vector<int> some_vec{ 1, 2, 3 };
|
||||
REQUIRE_THAT(some_vec, Catch::Matchers::UnorderedEquals(std::vector<int>{ 3, 2, 1 }));
|
||||
```
|
||||
|
||||
This assertions will pass, because the elements given to the matchers
|
||||
are a permutation of the ones in `some_vec`.
|
||||
|
||||
> vector matchers live in `catch2/matchers/catch_matchers_vector.hpp`
|
||||
|
||||
|
||||
### 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.
|
||||
Catch2 provides 3 matchers that target floating point numbers. These
|
||||
are:
|
||||
|
||||
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.
|
||||
* `WithinAbs(double target, double margin)`,
|
||||
* `WithinUlps(FloatingPoint target, uint64_t maxUlpDiff)`, and
|
||||
* `WithinRel(FloatingPoint target, FloatingPoint eps)`.
|
||||
|
||||
> `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:
|
||||
`WithinAbs` creates a matcher that accepts floating point numbers whose
|
||||
difference with `target` is less than the `margin`.
|
||||
|
||||
`WithinULP` creates a matcher that accepts floating point numbers that
|
||||
are no more than `maxUlpDiff`
|
||||
[ULPs](https://en.wikipedia.org/wiki/Unit_in_the_last_place)
|
||||
away from the `target` value. The short version of what this means
|
||||
is that there is no more than `maxUlpDiff - 1` representeable floating
|
||||
point numbers between the argument for matching and the `target` value.
|
||||
|
||||
`WithinRel` creates a matcher that accepts floating point numbers that
|
||||
are _approximately equal_ with the `target` with tolerance of `eps.`
|
||||
Specifically, it matches if
|
||||
`|arg - target| <= eps * max(|arg|, |target|)` holds. If you do not
|
||||
specify `eps`, `std::numeric_limits<FloatingPoint>::epsilon * 100`
|
||||
is used as the default.
|
||||
|
||||
|
||||
In practice, you will often want to combine multiple of these matchers,
|
||||
together for an assertion, because all 3 options have edge cases where
|
||||
they behave differently than you would expect. As an example, under
|
||||
the `WithinRel` matcher, a `0.` only ever matches a `0.` (or `-0.`),
|
||||
regardless of the relative tolerance specified. Thus, if you want to
|
||||
handle numbers that are "close enough to 0 to be 0", you have to combine
|
||||
it with the `WithinAbs` matcher.
|
||||
|
||||
For example, to check that our computation matches known good value
|
||||
within 0.1%, or is close enough (no different to 5 decimal places)
|
||||
to zero, we would write this assertion:
|
||||
```cpp
|
||||
REQUIRE_THAT( computation(input),
|
||||
Catch::Matchers::WithinRel(expected, 0.001)
|
||||
|| Catch::Matchers::WithinAbs(0, 0.000001) );
|
||||
```
|
||||
|
||||
|
||||
> floating point matchers live in `catch2/matchers/catch_matchers_floating.hpp`
|
||||
|
||||
|
||||
### Miscellaneous matchers
|
||||
|
||||
Catch2 also provides some matchers and matcher utilities that do not
|
||||
quite fit into other categories.
|
||||
|
||||
The first one of them is the `Predicate(Callable pred, std::string description)`
|
||||
matcher. It creates a matcher object that calls `pred` for the provided
|
||||
argument. The `description` argument allows users to set what the
|
||||
resulting matcher should self-describe as if required.
|
||||
|
||||
Do note that you will need to explicitly specify the type of the
|
||||
argument, like in this example:
|
||||
|
||||
```cpp
|
||||
REQUIRE_THAT("Hello olleH",
|
||||
Predicate<std::string>(
|
||||
@ -123,84 +211,175 @@ REQUIRE_THAT("Hello olleH",
|
||||
);
|
||||
```
|
||||
|
||||
The second argument is an optional description of the predicate, and is
|
||||
used only during reporting of the result.
|
||||
> the predicate matcher lives in `catch2/matchers/catch_matchers_predicate.hpp`
|
||||
|
||||
|
||||
### 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 other miscellaneous matcher utility is exception matching.
|
||||
|
||||
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
|
||||
#### Matching exceptions
|
||||
|
||||
Catch2 provides an utility macro for asserting that an expression
|
||||
throws exception of specific type, and that the exception has desired
|
||||
properties. The macro is `REQUIRE_THROWS_MATCHES(expr, ExceptionType, Matcher)`.
|
||||
|
||||
> `REQUIRE_THROWS_MATCHES` macro lives in `catch2/matchers/catch_matchers.hpp`
|
||||
|
||||
|
||||
Catch2 currently provides only one matcher for exceptions,
|
||||
`Message(std::string message)`. `Message` checks that the exception's
|
||||
message, as returned from `what` is exactly equal to `message`.
|
||||
|
||||
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.
|
||||
Note that `DerivedException` in the example above has to derive from
|
||||
`std::exception` for the example to work.
|
||||
|
||||
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.
|
||||
> the exception message matcher lives in `catch2/matchers/catch_matchers_exception.hpp`
|
||||
|
||||
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):
|
||||
|
||||
|
||||
## Writing custom matchers (old style)
|
||||
|
||||
The old style of writing matchers has been introduced back in Catch
|
||||
Classic. To create an old-style matcher, you have to create your own
|
||||
type that derives from `Catch::Matchers::MatcherBase<ArgT>`, where
|
||||
`ArgT` is the type your matcher works for. Your type has to override
|
||||
two methods, `bool match(ArgT const&) const`,
|
||||
and `std::string describe() const`.
|
||||
|
||||
As the name suggests, `match` decides whether the provided argument
|
||||
is matched (accepted) by the matcher. `describe` then provides a
|
||||
human-oriented description of what the matcher does.
|
||||
|
||||
We also recommend that you create factory function, just like Catch2
|
||||
does, but that is mostly useful for template argument deduction for
|
||||
templated matchers (assuming you do not have CTAD available).
|
||||
|
||||
To combine these into an example, let's say that you want to write
|
||||
a matcher that decides whether the provided argument is a number
|
||||
within certain range. We will call it `IsBetweenMatcher<T>`:
|
||||
|
||||
```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 ) {}
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
// ...
|
||||
|
||||
// Performs the test for this matcher
|
||||
bool match( int const& i ) const override {
|
||||
return i >= m_begin && i <= m_end;
|
||||
|
||||
template <typename T>
|
||||
class IsBetweenMatcher : public Catch::Matchers::MatcherBase<T> {
|
||||
T m_begin, m_end;
|
||||
public:
|
||||
IsBetweenMatcher(T begin, T end) : m_begin(begin), m_end(end) {}
|
||||
|
||||
bool match(T const& in) const override {
|
||||
return in >= m_begin && in <= 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::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 );
|
||||
template <typename T>
|
||||
IsBetweenMatcher<T> IsBetween(T begin, T end) {
|
||||
return { begin, end };
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
// Usage
|
||||
TEST_CASE("Integers are within a range")
|
||||
{
|
||||
CHECK_THAT( 3, IsBetween( 1, 10 ) );
|
||||
CHECK_THAT( 100, IsBetween( 1, 10 ) );
|
||||
TEST_CASE("Numbers are within range") {
|
||||
// infers `double` for the argument type of the matcher
|
||||
CHECK_THAT(3., IsBetween(1., 10.));
|
||||
// infers `int` for the argument type of the matcher
|
||||
CHECK_THAT(100, IsBetween(1, 10));
|
||||
}
|
||||
```
|
||||
|
||||
Running this test gives the following in the console:
|
||||
Obviously, the code above can be improved somewhat, for example you
|
||||
might want to `static_assert` over the fact that `T` is an arithmetic
|
||||
type... or generalize the matcher to cover any type for which the user
|
||||
can provide a comparison function object.
|
||||
|
||||
Note that while any matcher written using the old style can also be
|
||||
written using the new style, combining old style matchers should
|
||||
generally compile faster. Also note that you can combine old and new
|
||||
style matchers arbitrarily.
|
||||
|
||||
> `MatcherBase` lives in `catch2/matchers/catch_matchers.hpp`
|
||||
|
||||
|
||||
## Writing custom matchers (new style)
|
||||
|
||||
The new style of writing matchers has been introduced in Catch2 v3.
|
||||
To create a new-style matcher, you have to create your own type that
|
||||
derives from `Catch::Matchers::MatcherGenericBase`. Your type has to
|
||||
also provide two methods, `bool match( ... ) const` and overriden
|
||||
`std::string describe() const`.
|
||||
|
||||
Unlike with old-style matchers, there are no requirements on how
|
||||
the `match` member function takes its argument. This means that the
|
||||
argument can be taken by value or by mutating reference, but also that
|
||||
the matcher's `match` member function can be templated.
|
||||
|
||||
This allows you to write more complex matcher, such as a matcher that
|
||||
can compare one range-like (something that responds to `begin` and
|
||||
`end`) object to another, like in the following example:
|
||||
|
||||
```cpp
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_templated.hpp>
|
||||
// ...
|
||||
|
||||
template<typename Range>
|
||||
struct EqualsRangeMatcher : Catch::Matchers::MatcherGenericBase {
|
||||
EqualsRangeMatcher(Range const& range):
|
||||
range{ range }
|
||||
{}
|
||||
|
||||
template<typename OtherRange>
|
||||
bool match(OtherRange const& other) const {
|
||||
using std::begin; using std::end;
|
||||
|
||||
return std::equal(begin(range), end(range), begin(other), end(other));
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "Equals: " + Catch::rangeToString(range);
|
||||
}
|
||||
|
||||
private:
|
||||
Range const& range;
|
||||
};
|
||||
|
||||
template<typename Range>
|
||||
auto EqualsRange(const Range& range) -> EqualsRangeMatcher<Range> {
|
||||
return EqualsRangeMatcher<Range>{range};
|
||||
}
|
||||
|
||||
TEST_CASE("Combining templated matchers", "[matchers][templated]") {
|
||||
std::array<int, 3> container{{ 1,2,3 }};
|
||||
|
||||
std::array<int, 3> a{{ 1,2,3 }};
|
||||
std::vector<int> b{ 0,1,2 };
|
||||
std::list<int> c{ 4,5,6 };
|
||||
|
||||
REQUIRE_THAT(container, EqualsRange(a) || EqualsRange(b) || EqualsRange(c));
|
||||
}
|
||||
```
|
||||
/**/TestFile.cpp:123: FAILED:
|
||||
CHECK_THAT( 100, IsBetween( 1, 10 ) )
|
||||
with expansion:
|
||||
100 is between 1 and 10
|
||||
```
|
||||
|
||||
Do note that while you can rewrite any matcher from the old style to
|
||||
a new style matcher, combining new style matchers is more expensive
|
||||
in terms of compilation time. Also note that you can combine old style
|
||||
and new style matchers arbitrarily.
|
||||
|
||||
> `MatcherGenericBase` lives in `catch2/matchers/catch_matchers_templated.hpp`
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
@ -58,9 +58,18 @@
|
||||
* This does not change `TEST_CASE` and friends in any way
|
||||
* `IStreamingReporter::IsMulti` member function was removed
|
||||
* This is _very_ unlikely to actually affect anyone, as it was default-implemented in the interface, and only used internally
|
||||
* Various classes not designed for user-extension have been made final
|
||||
* `ListeningReporter` is now `final`
|
||||
* Concrete Matchers (e.g. `UnorderedEquals` vector matcher) are now `final`
|
||||
* `ListeningReporter` is now final
|
||||
|
||||
|
||||
### Improvements
|
||||
* Matchers have been extended with the ability to use different signatures of `match` (#1307, #1553, #1554, #1843)
|
||||
* This includes having templated `match` member function
|
||||
* See the [rewritten Matchers documentation](matchers.md#top) for details
|
||||
|
||||
|
||||
### Fixes
|
||||
* The `INFO` macro no longer contains superfluous semicolon (#1456)
|
||||
* The `--list*` family of command line flags now return 0 on success (#1410, #1146)
|
||||
|
@ -33,13 +33,14 @@ set(BENCHMARK_SOURCES
|
||||
SOURCE_GROUP("benchmark" FILES ${BENCHMARK_HEADERS} ${BENCHMARK_SOURCES})
|
||||
|
||||
set(INTERNAL_HEADERS
|
||||
${SOURCES_DIR}/internal/catch_capture_matchers.h
|
||||
${SOURCES_DIR}/internal/catch_container_nonmembers.hpp
|
||||
${SOURCES_DIR}/catch.hpp
|
||||
${SOURCES_DIR}/catch_approx.h
|
||||
${SOURCES_DIR}/catch_assertionhandler.h
|
||||
${SOURCES_DIR}/catch_assertioninfo.h
|
||||
${SOURCES_DIR}/catch_assertionresult.h
|
||||
${SOURCES_DIR}/catch_capture.hpp
|
||||
${SOURCES_DIR}/internal/catch_capture_matchers.h
|
||||
${SOURCES_DIR}/catch_clara.h
|
||||
${SOURCES_DIR}/catch_commandline.h
|
||||
${SOURCES_DIR}/catch_common.h
|
||||
@ -72,13 +73,15 @@ set(INTERNAL_HEADERS
|
||||
${SOURCES_DIR}/catch_interfaces_testcase.h
|
||||
${SOURCES_DIR}/catch_leak_detector.h
|
||||
${SOURCES_DIR}/catch_list.h
|
||||
${SOURCES_DIR}/matchers/catch_matchers.h
|
||||
${SOURCES_DIR}/matchers/catch_matchers.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_container_properties.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_contains.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_exception.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_floating.h
|
||||
${SOURCES_DIR}/matchers/catch_matchers_generic.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_string.h
|
||||
${SOURCES_DIR}/matchers/catch_matchers_templates.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_vector.h
|
||||
${SOURCES_DIR}/matchers/catch_matchers_floating.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_predicate.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_string.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_templated.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_vector.hpp
|
||||
${SOURCES_DIR}/catch_message.h
|
||||
${SOURCES_DIR}/catch_meta.hpp
|
||||
${SOURCES_DIR}/catch_objc.hpp
|
||||
@ -156,11 +159,12 @@ set(IMPL_SOURCES
|
||||
${SOURCES_DIR}/catch_list.cpp
|
||||
${SOURCES_DIR}/catch_leak_detector.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_container_properties.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_exception.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_floating.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_generic.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_predicate.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_string.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_templates.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_templated.cpp
|
||||
${SOURCES_DIR}/catch_message.cpp
|
||||
${SOURCES_DIR}/catch_output_redirect.cpp
|
||||
${SOURCES_DIR}/catch_registry_hub.cpp
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <catch2/catch_interfaces_registry_hub.h>
|
||||
#include <catch2/internal/catch_capture_matchers.h>
|
||||
#include <catch2/catch_run_context.h>
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include <catch2/internal/catch_capture_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/catch_interfaces_registry_hub.h>
|
||||
|
||||
namespace Catch {
|
||||
|
67
src/catch2/internal/catch_container_nonmembers.hpp
Normal file
67
src/catch2/internal/catch_container_nonmembers.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_compiler_capabilities.h>
|
||||
|
||||
|
||||
// We want a simple polyfill over `std::empty`, `std::size` and so on
|
||||
// for C++14 or C++ libraries with incomplete support.
|
||||
// We also have to handle that MSVC std lib will happily provide these
|
||||
// under older standards.
|
||||
#if defined(CATCH_CPP17_OR_GREATER) || defined(_MSC_VER)
|
||||
|
||||
// We are already using this header either way, so there shouldn't
|
||||
// be much additional overhead in including it to get the feature
|
||||
// test macros
|
||||
#include <string>
|
||||
|
||||
# if !defined(__cpp_lib_nonmember_container_access)
|
||||
# define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
|
||||
# endif
|
||||
|
||||
#else
|
||||
#define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
|
||||
template <typename Container>
|
||||
constexpr auto empty(Container const& cont) -> decltype(cont.empty()) {
|
||||
return cont.empty();
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
constexpr bool empty(const T (&)[N]) noexcept {
|
||||
// GCC < 7 does not support the const T(&)[] parameter syntax
|
||||
// so we have to ignore the length explicitly
|
||||
(void)N;
|
||||
return false;
|
||||
}
|
||||
template <typename T>
|
||||
constexpr bool empty(std::initializer_list<T> list) noexcept {
|
||||
return list.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
template <typename Container>
|
||||
constexpr auto size(Container const& cont) -> decltype(cont.size()) {
|
||||
return cont.size();
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
constexpr std::size_t size(const T(&)[N]) noexcept {
|
||||
return N;
|
||||
}
|
||||
#endif // CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
|
||||
|
||||
} // end namespace Detail
|
||||
} // end namespace Catch
|
||||
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
|
@ -3,7 +3,7 @@
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
30
src/catch2/matchers/catch_matchers_container_properties.cpp
Normal file
30
src/catch2/matchers/catch_matchers_container_properties.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <catch2/matchers/catch_matchers_container_properties.hpp>
|
||||
|
||||
#include <catch2/catch_stream.h>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
|
||||
std::string IsEmptyMatcher::describe() const {
|
||||
return "is empty";
|
||||
}
|
||||
|
||||
std::string HasSizeMatcher::describe() const {
|
||||
ReusableStringStream sstr;
|
||||
sstr << "has size == " << m_target_size;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
IsEmptyMatcher IsEmpty() {
|
||||
return {};
|
||||
}
|
||||
|
||||
HasSizeMatcher SizeIs(std::size_t sz) {
|
||||
return HasSizeMatcher{ sz };
|
||||
}
|
||||
|
||||
} // end namespace Matchers
|
||||
} // end namespace Catch
|
86
src/catch2/matchers/catch_matchers_container_properties.hpp
Normal file
86
src/catch2/matchers/catch_matchers_container_properties.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
|
||||
|
||||
#include <catch2/matchers/catch_matchers_templated.hpp>
|
||||
#include <catch2/internal/catch_container_nonmembers.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
|
||||
class IsEmptyMatcher final : public MatcherGenericBase {
|
||||
public:
|
||||
// todo: Use polyfills
|
||||
template <typename RangeLike>
|
||||
bool match(RangeLike&& rng) const {
|
||||
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
|
||||
using Catch::Detail::empty;
|
||||
#else
|
||||
using std::empty;
|
||||
#endif
|
||||
return empty(rng);
|
||||
}
|
||||
|
||||
std::string describe() const override;
|
||||
};
|
||||
|
||||
class HasSizeMatcher final : public MatcherGenericBase {
|
||||
std::size_t m_target_size;
|
||||
public:
|
||||
explicit HasSizeMatcher(std::size_t target_size):
|
||||
m_target_size(target_size)
|
||||
{}
|
||||
|
||||
template <typename RangeLike>
|
||||
bool match(RangeLike&& rng) const {
|
||||
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
|
||||
using Catch::Detail::size;
|
||||
#else
|
||||
using std::size;
|
||||
#endif
|
||||
return size(rng) == m_target_size;
|
||||
}
|
||||
|
||||
std::string describe() const override;
|
||||
};
|
||||
|
||||
template <typename Matcher>
|
||||
class SizeMatchesMatcher final : public MatcherGenericBase {
|
||||
Matcher m_matcher;
|
||||
public:
|
||||
explicit SizeMatchesMatcher(Matcher m):
|
||||
m_matcher(std::move(m))
|
||||
{}
|
||||
|
||||
template <typename RangeLike>
|
||||
bool match(RangeLike&& rng) const {
|
||||
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
|
||||
using Catch::Detail::size;
|
||||
#else
|
||||
using std::size;
|
||||
#endif
|
||||
return m_matcher.match(size(rng));
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "size matches " + m_matcher.describe();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//! Creates a matcher that accepts empty ranges/containers
|
||||
IsEmptyMatcher IsEmpty();
|
||||
//! Creates a matcher that accepts ranges/containers with specific size
|
||||
HasSizeMatcher SizeIs(std::size_t sz);
|
||||
template <typename Matcher>
|
||||
std::enable_if_t<Detail::is_matcher<Matcher>::value,
|
||||
SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) {
|
||||
return SizeMatchesMatcher<Matcher>{std::forward<Matcher>(m)};
|
||||
}
|
||||
|
||||
} // end namespace Matchers
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
|
102
src/catch2/matchers/catch_matchers_contains.hpp
Normal file
102
src/catch2/matchers/catch_matchers_contains.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/matchers/catch_matchers_templated.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
//! Matcher for checking that an element in range is equal to specific element
|
||||
template <typename T, typename Equality>
|
||||
class ContainsElementMatcher final : public MatcherGenericBase {
|
||||
T m_desired;
|
||||
Equality m_eq;
|
||||
public:
|
||||
template <typename T2, typename Equality2>
|
||||
ContainsElementMatcher(T2&& target, Equality2&& predicate):
|
||||
m_desired(std::forward<T2>(target)),
|
||||
m_eq(std::forward<Equality2>(predicate))
|
||||
{}
|
||||
|
||||
std::string describe() const override {
|
||||
return "contains element " + Catch::Detail::stringify(m_desired);
|
||||
}
|
||||
|
||||
template <typename RangeLike>
|
||||
bool match(RangeLike&& rng) const {
|
||||
using std::begin; using std::end;
|
||||
|
||||
return end(rng) != std::find_if(begin(rng), end(rng),
|
||||
[&](auto const& elem) {
|
||||
return m_eq(elem, m_desired);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//! Meta-matcher for checking that an element in a range matches a specific matcher
|
||||
template <typename Matcher>
|
||||
class ContainsMatcherMatcher final : public MatcherGenericBase {
|
||||
Matcher m_matcher;
|
||||
public:
|
||||
// Note that we do a copy+move to avoid having to SFINAE this
|
||||
// constructor (and also avoid some perfect forwarding failure
|
||||
// cases)
|
||||
ContainsMatcherMatcher(Matcher matcher):
|
||||
m_matcher(std::move(matcher))
|
||||
{}
|
||||
|
||||
template <typename RangeLike>
|
||||
bool match(RangeLike&& rng) const {
|
||||
using std::begin; using std::endl;
|
||||
for (auto&& elem : rng) {
|
||||
if (m_matcher.match(elem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "contains element matching " + m_matcher.describe();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a matcher that checks whether a range contains a specific element.
|
||||
*
|
||||
* Uses `std::equal_to` to do the comparison
|
||||
*/
|
||||
template <typename T>
|
||||
std::enable_if_t<!Detail::is_matcher<T>::value,
|
||||
ContainsElementMatcher<T, std::equal_to<>>> Contains(T&& elem) {
|
||||
return { std::forward<T>(elem), std::equal_to<>{} };
|
||||
}
|
||||
|
||||
//! Creates a matcher that checks whether a range contains element matching a matcher
|
||||
template <typename Matcher>
|
||||
std::enable_if_t<Detail::is_matcher<Matcher>::value,
|
||||
ContainsMatcherMatcher<Matcher>> Contains(Matcher&& matcher) {
|
||||
return { std::forward<Matcher>(matcher) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a matcher that checks whether a range contains a specific element.
|
||||
*
|
||||
* Uses `eq` to do the comparisons
|
||||
*/
|
||||
template <typename T, typename Equality>
|
||||
ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
|
||||
return { std::forward<T>(elem), std::forward<Equality>(eq) };
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
|
@ -7,13 +7,13 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
|
||||
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
namespace Exception {
|
||||
|
||||
class ExceptionMessageMatcher : public MatcherBase<std::exception> {
|
||||
class ExceptionMessageMatcher final : public MatcherBase<std::exception> {
|
||||
std::string m_message;
|
||||
public:
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating.h>
|
||||
#include <catch2/matchers/catch_matchers_floating.hpp>
|
||||
#include <catch2/catch_enforce.h>
|
||||
#include <catch2/catch_polyfills.hpp>
|
||||
#include <catch2/catch_to_string.hpp>
|
||||
|
@ -7,7 +7,7 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_FLOATING_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_FLOATING_H_INCLUDED
|
||||
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
@ -16,7 +16,7 @@ namespace Matchers {
|
||||
|
||||
enum class FloatingPointKind : uint8_t;
|
||||
|
||||
struct WithinAbsMatcher : MatcherBase<double> {
|
||||
struct WithinAbsMatcher final : MatcherBase<double> {
|
||||
WithinAbsMatcher(double target, double margin);
|
||||
bool match(double const& matchee) const override;
|
||||
std::string describe() const override;
|
||||
@ -25,7 +25,7 @@ namespace Matchers {
|
||||
double m_margin;
|
||||
};
|
||||
|
||||
struct WithinUlpsMatcher : MatcherBase<double> {
|
||||
struct WithinUlpsMatcher final : MatcherBase<double> {
|
||||
WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
|
||||
bool match(double const& matchee) const override;
|
||||
std::string describe() const override;
|
||||
@ -41,7 +41,7 @@ namespace Matchers {
|
||||
// |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
|
||||
// the same result if we do this for floats, as if we do this for
|
||||
// doubles that were promoted from floats.
|
||||
struct WithinRelMatcher : MatcherBase<double> {
|
||||
struct WithinRelMatcher final : MatcherBase<double> {
|
||||
WithinRelMatcher(double target, double epsilon);
|
||||
bool match(double const& matchee) const override;
|
||||
std::string describe() const override;
|
@ -1,4 +1,4 @@
|
||||
#include <catch2/matchers/catch_matchers_generic.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
|
||||
std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {
|
||||
if (desc.empty()) {
|
@ -8,7 +8,7 @@
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_common.h>
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/catch_meta.hpp>
|
||||
|
||||
#include <string>
|
||||
@ -23,7 +23,7 @@ namespace Detail {
|
||||
}
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
class PredicateMatcher : public MatcherBase<T> {
|
||||
class PredicateMatcher final : public MatcherBase<T> {
|
||||
Predicate m_predicate;
|
||||
std::string m_description;
|
||||
public:
|
@ -3,7 +3,7 @@
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/catch_string_manip.h>
|
||||
#include <catch2/catch_tostring.h>
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
|
||||
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -35,24 +35,24 @@ namespace Matchers {
|
||||
std::string m_operation;
|
||||
};
|
||||
|
||||
struct EqualsMatcher : StringMatcherBase {
|
||||
struct EqualsMatcher final : StringMatcherBase {
|
||||
EqualsMatcher( CasedString const& comparator );
|
||||
bool match( std::string const& source ) const override;
|
||||
};
|
||||
struct ContainsMatcher : StringMatcherBase {
|
||||
struct ContainsMatcher final : StringMatcherBase {
|
||||
ContainsMatcher( CasedString const& comparator );
|
||||
bool match( std::string const& source ) const override;
|
||||
};
|
||||
struct StartsWithMatcher : StringMatcherBase {
|
||||
struct StartsWithMatcher final : StringMatcherBase {
|
||||
StartsWithMatcher( CasedString const& comparator );
|
||||
bool match( std::string const& source ) const override;
|
||||
};
|
||||
struct EndsWithMatcher : StringMatcherBase {
|
||||
struct EndsWithMatcher final : StringMatcherBase {
|
||||
EndsWithMatcher( CasedString const& comparator );
|
||||
bool match( std::string const& source ) const override;
|
||||
};
|
||||
|
||||
struct RegexMatcher : MatcherBase<std::string> {
|
||||
struct RegexMatcher final : MatcherBase<std::string> {
|
||||
RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );
|
||||
bool match( std::string const& matchee ) const override;
|
||||
std::string describe() const override;
|
@ -1,4 +1,4 @@
|
||||
#include <catch2/matchers/catch_matchers_templates.hpp>
|
||||
#include <catch2/matchers/catch_matchers_templated.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
@ -1,8 +1,11 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_TEMPLATES_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_TEMPLATES_HPP_INCLUDED
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_common.h>
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/catch_stringref.h>
|
||||
|
||||
#include <array>
|
||||
@ -60,7 +63,7 @@ namespace Matchers {
|
||||
template<typename T>
|
||||
using is_generic_matcher = std::is_base_of<
|
||||
Catch::Matchers::MatcherGenericBase,
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type
|
||||
std::remove_cv_t<std::remove_reference_t<T>>
|
||||
>;
|
||||
|
||||
template<typename... Ts>
|
||||
@ -69,7 +72,7 @@ namespace Matchers {
|
||||
template<typename T>
|
||||
using is_matcher = std::is_base_of<
|
||||
Catch::Matchers::MatcherUntypedBase,
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type
|
||||
std::remove_cv_t<std::remove_reference_t<T>>
|
||||
>;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
|
||||
|
||||
#include <catch2/matchers/catch_matchers.h>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/catch_approx.h>
|
||||
|
||||
#include <algorithm>
|
||||
@ -18,7 +18,7 @@ namespace Matchers {
|
||||
|
||||
namespace Vector {
|
||||
template<typename T>
|
||||
struct ContainsElementMatcher : MatcherBase<std::vector<T>> {
|
||||
struct ContainsElementMatcher final : MatcherBase<std::vector<T>> {
|
||||
|
||||
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
|
||||
|
||||
@ -39,7 +39,7 @@ namespace Matchers {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ContainsMatcher : MatcherBase<std::vector<T>> {
|
||||
struct ContainsMatcher final : MatcherBase<std::vector<T>> {
|
||||
|
||||
ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
|
||||
|
||||
@ -69,7 +69,7 @@ namespace Matchers {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct EqualsMatcher : MatcherBase<std::vector<T>> {
|
||||
struct EqualsMatcher final : MatcherBase<std::vector<T>> {
|
||||
|
||||
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
|
||||
|
||||
@ -92,7 +92,7 @@ namespace Matchers {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ApproxMatcher : MatcherBase<std::vector<T>> {
|
||||
struct ApproxMatcher final : MatcherBase<std::vector<T>> {
|
||||
|
||||
ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {}
|
||||
|
||||
@ -128,7 +128,7 @@ namespace Matchers {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> {
|
||||
struct UnorderedEqualsMatcher final : MatcherBase<std::vector<T>> {
|
||||
UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
|
||||
bool match(std::vector<T> const& vec) const override {
|
||||
// Note: This is a reimplementation of std::is_permutation,
|
@ -50,6 +50,7 @@ set(TEST_SOURCES
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringWhich.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Tricky.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/VariadicMacros.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/MatchersRanges.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Matchers.tests.cpp
|
||||
)
|
||||
CheckFileList(TEST_SOURCES ${SELF_TEST_DIR})
|
||||
|
@ -5,8 +5,8 @@
|
||||
// This won't provide full coverage, but it might be worth checking
|
||||
// the other branch as well
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_generic.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
@ -80,6 +80,8 @@ Nor would this
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Arbitrary predicate matcher
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Basic use of the Contains range matcher
|
||||
:test-result: PASS Basic use of the Empty range matcher
|
||||
:test-result: PASS CAPTURE can deal with complex expressions
|
||||
:test-result: PASS CAPTURE can deal with complex expressions involving commas
|
||||
:test-result: PASS CAPTURE parses string and character constants
|
||||
@ -217,6 +219,7 @@ Message from section two
|
||||
:test-result: PASS Tracker
|
||||
:test-result: PASS Trim strings
|
||||
:test-result: FAIL Unexpected exceptions can be translated
|
||||
:test-result: PASS Usage of the SizeIs range matcher
|
||||
:test-result: PASS Use a custom approx
|
||||
:test-result: PASS Variadic macros
|
||||
:test-result: PASS Vector Approx matcher
|
||||
|
@ -244,6 +244,26 @@ Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
MatchersRanges.tests.cpp:<line number>: passed: a, Contains(1) for: { 1, 2, 3 } contains element 1
|
||||
MatchersRanges.tests.cpp:<line number>: passed: b, Contains(1) for: { 0, 1, 2 } contains element 1
|
||||
MatchersRanges.tests.cpp:<line number>: passed: c, !Contains(1) for: { 4, 5, 6 } not contains element 1
|
||||
MatchersRanges.tests.cpp:<line number>: passed: a, Contains(0, close_enough) for: { 1, 2, 3 } contains element 0
|
||||
MatchersRanges.tests.cpp:<line number>: passed: b, Contains(0, close_enough) for: { 0, 1, 2 } contains element 0
|
||||
MatchersRanges.tests.cpp:<line number>: passed: c, !Contains(0, close_enough) for: { 4, 5, 6 } not contains element 0
|
||||
MatchersRanges.tests.cpp:<line number>: passed: a, Contains(4, [](auto&& lhs, size_t sz) { return lhs.size() == sz; }) for: { "abc", "abcd", "abcde" } contains element 4
|
||||
MatchersRanges.tests.cpp:<line number>: passed: in, Contains(1) for: { 1, 2, 3, 4, 5 } contains element 1
|
||||
MatchersRanges.tests.cpp:<line number>: passed: in, !Contains(8) for: { 1, 2, 3, 4, 5 } not contains element 8
|
||||
MatchersRanges.tests.cpp:<line number>: passed: in, Contains(MoveOnlyTestElement{ 2 }) for: { 1, 2, 3 } contains element 2
|
||||
MatchersRanges.tests.cpp:<line number>: passed: in, !Contains(MoveOnlyTestElement{ 9 }) for: { 1, 2, 3 } not contains element 9
|
||||
MatchersRanges.tests.cpp:<line number>: passed: in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)) for: { 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5
|
||||
MatchersRanges.tests.cpp:<line number>: passed: empty_array, IsEmpty() for: { } is empty
|
||||
MatchersRanges.tests.cpp:<line number>: passed: non_empty_array, !IsEmpty() for: { 0.0 } not is empty
|
||||
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, IsEmpty() for: { } is empty
|
||||
MatchersRanges.tests.cpp:<line number>: passed: non_empty_vec, !IsEmpty() for: { 'a', 'b', 'c' } not is empty
|
||||
MatchersRanges.tests.cpp:<line number>: passed: inner_lists_are_empty, !IsEmpty() for: { { } } not is empty
|
||||
MatchersRanges.tests.cpp:<line number>: passed: inner_lists_are_empty.front(), IsEmpty() for: { } is empty
|
||||
MatchersRanges.tests.cpp:<line number>: passed: has_empty{}, !IsEmpty() for: {?} not is empty
|
||||
MatchersRanges.tests.cpp:<line number>: passed: unrelated::ADL_empty{}, IsEmpty() for: {?} is empty
|
||||
Message.tests.cpp:<line number>: passed: with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true'
|
||||
Message.tests.cpp:<line number>: passed: with 7 messages: 'std::vector<int>{1, 2, 3}[0, 1, 2] := 3' and 'std::vector<int>{1, 2, 3}[(0, 1)] := 2' and 'std::vector<int>{1, 2, 3}[0] := 1' and '(helper_1436<int, int>{12, -12}) := { 12, -12 }' and '(helper_1436<int, int>(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3'
|
||||
Message.tests.cpp:<line number>: passed: with 11 messages: '("comma, in string", "escaped, \", ") := "escaped, ", "' and '"single quote in string,'," := "single quote in string,',"' and '"some escapes, \\,\\\\" := "some escapes, \,\\"' and '"some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<"' and ''"' := '"'' and ''\'' := '''' and '',' := ','' and ''}' := '}'' and '')' := ')'' and ''(' := '('' and ''{' := '{''
|
||||
@ -1551,6 +1571,15 @@ StringManip.tests.cpp:<line number>: passed: trim(StringRef(whitespace_at_both_e
|
||||
==
|
||||
There is no extra whitespace here
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: '3.14'
|
||||
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, SizeIs(0) for: { } has size == 0
|
||||
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, !SizeIs(2) for: { } not has size == 2
|
||||
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2
|
||||
MatchersRanges.tests.cpp:<line number>: passed: arr, SizeIs(2) for: { 0, 0 } has size == 2
|
||||
MatchersRanges.tests.cpp:<line number>: passed: arr, SizeIs( Lt(3)) for: { 0, 0 } size matches is less than 3
|
||||
MatchersRanges.tests.cpp:<line number>: passed: arr, !SizeIs(!Lt(3)) for: { 0, 0 } not size matches not is less than 3
|
||||
MatchersRanges.tests.cpp:<line number>: passed: map, SizeIs(3) for: { {?}, {?}, {?} } has size == 3
|
||||
MatchersRanges.tests.cpp:<line number>: passed: unrelated::ADL_size{}, SizeIs(12) for: {?} has size == 12
|
||||
MatchersRanges.tests.cpp:<line number>: passed: has_size{}, SizeIs(13) for: {?} has size == 13
|
||||
Approx.tests.cpp:<line number>: passed: d == approx( 1.23 ) for: 1.23 == Approx( 1.23 )
|
||||
Approx.tests.cpp:<line number>: passed: d == approx( 1.22 ) for: 1.23 == Approx( 1.22 )
|
||||
Approx.tests.cpp:<line number>: passed: d == approx( 1.24 ) for: 1.23 == Approx( 1.24 )
|
||||
|
@ -1380,6 +1380,6 @@ due to unexpected exception with message:
|
||||
Why would you throw a std::string?
|
||||
|
||||
===============================================================================
|
||||
test cases: 328 | 254 passed | 70 failed | 4 failed as expected
|
||||
assertions: 1839 | 1687 passed | 131 failed | 21 failed as expected
|
||||
test cases: 331 | 257 passed | 70 failed | 4 failed as expected
|
||||
assertions: 1868 | 1716 passed | 131 failed | 21 failed as expected
|
||||
|
||||
|
@ -1948,6 +1948,169 @@ Tricky.tests.cpp:<line number>
|
||||
Tricky.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( true )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Contains range matcher
|
||||
Different argument ranges, same element type, default comparison
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( a, Contains(1) )
|
||||
with expansion:
|
||||
{ 1, 2, 3 } contains element 1
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( b, Contains(1) )
|
||||
with expansion:
|
||||
{ 0, 1, 2 } contains element 1
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( c, !Contains(1) )
|
||||
with expansion:
|
||||
{ 4, 5, 6 } not contains element 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Contains range matcher
|
||||
Different argument ranges, same element type, custom comparison
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( a, Contains(0, close_enough) )
|
||||
with expansion:
|
||||
{ 1, 2, 3 } contains element 0
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( b, Contains(0, close_enough) )
|
||||
with expansion:
|
||||
{ 0, 1, 2 } contains element 0
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( c, !Contains(0, close_enough) )
|
||||
with expansion:
|
||||
{ 4, 5, 6 } not contains element 0
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Contains range matcher
|
||||
Different element type, custom comparisons
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( a, Contains(4, [](auto&& lhs, size_t sz) { return lhs.size() == sz; }) )
|
||||
with expansion:
|
||||
{ "abc", "abcd", "abcde" } contains element 4
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Contains range matcher
|
||||
Can handle type that requires ADL-found free function begin and end
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( in, Contains(1) )
|
||||
with expansion:
|
||||
{ 1, 2, 3, 4, 5 } contains element 1
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( in, !Contains(8) )
|
||||
with expansion:
|
||||
{ 1, 2, 3, 4, 5 } not contains element 8
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Contains range matcher
|
||||
Initialization with move only types
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( in, Contains(MoveOnlyTestElement{ 2 }) )
|
||||
with expansion:
|
||||
{ 1, 2, 3 } contains element 2
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( in, !Contains(MoveOnlyTestElement{ 9 }) )
|
||||
with expansion:
|
||||
{ 1, 2, 3 } not contains element 9
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Contains range matcher
|
||||
Matching using matcher
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)) )
|
||||
with expansion:
|
||||
{ 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Empty range matcher
|
||||
Simple, std-provided containers
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( empty_array, IsEmpty() )
|
||||
with expansion:
|
||||
{ } is empty
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( non_empty_array, !IsEmpty() )
|
||||
with expansion:
|
||||
{ 0.0 } not is empty
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( empty_vec, IsEmpty() )
|
||||
with expansion:
|
||||
{ } is empty
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( non_empty_vec, !IsEmpty() )
|
||||
with expansion:
|
||||
{ 'a', 'b', 'c' } not is empty
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( inner_lists_are_empty, !IsEmpty() )
|
||||
with expansion:
|
||||
{ { } } not is empty
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( inner_lists_are_empty.front(), IsEmpty() )
|
||||
with expansion:
|
||||
{ } is empty
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Empty range matcher
|
||||
Type with empty
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( has_empty{}, !IsEmpty() )
|
||||
with expansion:
|
||||
{?} not is empty
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Basic use of the Empty range matcher
|
||||
Type requires ADL found empty free function
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( unrelated::ADL_empty{}, IsEmpty() )
|
||||
with expansion:
|
||||
{?} is empty
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
CAPTURE can deal with complex expressions
|
||||
-------------------------------------------------------------------------------
|
||||
@ -11277,6 +11440,72 @@ Exception.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with message:
|
||||
3.14
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Usage of the SizeIs range matcher
|
||||
Some with stdlib containers
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( empty_vec, SizeIs(0) )
|
||||
with expansion:
|
||||
{ } has size == 0
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( empty_vec, !SizeIs(2) )
|
||||
with expansion:
|
||||
{ } not has size == 2
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( empty_vec, SizeIs(Lt(2)) )
|
||||
with expansion:
|
||||
{ } size matches is less than 2
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( arr, SizeIs(2) )
|
||||
with expansion:
|
||||
{ 0, 0 } has size == 2
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( arr, SizeIs( Lt(3)) )
|
||||
with expansion:
|
||||
{ 0, 0 } size matches is less than 3
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( arr, !SizeIs(!Lt(3)) )
|
||||
with expansion:
|
||||
{ 0, 0 } not size matches not is less than 3
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( map, SizeIs(3) )
|
||||
with expansion:
|
||||
{ {?}, {?}, {?} } has size == 3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Usage of the SizeIs range matcher
|
||||
Type requires ADL found size free function
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( unrelated::ADL_size{}, SizeIs(12) )
|
||||
with expansion:
|
||||
{?} has size == 12
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Usage of the SizeIs range matcher
|
||||
Type has size member
|
||||
-------------------------------------------------------------------------------
|
||||
MatchersRanges.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
MatchersRanges.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( has_size{}, SizeIs(13) )
|
||||
with expansion:
|
||||
{?} has size == 13
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Use a custom approx
|
||||
-------------------------------------------------------------------------------
|
||||
@ -14396,6 +14625,6 @@ Misc.tests.cpp:<line number>
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
===============================================================================
|
||||
test cases: 328 | 238 passed | 86 failed | 4 failed as expected
|
||||
assertions: 1856 | 1687 passed | 148 failed | 21 failed as expected
|
||||
test cases: 331 | 241 passed | 86 failed | 4 failed as expected
|
||||
assertions: 1885 | 1716 passed | 148 failed | 21 failed as expected
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuitesloose text artifact
|
||||
>
|
||||
<testsuite name="<exe-name>" errors="17" failures="132" tests="1857" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuite name="<exe-name>" errors="17" failures="132" tests="1886" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<properties>
|
||||
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/>
|
||||
<property name="random-seed" value="1"/>
|
||||
@ -342,6 +342,15 @@ Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections/A section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another other section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Different argument ranges, same element type, default comparison" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Different argument ranges, same element type, custom comparison" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Different element type, custom comparisons" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Can handle type that requires ADL-found free function begin and end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Initialization with move only types" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Matching using matcher" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Empty range matcher/Simple, std-provided containers" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Empty range matcher/Type with empty" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Basic use of the Empty range matcher/Type requires ADL found empty free function" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions involving commas" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="CAPTURE parses string and character constants" time="{duration}"/>
|
||||
@ -1243,6 +1252,9 @@ FAILED:
|
||||
Exception.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Some with stdlib containers" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Type requires ADL found size free function" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Type has size member" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Use a custom approx" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Variadic macros/Section with one argument" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Vector Approx matcher/Empty vector is roughly equal to an empty vector" time="{duration}"/>
|
||||
|
@ -1215,6 +1215,20 @@ Matchers.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testCase>
|
||||
</file>
|
||||
<file path="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp">
|
||||
<testCase name="Basic use of the Contains range matcher/Different argument ranges, same element type, default comparison" duration="{duration}"/>
|
||||
<testCase name="Basic use of the Contains range matcher/Different argument ranges, same element type, custom comparison" duration="{duration}"/>
|
||||
<testCase name="Basic use of the Contains range matcher/Different element type, custom comparisons" duration="{duration}"/>
|
||||
<testCase name="Basic use of the Contains range matcher/Can handle type that requires ADL-found free function begin and end" duration="{duration}"/>
|
||||
<testCase name="Basic use of the Contains range matcher/Initialization with move only types" duration="{duration}"/>
|
||||
<testCase name="Basic use of the Contains range matcher/Matching using matcher" duration="{duration}"/>
|
||||
<testCase name="Basic use of the Empty range matcher/Simple, std-provided containers" duration="{duration}"/>
|
||||
<testCase name="Basic use of the Empty range matcher/Type with empty" duration="{duration}"/>
|
||||
<testCase name="Basic use of the Empty range matcher/Type requires ADL found empty free function" duration="{duration}"/>
|
||||
<testCase name="Usage of the SizeIs range matcher/Some with stdlib containers" duration="{duration}"/>
|
||||
<testCase name="Usage of the SizeIs range matcher/Type requires ADL found size free function" duration="{duration}"/>
|
||||
<testCase name="Usage of the SizeIs range matcher/Type has size member" duration="{duration}"/>
|
||||
</file>
|
||||
<file path="tests/<exe-name>/UsageTests/Message.tests.cpp">
|
||||
<testCase name="#1455 - INFO and WARN can start with a linebreak" duration="{duration}"/>
|
||||
<testCase name="CAPTURE can deal with complex expressions" duration="{duration}"/>
|
||||
|
@ -486,6 +486,46 @@ ok {test-number} - true
|
||||
ok {test-number} - true
|
||||
# Assertions then sections
|
||||
ok {test-number} - true
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - a, Contains(1) for: { 1, 2, 3 } contains element 1
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - b, Contains(1) for: { 0, 1, 2 } contains element 1
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - c, !Contains(1) for: { 4, 5, 6 } not contains element 1
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - a, Contains(0, close_enough) for: { 1, 2, 3 } contains element 0
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - b, Contains(0, close_enough) for: { 0, 1, 2 } contains element 0
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - c, !Contains(0, close_enough) for: { 4, 5, 6 } not contains element 0
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - a, Contains(4, [](auto&& lhs, size_t sz) { return lhs.size() == sz; }) for: { "abc", "abcd", "abcde" } contains element 4
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - in, Contains(1) for: { 1, 2, 3, 4, 5 } contains element 1
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - in, !Contains(8) for: { 1, 2, 3, 4, 5 } not contains element 8
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - in, Contains(MoveOnlyTestElement{ 2 }) for: { 1, 2, 3 } contains element 2
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - in, !Contains(MoveOnlyTestElement{ 9 }) for: { 1, 2, 3 } not contains element 9
|
||||
# Basic use of the Contains range matcher
|
||||
ok {test-number} - in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)) for: { 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5
|
||||
# Basic use of the Empty range matcher
|
||||
ok {test-number} - empty_array, IsEmpty() for: { } is empty
|
||||
# Basic use of the Empty range matcher
|
||||
ok {test-number} - non_empty_array, !IsEmpty() for: { 0.0 } not is empty
|
||||
# Basic use of the Empty range matcher
|
||||
ok {test-number} - empty_vec, IsEmpty() for: { } is empty
|
||||
# Basic use of the Empty range matcher
|
||||
ok {test-number} - non_empty_vec, !IsEmpty() for: { 'a', 'b', 'c' } not is empty
|
||||
# Basic use of the Empty range matcher
|
||||
ok {test-number} - inner_lists_are_empty, !IsEmpty() for: { { } } not is empty
|
||||
# Basic use of the Empty range matcher
|
||||
ok {test-number} - inner_lists_are_empty.front(), IsEmpty() for: { } is empty
|
||||
# Basic use of the Empty range matcher
|
||||
ok {test-number} - has_empty{}, !IsEmpty() for: {?} not is empty
|
||||
# Basic use of the Empty range matcher
|
||||
ok {test-number} - unrelated::ADL_empty{}, IsEmpty() for: {?} is empty
|
||||
# CAPTURE can deal with complex expressions
|
||||
ok {test-number} - with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true'
|
||||
# CAPTURE can deal with complex expressions involving commas
|
||||
@ -2949,6 +2989,24 @@ ok {test-number} - trim(StringRef(trailing_whitespace)) == StringRef(no_whitespa
|
||||
ok {test-number} - trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here
|
||||
# Unexpected exceptions can be translated
|
||||
not ok {test-number} - unexpected exception with message: '3.14'
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - empty_vec, SizeIs(0) for: { } has size == 0
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - empty_vec, !SizeIs(2) for: { } not has size == 2
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - arr, SizeIs(2) for: { 0, 0 } has size == 2
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - arr, SizeIs( Lt(3)) for: { 0, 0 } size matches is less than 3
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - arr, !SizeIs(!Lt(3)) for: { 0, 0 } not size matches not is less than 3
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - map, SizeIs(3) for: { {?}, {?}, {?} } has size == 3
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - unrelated::ADL_size{}, SizeIs(12) for: {?} has size == 12
|
||||
# Usage of the SizeIs range matcher
|
||||
ok {test-number} - has_size{}, SizeIs(13) for: {?} has size == 13
|
||||
# Use a custom approx
|
||||
ok {test-number} - d == approx( 1.23 ) for: 1.23 == Approx( 1.23 )
|
||||
# Use a custom approx
|
||||
@ -3704,5 +3762,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
|
||||
ok {test-number} -
|
||||
# xmlentitycheck
|
||||
ok {test-number} -
|
||||
1..1848
|
||||
1..1877
|
||||
|
||||
|
@ -193,6 +193,10 @@ Exception.tests.cpp:<line number>|nunexpected exception with message:|n "unexpe
|
||||
##teamcity[testFinished name='Arbitrary predicate matcher' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertions then sections']
|
||||
##teamcity[testFinished name='Assertions then sections' duration="{duration}"]
|
||||
##teamcity[testStarted name='Basic use of the Contains range matcher']
|
||||
##teamcity[testFinished name='Basic use of the Contains range matcher' duration="{duration}"]
|
||||
##teamcity[testStarted name='Basic use of the Empty range matcher']
|
||||
##teamcity[testFinished name='Basic use of the Empty range matcher' duration="{duration}"]
|
||||
##teamcity[testStarted name='CAPTURE can deal with complex expressions']
|
||||
##teamcity[testFinished name='CAPTURE can deal with complex expressions' duration="{duration}"]
|
||||
##teamcity[testStarted name='CAPTURE can deal with complex expressions involving commas']
|
||||
@ -537,6 +541,8 @@ Exception.tests.cpp:<line number>|nunexpected exception with message:|n "For so
|
||||
##teamcity[testStarted name='Unexpected exceptions can be translated']
|
||||
Exception.tests.cpp:<line number>|nunexpected exception with message:|n "3.14"']
|
||||
##teamcity[testFinished name='Unexpected exceptions can be translated' duration="{duration}"]
|
||||
##teamcity[testStarted name='Usage of the SizeIs range matcher']
|
||||
##teamcity[testFinished name='Usage of the SizeIs range matcher' duration="{duration}"]
|
||||
##teamcity[testStarted name='Use a custom approx']
|
||||
##teamcity[testFinished name='Use a custom approx' duration="{duration}"]
|
||||
##teamcity[testStarted name='Variadic macros']
|
||||
|
@ -2178,6 +2178,199 @@ Nor would this
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Basic use of the Contains range matcher" tags="[contains][matchers][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Section name="Different argument ranges, same element type, default comparison" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
a, Contains(1)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1, 2, 3 } contains element 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
b, Contains(1)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 0, 1, 2 } contains element 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
c, !Contains(1)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 4, 5, 6 } not contains element 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="3" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Different argument ranges, same element type, custom comparison" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
a, Contains(0, close_enough)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1, 2, 3 } contains element 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
b, Contains(0, close_enough)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 0, 1, 2 } contains element 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
c, !Contains(0, close_enough)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 4, 5, 6 } not contains element 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="3" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Different element type, custom comparisons" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
a, Contains(4, [](auto&& lhs, size_t sz) { return lhs.size() == sz; })
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ "abc", "abcd", "abcde" } contains element 4
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Can handle type that requires ADL-found free function begin and end" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
in, Contains(1)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1, 2, 3, 4, 5 } contains element 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
in, !Contains(8)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1, 2, 3, 4, 5 } not contains element 8
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="2" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Initialization with move only types" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
in, Contains(MoveOnlyTestElement{ 2 })
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1, 2, 3 } contains element 2
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
in, !Contains(MoveOnlyTestElement{ 9 })
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1, 2, 3 } not contains element 9
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="2" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Matching using matcher" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5))
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Basic use of the Empty range matcher" tags="[empty][matchers][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Section name="Simple, std-provided containers" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
empty_array, IsEmpty()
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ } is empty
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
non_empty_array, !IsEmpty()
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 0.0 } not is empty
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
empty_vec, IsEmpty()
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ } is empty
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
non_empty_vec, !IsEmpty()
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 'a', 'b', 'c' } not is empty
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
inner_lists_are_empty, !IsEmpty()
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ { } } not is empty
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
inner_lists_are_empty.front(), IsEmpty()
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ } is empty
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="6" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Type with empty" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
has_empty{}, !IsEmpty()
|
||||
</Original>
|
||||
<Expanded>
|
||||
{?} not is empty
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Type requires ADL found empty free function" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
unrelated::ADL_empty{}, IsEmpty()
|
||||
</Original>
|
||||
<Expanded>
|
||||
{?} is empty
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="CAPTURE can deal with complex expressions" tags="[capture][messages]" filename="tests/<exe-name>/UsageTests/Message.tests.cpp" >
|
||||
<Info>
|
||||
a := 1
|
||||
@ -13632,6 +13825,90 @@ There is no extra whitespace here
|
||||
</Exception>
|
||||
<OverallResult success="false"/>
|
||||
</TestCase>
|
||||
<TestCase name="Usage of the SizeIs range matcher" tags="[matchers][size][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Section name="Some with stdlib containers" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
empty_vec, SizeIs(0)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ } has size == 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
empty_vec, !SizeIs(2)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ } not has size == 2
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
empty_vec, SizeIs(Lt(2))
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ } size matches is less than 2
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
arr, SizeIs(2)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 0, 0 } has size == 2
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
arr, SizeIs( Lt(3))
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 0, 0 } size matches is less than 3
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
arr, !SizeIs(!Lt(3))
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 0, 0 } not size matches not is less than 3
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
map, SizeIs(3)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ {?}, {?}, {?} } has size == 3
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="7" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Type requires ADL found size free function" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
unrelated::ADL_size{}, SizeIs(12)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{?} has size == 12
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="Type has size member" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
|
||||
<Original>
|
||||
has_size{}, SizeIs(13)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{?} has size == 13
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Use a custom approx" tags="[Approx][custom]" filename="tests/<exe-name>/UsageTests/Approx.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Approx.tests.cpp" >
|
||||
<Original>
|
||||
@ -17264,7 +17541,7 @@ loose text artifact
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<OverallResults successes="1687" failures="149" expectedFailures="21"/>
|
||||
<OverallResults successes="1716" failures="149" expectedFailures="21"/>
|
||||
</Group>
|
||||
<OverallResults successes="1687" failures="148" expectedFailures="21"/>
|
||||
<OverallResults successes="1716" failures="148" expectedFailures="21"/>
|
||||
</Catch>
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <catch2/catch_approx.h>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/catch_test_spec_parser.h>
|
||||
#include <catch2/catch_test_case_info.h>
|
||||
#include <catch2/catch_config.hpp>
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.h>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/catch_string_manip.h>
|
||||
|
||||
static const char * const no_whitespace = "There is no extra whitespace here";
|
||||
|
@ -3,8 +3,8 @@
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
#include <catch2/matchers/catch_matchers_vector.h>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/catch_tag_alias_registry.h>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_test_case_info.h>
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <catch2/catch_enum_values_registry.h>
|
||||
#include <catch2/matchers/catch_matchers_vector.h>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
enum class EnumClass3 { Value1, Value2, Value3, Value4 };
|
||||
|
@ -29,7 +29,7 @@ std::ostream& operator<<(std::ostream& out, foo::helper_1403 const&) {
|
||||
///////////////////////////////
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
@ -5,11 +5,11 @@
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_exception.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating.h>
|
||||
#include <catch2/matchers/catch_matchers_generic.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.h>
|
||||
#include <catch2/matchers/catch_matchers_vector.h>
|
||||
#include <catch2/matchers/catch_matchers_templates.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/matchers/catch_matchers_templated.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
219
tests/SelfTest/UsageTests/MatchersRanges.tests.cpp
Normal file
219
tests/SelfTest/UsageTests/MatchersRanges.tests.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_container_properties.hpp>
|
||||
#include <catch2/matchers/catch_matchers_contains.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
namespace unrelated {
|
||||
class needs_ADL_begin {
|
||||
std::array<int, 5> elements{ {1, 2, 3, 4, 5} };
|
||||
public:
|
||||
using iterator = std::array<int, 5>::iterator;
|
||||
using const_iterator = std::array<int, 5>::const_iterator;
|
||||
|
||||
const_iterator Begin() const { return elements.begin(); }
|
||||
const_iterator End() const { return elements.end(); }
|
||||
|
||||
friend const_iterator begin(needs_ADL_begin const& lhs) {
|
||||
return lhs.Begin();
|
||||
}
|
||||
friend const_iterator end(needs_ADL_begin const& rhs) {
|
||||
return rhs.End();
|
||||
}
|
||||
};
|
||||
} // end unrelated namespace
|
||||
} // end anon namespace
|
||||
|
||||
struct MoveOnlyTestElement {
|
||||
int num = 0;
|
||||
MoveOnlyTestElement(int n) :num(n) {}
|
||||
|
||||
MoveOnlyTestElement(MoveOnlyTestElement&& rhs) = default;
|
||||
MoveOnlyTestElement& operator=(MoveOnlyTestElement&& rhs) = default;
|
||||
|
||||
friend bool operator==(MoveOnlyTestElement const& lhs, MoveOnlyTestElement const& rhs) {
|
||||
return lhs.num == rhs.num;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, MoveOnlyTestElement const& elem) {
|
||||
out << elem.num;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Basic use of the Contains range matcher", "[matchers][templated][contains]") {
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
SECTION("Different argument ranges, same element type, default comparison") {
|
||||
std::array<int, 3> a{ { 1,2,3 } };
|
||||
std::vector<int> b{ 0,1,2 };
|
||||
std::list<int> c{ 4,5,6 };
|
||||
|
||||
// A contains 1
|
||||
REQUIRE_THAT(a, Contains(1));
|
||||
// B contains 1
|
||||
REQUIRE_THAT(b, Contains(1));
|
||||
// C does not contain 1
|
||||
REQUIRE_THAT(c, !Contains(1));
|
||||
}
|
||||
|
||||
SECTION("Different argument ranges, same element type, custom comparison") {
|
||||
std::array<int, 3> a{ { 1,2,3 } };
|
||||
std::vector<int> b{ 0,1,2 };
|
||||
std::list<int> c{ 4,5,6 };
|
||||
|
||||
auto close_enough = [](int lhs, int rhs) { return std::abs(lhs - rhs) <= 1; };
|
||||
|
||||
// A contains 1, which is "close enough" to 0
|
||||
REQUIRE_THAT(a, Contains(0, close_enough));
|
||||
// B contains 0 directly
|
||||
REQUIRE_THAT(b, Contains(0, close_enough));
|
||||
// C does not contain anything "close enough" to 0
|
||||
REQUIRE_THAT(c, !Contains(0, close_enough));
|
||||
}
|
||||
|
||||
SECTION("Different element type, custom comparisons") {
|
||||
std::array<std::string, 3> a{ { "abc", "abcd" , "abcde" } };
|
||||
|
||||
REQUIRE_THAT(a, Contains(4, [](auto&& lhs, size_t sz) {
|
||||
return lhs.size() == sz;
|
||||
}));
|
||||
}
|
||||
|
||||
SECTION("Can handle type that requires ADL-found free function begin and end") {
|
||||
unrelated::needs_ADL_begin in;
|
||||
|
||||
REQUIRE_THAT(in, Contains(1));
|
||||
REQUIRE_THAT(in, !Contains(8));
|
||||
}
|
||||
|
||||
SECTION("Initialization with move only types") {
|
||||
std::array<MoveOnlyTestElement, 3> in{ { MoveOnlyTestElement{ 1 }, MoveOnlyTestElement{ 2 }, MoveOnlyTestElement{ 3 } } };
|
||||
|
||||
REQUIRE_THAT(in, Contains(MoveOnlyTestElement{ 2 }));
|
||||
REQUIRE_THAT(in, !Contains(MoveOnlyTestElement{ 9 }));
|
||||
}
|
||||
|
||||
SECTION("Matching using matcher") {
|
||||
std::array<double, 4> in{ {1, 2, 3} };
|
||||
|
||||
REQUIRE_THAT(in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)));
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct has_empty {
|
||||
bool empty() const { return false; }
|
||||
};
|
||||
|
||||
namespace unrelated {
|
||||
struct ADL_empty {
|
||||
bool Empty() const { return true; }
|
||||
|
||||
friend bool empty(ADL_empty e) {
|
||||
return e.Empty();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace unrelated
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("Basic use of the Empty range matcher", "[matchers][templated][empty]") {
|
||||
using Catch::Matchers::IsEmpty;
|
||||
SECTION("Simple, std-provided containers") {
|
||||
std::array<int, 0> empty_array{};
|
||||
std::array<double, 1> non_empty_array{};
|
||||
REQUIRE_THAT(empty_array, IsEmpty());
|
||||
REQUIRE_THAT(non_empty_array, !IsEmpty());
|
||||
|
||||
std::vector<std::string> empty_vec;
|
||||
std::vector<char> non_empty_vec{ 'a', 'b', 'c' };
|
||||
REQUIRE_THAT(empty_vec, IsEmpty());
|
||||
REQUIRE_THAT(non_empty_vec, !IsEmpty());
|
||||
|
||||
std::list<std::list<std::list<int>>> inner_lists_are_empty;
|
||||
inner_lists_are_empty.push_back({});
|
||||
REQUIRE_THAT(inner_lists_are_empty, !IsEmpty());
|
||||
REQUIRE_THAT(inner_lists_are_empty.front(), IsEmpty());
|
||||
}
|
||||
SECTION("Type with empty") {
|
||||
REQUIRE_THAT(has_empty{}, !IsEmpty());
|
||||
}
|
||||
SECTION("Type requires ADL found empty free function") {
|
||||
REQUIRE_THAT(unrelated::ADL_empty{}, IsEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class LessThanMatcher final : public Catch::Matchers::MatcherBase<size_t> {
|
||||
size_t m_target;
|
||||
public:
|
||||
explicit LessThanMatcher(size_t target):
|
||||
m_target(target)
|
||||
{}
|
||||
|
||||
bool match(size_t const& size) const override {
|
||||
return size < m_target;
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "is less than " + std::to_string(m_target);
|
||||
}
|
||||
};
|
||||
|
||||
LessThanMatcher Lt(size_t sz) {
|
||||
return LessThanMatcher{ sz };
|
||||
}
|
||||
|
||||
namespace unrelated {
|
||||
struct ADL_size {
|
||||
size_t sz() const {
|
||||
return 12;
|
||||
}
|
||||
friend size_t size(ADL_size s) {
|
||||
return s.sz();
|
||||
}
|
||||
};
|
||||
} // end namespace unrelated
|
||||
|
||||
struct has_size {
|
||||
size_t size() const {
|
||||
return 13;
|
||||
}
|
||||
};
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("Usage of the SizeIs range matcher", "[matchers][templated][size]") {
|
||||
using Catch::Matchers::SizeIs;
|
||||
SECTION("Some with stdlib containers") {
|
||||
std::vector<int> empty_vec;
|
||||
REQUIRE_THAT(empty_vec, SizeIs(0));
|
||||
REQUIRE_THAT(empty_vec, !SizeIs(2));
|
||||
REQUIRE_THAT(empty_vec, SizeIs(Lt(2)));
|
||||
|
||||
std::array<int, 2> arr{};
|
||||
REQUIRE_THAT(arr, SizeIs(2));
|
||||
REQUIRE_THAT(arr, SizeIs( Lt(3)));
|
||||
REQUIRE_THAT(arr, !SizeIs(!Lt(3)));
|
||||
|
||||
std::map<int, int> map{ {1, 1}, {2, 2}, {3, 3} };
|
||||
REQUIRE_THAT(map, SizeIs(3));
|
||||
}
|
||||
SECTION("Type requires ADL found size free function") {
|
||||
REQUIRE_THAT(unrelated::ADL_size{}, SizeIs(12));
|
||||
}
|
||||
SECTION("Type has size member") {
|
||||
REQUIRE_THAT(has_size{}, SizeIs(13));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user