Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRTP matchers #1554

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ Build
cmake-build-*
benchmark-dir
.conan/test_package/build
_*/
.vscode/
.history/
10 changes: 5 additions & 5 deletions docs/matchers.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,31 +147,31 @@ REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("De
It's easy to provide your own matchers to extend Catch or just to work with your own types.

You need to provide two things:
1. A matcher class, derived from `Catch::MatcherBase<T>` - where `T` is the type being tested.
1. A matcher class, derived from `Catch::MatcherBaseGeneric<T>` - where `T` is the matcher class.
The constructor takes and stores any arguments needed (e.g. something to compare against) and you must
override two methods: `match()` and `describe()`.
provide two methods: `match()` and `describe()`.
2. A simple builder function. This is what is actually called from the test code and allows overloading.

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

```c++
// The matcher class
class IntRange : public Catch::MatcherBase<int> {
class IntRange : public Catch::MatcherBaseGeneric<IntRange> {
int m_begin, m_end;
public:
IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {}

// Performs the test for this matcher
bool match( int const& i ) const override {
bool match( int const& i ) const {
return i >= m_begin && i <= 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 {
std::ostringstream ss;
ss << "is between " << m_begin << " and " << m_end;
return ss.str();
Expand Down
2 changes: 0 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ set(IMPL_SOURCES
${SOURCES_DIR}/catch_approx.cpp
${SOURCES_DIR}/catch_assertionhandler.cpp
${SOURCES_DIR}/catch_assertionresult.cpp
${SOURCES_DIR}/catch_capture_matchers.cpp
${SOURCES_DIR}/catch_commandline.cpp
${SOURCES_DIR}/catch_common.cpp
${SOURCES_DIR}/catch_config.cpp
Expand All @@ -153,7 +152,6 @@ set(IMPL_SOURCES
${SOURCES_DIR}/catch_interfaces_testcase.cpp
${SOURCES_DIR}/catch_list.cpp
${SOURCES_DIR}/catch_leak_detector.cpp
${SOURCES_DIR}/catch_matchers.cpp
${SOURCES_DIR}/catch_matchers_exception.cpp
${SOURCES_DIR}/catch_matchers_floating.cpp
${SOURCES_DIR}/catch_matchers_generic.cpp
Expand Down
24 changes: 0 additions & 24 deletions src/catch2/catch_capture_matchers.cpp

This file was deleted.

24 changes: 16 additions & 8 deletions src/catch2/catch_capture_matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@
#include <catch2/catch_capture.hpp>
#include <catch2/catch_matchers.h>
#include <catch2/catch_stringref.h>
#include <catch2/catch_interfaces_registry_hub.h>

namespace Catch {

template<typename ArgT, typename MatcherT>
class MatchExpr : public ITransientExpression {
ArgT const& m_arg;
ArgT m_arg;
MatcherT m_matcher;
StringRef m_matcherString;
public:
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
MatchExpr( ArgT arg, MatcherT const& matcher, StringRef const& matcherString )
: ITransientExpression{ true, matcher.match( arg ) },
m_arg( arg ),
m_arg( std::forward<ArgT>(arg) ),
m_matcher( matcher ),
m_matcherString( matcherString )
{}
Expand All @@ -37,13 +38,20 @@ namespace Catch {
}
};

using StringMatcher = Matchers::Impl::MatcherBase<std::string>;

void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );
// This is the general overload that takes a any string matcher
// There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
// the Equals matcher (so the header does not mention matchers)
template<typename StringMatcher,
typename = typename std::enable_if<std::is_base_of<MatcherBaseGeneric<StringMatcher>, StringMatcher>::value>::type>
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {
std::string exceptionMessage = Catch::translateActiveException();
MatchExpr<std::string const&, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
handler.handleExpr( expr );
}

template<typename ArgT, typename MatcherT>
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
auto makeMatchExpr( ArgT && arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT&&, MatcherT> {
return MatchExpr<ArgT&&, MatcherT>( std::forward<ArgT>(arg), matcher, matcherString );
}

} // namespace Catch
Expand Down
17 changes: 17 additions & 0 deletions src/catch2/catch_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,23 @@ namespace Catch {
T const& operator + ( T const& value, StreamEndStop ) {
return value;
}

// backported index_sequnce
template <std::size_t ...>
struct indexSequence
{ };

template <std::size_t N, std::size_t ... Next>
struct indexSequenceHelper : public indexSequenceHelper<N-1U, N-1U, Next...>
{ };

template <std::size_t ... Next>
struct indexSequenceHelper<0U, Next ... >
{ using type = indexSequence<Next ... >; };

template <std::size_t N>
using makeIndexSequence = typename indexSequenceHelper<N>::type;

}

#define CATCH_INTERNAL_LINEINFO \
Expand Down
28 changes: 0 additions & 28 deletions src/catch2/catch_matchers.cpp

This file was deleted.

Loading