From 054e3c5b4319ee21b7160736d0bdde2df438ad5f Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Thu, 5 Nov 2015 18:46:00 +0000 Subject: [PATCH] Added &&, || and ! operator overloads for matchers (syntactic sugar for AllOf, AnyOf and Not compositional matchers, respectively) --- include/internal/catch_matchers.hpp | 47 +++++++++- .../Baselines/console.std.approved.txt | 27 +++++- .../Baselines/console.sw.approved.txt | 85 ++++++++++++++++++- .../SelfTest/Baselines/junit.sw.approved.txt | 16 +++- .../SelfTest/Baselines/xml.sw.approved.txt | 78 ++++++++++++++++- projects/SelfTest/MiscTests.cpp | 41 +++++++++ 6 files changed, 286 insertions(+), 8 deletions(-) diff --git a/include/internal/catch_matchers.hpp b/include/internal/catch_matchers.hpp index fd9dfd2b..14249ebf 100644 --- a/include/internal/catch_matchers.hpp +++ b/include/internal/catch_matchers.hpp @@ -12,6 +12,12 @@ namespace Catch { namespace Matchers { namespace Impl { + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + template struct Matcher : SharedImpl { @@ -21,6 +27,10 @@ namespace Matchers { virtual Ptr clone() const = 0; virtual bool match( ExpressionT const& expr ) const = 0; virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; }; template @@ -34,7 +44,7 @@ namespace Matchers { namespace Generic { template struct Not : public MatcherImpl, ExpressionT> { - Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} Not( Not const& other ) : m_matcher( other.m_matcher ) {} virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { @@ -78,6 +88,12 @@ namespace Matchers { return oss.str(); } + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + private: std::vector > > m_matchers; }; @@ -112,11 +128,40 @@ namespace Matchers { return oss.str(); } + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + private: std::vector > > m_matchers; }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; } + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { inline std::string makeString( std::string const& str ) { return str; } diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index c222e306..73cef33c 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -707,6 +707,29 @@ MiscTests.cpp:: FAILED: with expansion: "this string contains 'abc' as a substring" equals: "something else" +------------------------------------------------------------------------------- +Matchers can be composed with both + and | - failing +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: FAILED: + CHECK_THAT( testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "random" ) ) +with expansion: + "this string contains 'abc' as a substring" ( ( contains: "string" or + contains: "different" ) and contains: "random" ) + +------------------------------------------------------------------------------- +Matchers can be negated (Not) with the ! operator - failing +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: FAILED: + CHECK_THAT( testStringForMatching() !Contains( "substring" ) ) +with expansion: + "this string contains 'abc' as a substring" not contains: "substring" + ------------------------------------------------------------------------------- Nice descriptive name ------------------------------------------------------------------------------- @@ -797,6 +820,6 @@ with expansion: "first" == "second" =============================================================================== -test cases: 159 | 119 passed | 39 failed | 1 failed as expected -assertions: 905 | 812 passed | 80 failed | 13 failed as expected +test cases: 165 | 123 passed | 41 failed | 1 failed as expected +assertions: 912 | 817 passed | 82 failed | 13 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 981fce15..082fa32d 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -3418,6 +3418,87 @@ with expansion: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" +------------------------------------------------------------------------------- +Matchers can be (AllOf) composed with the + operator +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching() Contains( "string" ) && Contains( "abc" ) && Contains( "substring" ) && Contains( "contains" ) ) +with expansion: + "this string contains 'abc' as a substring" ( contains: "string" and + contains: "abc" and contains: "substring" and contains: "contains" ) + +------------------------------------------------------------------------------- +Matchers can be (AnyOf) composed with the | operator +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching() Contains( "string" ) || Contains( "different" ) || Contains( "random" ) ) +with expansion: + "this string contains 'abc' as a substring" ( contains: "string" or contains: + "different" or contains: "random" ) + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching2() Contains( "string" ) || Contains( "different" ) || Contains( "random" ) ) +with expansion: + "some completely different text that contains one common word" ( contains: + "string" or contains: "different" or contains: "random" ) + +------------------------------------------------------------------------------- +Matchers can be composed with both + and | +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "substring" ) ) +with expansion: + "this string contains 'abc' as a substring" ( ( contains: "string" or + contains: "different" ) and contains: "substring" ) + +------------------------------------------------------------------------------- +Matchers can be composed with both + and | - failing +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: FAILED: + CHECK_THAT( testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "random" ) ) +with expansion: + "this string contains 'abc' as a substring" ( ( contains: "string" or + contains: "different" ) and contains: "random" ) + +------------------------------------------------------------------------------- +Matchers can be negated (Not) with the ! operator +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching() !Contains( "different" ) ) +with expansion: + "this string contains 'abc' as a substring" not contains: "different" + +------------------------------------------------------------------------------- +Matchers can be negated (Not) with the ! operator - failing +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: FAILED: + CHECK_THAT( testStringForMatching() !Contains( "substring" ) ) +with expansion: + "this string contains 'abc' as a substring" not contains: "substring" + ------------------------------------------------------------------------------- Factorials are computed ------------------------------------------------------------------------------- @@ -8943,6 +9024,6 @@ with expansion: 1 > 0 =============================================================================== -test cases: 159 | 118 passed | 40 failed | 1 failed as expected -assertions: 907 | 812 passed | 82 failed | 13 failed as expected +test cases: 165 | 122 passed | 42 failed | 1 failed as expected +assertions: 914 | 817 passed | 84 failed | 13 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 0766b19e..039aeaae 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,5 +1,5 @@ - + @@ -438,6 +438,20 @@ MiscTests.cpp: + + + + + +MiscTests.cpp: + + + + + +MiscTests.cpp: + + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index 1bb662f2..ed4ce494 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -3590,6 +3590,80 @@ + + + + testStringForMatching() Contains( "string" ) && Contains( "abc" ) && Contains( "substring" ) && Contains( "contains" ) + + + "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" and contains: "substring" and contains: "contains" ) + + + + + + + + testStringForMatching() Contains( "string" ) || Contains( "different" ) || Contains( "random" ) + + + "this string contains 'abc' as a substring" ( contains: "string" or contains: "different" or contains: "random" ) + + + + + testStringForMatching2() Contains( "string" ) || Contains( "different" ) || Contains( "random" ) + + + "some completely different text that contains one common word" ( contains: "string" or contains: "different" or contains: "random" ) + + + + + + + + testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "substring" ) + + + "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "substring" ) + + + + + + + + testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "random" ) + + + "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) + + + + + + + + testStringForMatching() !Contains( "different" ) + + + "this string contains 'abc' as a substring" not contains: "different" + + + + + + + + testStringForMatching() !Contains( "substring" ) + + + "this string contains 'abc' as a substring" not contains: "substring" + + + + @@ -9422,7 +9496,7 @@ there" - + - + diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index 8bd271c4..c2a7784c 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -208,6 +208,11 @@ inline const char* testStringForMatching() { return "this string contains 'abc' as a substring"; } +inline const char* testStringForMatching2() +{ + return "some completely different text that contains one common word"; +} + using namespace Catch::Matchers; TEST_CASE("String matchers", "[matchers]" ) @@ -257,6 +262,42 @@ TEST_CASE("Equals", "[matchers]") CHECK_THAT( testStringForMatching(), Equals( "this string contains 'abc' as a substring" ) ); } +TEST_CASE("Matchers can be (AllOf) composed with the + operator", "[matchers][operators][operator+]") +{ + CHECK_THAT( testStringForMatching(), + Contains( "string" ) && + Contains( "abc" ) && + Contains( "substring" ) && + Contains( "contains" ) ); +} + +TEST_CASE("Matchers can be (AnyOf) composed with the | operator", "[matchers][operators][operator|]") +{ + CHECK_THAT( testStringForMatching(), Contains( "string" ) || Contains( "different" ) || Contains( "random" ) ); + CHECK_THAT( testStringForMatching2(), Contains( "string" ) || Contains( "different" ) || Contains( "random" ) ); +} + +TEST_CASE("Matchers can be composed with both + and |", "[matchers][operators][operator|][operator+]") +{ + CHECK_THAT( testStringForMatching(), ( Contains( "string" ) || Contains( "different" ) ) && Contains( "substring" ) ); +} + +TEST_CASE("Matchers can be composed with both + and | - failing", "[matchers][operators][operator|][operator+][.failing]") +{ + CHECK_THAT( testStringForMatching(), ( Contains( "string" ) || Contains( "different" ) ) && Contains( "random" ) ); +} + +TEST_CASE("Matchers can be negated (Not) with the ! operator", "[matchers][operators][not]") +{ + CHECK_THAT( testStringForMatching(), !Contains( "different" ) ); +} + +TEST_CASE("Matchers can be negated (Not) with the ! operator - failing", "[matchers][operators][not][.failing]") +{ + CHECK_THAT( testStringForMatching(), !Contains( "substring" ) ); +} + + inline unsigned int Factorial( unsigned int number ) { // return number <= 1 ? number : Factorial(number-1)*number;