1
0
mirror of https://github.com/catchorg/Catch2.git synced 2025-01-15 22:58:02 +00:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Martin Hořeňovský
ab0ca2f566
Rename some matcher-related files
The two changes are
`catch_matchers_templates` -> `catch_matchers_templated` and
`catch_matchers_generic` -> `catch_matchers_predicate`. The former
is mostly cosmetic, but the second was previously significantly
misleading, and as the library is now to be consumed by including
specific headers, this needed to be fixed.
2020-03-27 10:24:08 +01:00
Martin Hořeňovský
3a3efebd16
Add IsEmpty and SizeIs matchers for ranges/containers
`SizeIs` can accept both `size_t` and a matcher. In the first case,
it checks whether the size of the range is equal to specified size.
In the second case, it checks whether the provided matcher accepts
the size of the range.
2020-03-27 10:24:08 +01:00
Martin Hořeňovský
f52a58e857
Make concrete matchers final
Outside of `MatcherBase` and `GenericMatcherBase`, matchers are not
designed to be overriden. This means that doing so can easily lead
to errors, and matchers are generally fairly simple functionality-wise.
so there is not much code reuse to be gained anyway.

Thus, Catch2-provided concrete matchers are now final.
2020-03-27 10:22:25 +01:00
Martin Hořeňovský
007efc173a
Add generic Contains matcher
It matches a range iff the range contains a specific element,
or an element in the range matches the provided matcher.
2020-03-27 10:22:25 +01:00
Martin Hořeňovský
89e857349b
Use _t form of traits 2020-03-27 10:22:25 +01:00
Martin Hořeňovský
c2daf468bb
Standardize matcher headers to use .hpp suffix 2020-03-27 10:22:25 +01:00
Martin Hořeňovský
64d7f9b98a
New and hopefully improved documentation for matchers 2020-03-27 10:22:25 +01:00
40 changed files with 1512 additions and 184 deletions

View File

@ -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`
---

View File

@ -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)

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View 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

View File

@ -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 {

View 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

View 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

View 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

View File

@ -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:

View File

@ -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>

View File

@ -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;

View File

@ -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()) {

View File

@ -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:

View File

@ -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>

View File

@ -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;

View File

@ -1,4 +1,4 @@
#include <catch2/matchers/catch_matchers_templates.hpp>
#include <catch2/matchers/catch_matchers_templated.hpp>
namespace Catch {
namespace Matchers {

View File

@ -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>>
>;

View File

@ -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,

View File

@ -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})

View File

@ -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>

View File

@ -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

View File

@ -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 )

View File

@ -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

View File

@ -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

View File

@ -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}"/>

View File

@ -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}"/>

View File

@ -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

View File

@ -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']

View File

@ -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&amp;&amp; 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>

View File

@ -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>

View File

@ -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";

View File

@ -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>

View File

@ -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 };

View File

@ -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>

View File

@ -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>

View File

@ -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>

View 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));
}
}