diff --git a/include/catch.hpp b/include/catch.hpp index 505fa19b..9d81143e 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -72,7 +72,7 @@ #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) -#define CATCH_REQUIRE_THROWS_WITH( expr, expectedMessage ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, expectedMessage, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) @@ -83,7 +83,7 @@ #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) -#define CATCH_CHECK_THROWS_WITH( expr, expectedMessage ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, expectedMessage, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) @@ -139,7 +139,7 @@ #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) -#define REQUIRE_THROWS_WITH( expr, expectedMessage ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, expectedMessage, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) @@ -150,7 +150,7 @@ #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) -#define CHECK_THROWS_WITH( expr, expectedMessage ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, expectedMessage, "CHECK_THROWS_WITH" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 3858261a..544fc120 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -66,16 +66,16 @@ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, expectedMessage, macroName ) \ +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, expectedMessage ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureExpectedException( expectedMessage ); \ + __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h index cec7eba5..2ae79b18 100644 --- a/include/internal/catch_common.h +++ b/include/internal/catch_common.h @@ -25,6 +25,11 @@ namespace Catch { struct IConfig; + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + class NonCopyable { #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; diff --git a/include/internal/catch_matchers.hpp b/include/internal/catch_matchers.hpp index 028ff678..a959095e 100644 --- a/include/internal/catch_matchers.hpp +++ b/include/internal/catch_matchers.hpp @@ -108,68 +108,96 @@ namespace Matchers { inline std::string makeString( std::string const& str ) { return str; } inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + struct Equals : MatcherImpl { - Equals( std::string const& str ) : m_str( str ){} - Equals( Equals const& other ) : m_str( other.m_str ){} + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} virtual ~Equals(); virtual bool match( std::string const& expr ) const { - return m_str == expr; + return m_data.m_str == m_data.adjustString( expr );; } virtual std::string toString() const { - return "equals: \"" + m_str + "\""; + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } - std::string m_str; + CasedString m_data; }; struct Contains : MatcherImpl { - Contains( std::string const& substr ) : m_substr( substr ){} - Contains( Contains const& other ) : m_substr( other.m_substr ){} + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} virtual ~Contains(); virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) != std::string::npos; + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; } virtual std::string toString() const { - return "contains: \"" + m_substr + "\""; + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } - std::string m_substr; + CasedString m_data; }; struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr ) : m_substr( substr ){} - StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} virtual ~StartsWith(); virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == 0; + return m_data.adjustString( expr ).find( m_data.m_str ) == 0; } virtual std::string toString() const { - return "starts with: \"" + m_substr + "\""; + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } - std::string m_substr; + CasedString m_data; }; struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr ) : m_substr( substr ){} - EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} virtual ~EndsWith(); virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == expr.size() - m_substr.size(); + return m_data.adjustString( expr ).find( m_data.m_str ) == expr.size() - m_data.m_str.size(); } virtual std::string toString() const { - return "ends with: \"" + m_substr + "\""; + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } - std::string m_substr; + CasedString m_data; }; } // namespace StdString } // namespace Impl @@ -199,17 +227,17 @@ namespace Matchers { return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); } - inline Impl::StdString::Equals Equals( std::string const& str ) { - return Impl::StdString::Equals( str ); + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); } - inline Impl::StdString::Equals Equals( const char* str ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); } - inline Impl::StdString::Contains Contains( std::string const& substr ) { - return Impl::StdString::Contains( substr ); + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); } - inline Impl::StdString::Contains Contains( const char* substr ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); } inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { return Impl::StdString::StartsWith( substr ); diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h index c8cd92eb..c27fe5c2 100644 --- a/include/internal/catch_result_builder.h +++ b/include/internal/catch_result_builder.h @@ -11,6 +11,7 @@ #include "catch_result_type.h" #include "catch_assertionresult.h" #include "catch_common.h" +#include "catch_matchers.hpp" namespace Catch { @@ -69,6 +70,7 @@ namespace Catch { void captureResult( ResultWas::OfType resultType ); void captureExpression(); void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; diff --git a/include/internal/catch_result_builder.hpp b/include/internal/catch_result_builder.hpp index ae86d768..5e2ba32b 100644 --- a/include/internal/catch_result_builder.hpp +++ b/include/internal/catch_result_builder.hpp @@ -19,9 +19,9 @@ namespace Catch { std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { - return secondArg.empty() + return secondArg.empty() || secondArg == "\"\"" ? capturedExpression - : capturedExpression + ", \"" + secondArg + "\""; + : capturedExpression + ", " + secondArg; } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, @@ -69,20 +69,24 @@ namespace Catch { setResultType( resultType ); captureExpression(); } - void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + assert( m_exprComponents.testFalse == false ); AssertionResultData data = m_data; data.resultType = ResultWas::Ok; data.reconstructedExpression = m_assertionInfo.capturedExpression; - if( expectedMessage != "" ) { - - std::string actualMessage = Catch::translateActiveException(); - WildcardPattern pattern( expectedMessage, WildcardPattern::CaseInsensitive ); - if( !pattern.matches( actualMessage ) ) { - data.resultType = ResultWas::ExpressionFailed; - data.reconstructedExpression = actualMessage; - } + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; } AssertionResult result( m_assertionInfo, data ); handleResult( result ); diff --git a/include/internal/catch_test_spec.hpp b/include/internal/catch_test_spec.hpp index 292ffce4..8428b09d 100644 --- a/include/internal/catch_test_spec.hpp +++ b/include/internal/catch_test_spec.hpp @@ -29,7 +29,7 @@ namespace Catch { class NamePattern : public Pattern { public: NamePattern( std::string const& name ) - : m_wildcardPattern( toLower( name ), WildcardPattern::CaseInsensitive ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { diff --git a/include/internal/catch_wildcard_pattern.hpp b/include/internal/catch_wildcard_pattern.hpp index f42dc5d0..a5e89b6e 100644 --- a/include/internal/catch_wildcard_pattern.hpp +++ b/include/internal/catch_wildcard_pattern.hpp @@ -22,11 +22,7 @@ namespace Catch public: - enum CaseSensitivity { - CaseSensitive, - CaseInsensitive - }; - WildcardPattern( std::string const& pattern, CaseSensitivity caseSensitivity ) + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_wildcard( NoWildcard ), m_pattern( adjustCase( pattern ) ) @@ -64,9 +60,9 @@ namespace Catch } private: std::string adjustCase( std::string const& str ) const { - return m_caseSensitivity == CaseInsensitive ? toLower( str ) : str; + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } - CaseSensitivity m_caseSensitivity; + CaseSensitive::Choice m_caseSensitivity; WildcardPosition m_wildcard; std::string m_pattern; }; diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 63530052..67fb8437 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -798,5 +798,5 @@ with expansion: =============================================================================== test cases: 157 | 117 passed | 39 failed | 1 failed as expected -assertions: 774 | 681 passed | 80 failed | 13 failed as expected +assertions: 773 | 680 passed | 80 failed | 13 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 1919c1c2..7d41c5a7 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -1297,7 +1297,7 @@ ExceptionTests.cpp: ExceptionTests.cpp:: PASSED: - REQUIRE_THROWS_WITH( thisThrows(), "expecteD Exception" ) + REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) ) ------------------------------------------------------------------------------- Exception messages can be tested for @@ -1308,19 +1308,19 @@ ExceptionTests.cpp: ExceptionTests.cpp:: PASSED: - REQUIRE_THROWS_WITH( thisThrows(), "expected*" ) + REQUIRE_THROWS_WITH( thisThrows(), StartsWith( "expected" ) ) ExceptionTests.cpp:: PASSED: - REQUIRE_THROWS_WITH( thisThrows(), "*exception" ) + REQUIRE_THROWS_WITH( thisThrows(), EndsWith( "exception" ) ) ExceptionTests.cpp:: PASSED: - REQUIRE_THROWS_WITH( thisThrows(), "*except*" ) + REQUIRE_THROWS_WITH( thisThrows(), Contains( "except" ) ) ExceptionTests.cpp:: PASSED: - REQUIRE_THROWS_WITH( thisThrows(), "*exCept*" ) + REQUIRE_THROWS_WITH( thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) ) ------------------------------------------------------------------------------- Mismatching exception messages failing the test @@ -1328,10 +1328,6 @@ Mismatching exception messages failing the test ExceptionTests.cpp: ............................................................................... -ExceptionTests.cpp:: -PASSED: - REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ) - ExceptionTests.cpp:: PASSED: REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ) @@ -8009,5 +8005,5 @@ with expansion: =============================================================================== test cases: 157 | 101 passed | 55 failed | 1 failed as expected -assertions: 794 | 681 passed | 100 failed | 13 failed as expected +assertions: 793 | 680 passed | 100 failed | 13 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 95d4f9a2..cd978bfb 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,5 +1,5 @@ - + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index 0d06a704..654061f2 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -1611,10 +1611,10 @@
- thisThrows(), "expecteD Exception" + thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) - thisThrows(), "expecteD Exception" + thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) @@ -1622,34 +1622,34 @@
- thisThrows(), "expected*" + thisThrows(), StartsWith( "expected" ) - thisThrows(), "expected*" + thisThrows(), StartsWith( "expected" ) - thisThrows(), "*exception" + thisThrows(), EndsWith( "exception" ) - thisThrows(), "*exception" + thisThrows(), EndsWith( "exception" ) - thisThrows(), "*except*" + thisThrows(), Contains( "except" ) - thisThrows(), "*except*" + thisThrows(), Contains( "except" ) - thisThrows(), "*exCept*" + thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) - thisThrows(), "*exCept*" + thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) @@ -1657,14 +1657,6 @@ - - - thisThrows(), "expected exception" - - - thisThrows(), "expected exception" - - thisThrows(), "expected exception" @@ -8307,7 +8299,7 @@ there"
- + - + diff --git a/projects/SelfTest/ExceptionTests.cpp b/projects/SelfTest/ExceptionTests.cpp index f3b7f41d..3826c58b 100644 --- a/projects/SelfTest/ExceptionTests.cpp +++ b/projects/SelfTest/ExceptionTests.cpp @@ -154,20 +154,21 @@ TEST_CASE( "NotImplemented exception", "" ) } TEST_CASE( "Exception messages can be tested for", "" ) { + using namespace Catch::Matchers; SECTION( "exact match" ) REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ); SECTION( "different case" ) - REQUIRE_THROWS_WITH( thisThrows(), "expecteD Exception" ); + REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) ); SECTION( "wildcarded" ) { - REQUIRE_THROWS_WITH( thisThrows(), "expected*" ); - REQUIRE_THROWS_WITH( thisThrows(), "*exception" ); - REQUIRE_THROWS_WITH( thisThrows(), "*except*" ); - REQUIRE_THROWS_WITH( thisThrows(), "*exCept*" ); + REQUIRE_THROWS_WITH( thisThrows(), StartsWith( "expected" ) ); + REQUIRE_THROWS_WITH( thisThrows(), EndsWith( "exception" ) ); + REQUIRE_THROWS_WITH( thisThrows(), Contains( "except" ) ); + REQUIRE_THROWS_WITH( thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) ); } } TEST_CASE( "Mismatching exception messages failing the test", "[.][failing]" ) { - REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ); REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ); REQUIRE_THROWS_WITH( thisThrows(), "should fail" ); + REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ); }