mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-01 12:55:40 +02: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