mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Exception message assertions now work with matchers
This commit is contained in:
		| @@ -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" ) | ||||
|   | ||||
| @@ -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 ); \ | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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> { | ||||
|             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> { | ||||
|             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> { | ||||
|             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> { | ||||
|             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<ExpressionT>().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 ); | ||||
|   | ||||
| @@ -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<std::string> const& matcher ); | ||||
|         void handleResult( AssertionResult const& result ); | ||||
|         void react(); | ||||
|         bool shouldDebugBreak() const; | ||||
|   | ||||
| @@ -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<std::string>() ); | ||||
|         else | ||||
|             captureExpectedException( Matchers::Equals( expectedMessage ) ); | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> 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 ); | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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; | ||||
|     }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash