Lazily stringify expressions (closes #556)

This commit is contained in:
Ryan Gonzalez 2015-12-24 11:37:28 -06:00
parent 981347b6e4
commit ebf172be0b
4 changed files with 47 additions and 25 deletions

View File

@ -133,7 +133,7 @@
try { \ try { \
std::string matcherAsString = (matcher).toString(); \ std::string matcherAsString = (matcher).toString(); \
__catchResult \ __catchResult \
.setLhs( Catch::toString( arg ) ) \ .setLhs( arg ) \
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
.setOp( "matches" ) \ .setOp( "matches" ) \
.setResultType( (matcher).match( arg ) ); \ .setResultType( (matcher).match( arg ) ); \

View File

@ -71,7 +71,7 @@ public:
void endExpression() { void endExpression() {
bool value = m_lhs ? true : false; bool value = m_lhs ? true : false;
m_rb m_rb
.setLhs( Catch::toString( value ) ) .setLhs( value )
.setResultType( value ) .setResultType( value )
.endExpression(); .endExpression();
} }
@ -90,8 +90,8 @@ private:
ResultBuilder& captureExpression( RhsT const& rhs ) { ResultBuilder& captureExpression( RhsT const& rhs ) {
return m_rb return m_rb
.setResultType( Internal::compare<Op>( m_lhs, rhs ) ) .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
.setLhs( Catch::toString( m_lhs ) ) .setLhs( m_lhs )
.setRhs( Catch::toString( rhs ) ) .setRhs( rhs )
.setOp( Internal::OperatorTraits<Op>::getName() ); .setOp( Internal::OperatorTraits<Op>::getName() );
} }

View File

@ -12,6 +12,7 @@
#include "catch_assertionresult.h" #include "catch_assertionresult.h"
#include "catch_common.h" #include "catch_common.h"
#include "catch_matchers.hpp" #include "catch_matchers.hpp"
#include "catch_tostring.h"
namespace Catch { namespace Catch {
@ -34,6 +35,17 @@ namespace Catch {
std::ostringstream oss; std::ostringstream oss;
}; };
struct AnyTypeHolderBase {
virtual std::string toString() = 0;
};
template <typename T>
struct AnyTypeHolder : AnyTypeHolderBase {
AnyTypeHolder( const T& value ) : value ( value ) {}
std::string toString() { return Catch::toString( value ); }
T value;
};
class ResultBuilder { class ResultBuilder {
public: public:
ResultBuilder( char const* macroName, ResultBuilder( char const* macroName,
@ -57,8 +69,10 @@ namespace Catch {
ResultBuilder& setResultType( ResultWas::OfType result ); ResultBuilder& setResultType( ResultWas::OfType result );
ResultBuilder& setResultType( bool result ); ResultBuilder& setResultType( bool result );
ResultBuilder& setLhs( std::string const& lhs ); template <typename T>
ResultBuilder& setRhs( std::string const& rhs ); ResultBuilder& setLhs( T const& lhs );
template <typename T>
ResultBuilder& setRhs( T const& rhs );
ResultBuilder& setOp( std::string const& op ); ResultBuilder& setOp( std::string const& op );
void endExpression(); void endExpression();
@ -80,9 +94,11 @@ namespace Catch {
AssertionInfo m_assertionInfo; AssertionInfo m_assertionInfo;
AssertionResultData m_data; AssertionResultData m_data;
struct ExprComponents { struct ExprComponents {
ExprComponents() : testFalse( false ) {} ExprComponents() : testFalse( false ), lhs( NULL ), rhs( NULL ) {}
~ExprComponents() { delete lhs; delete rhs; }
bool testFalse; bool testFalse;
std::string lhs, rhs, op; std::string op;
AnyTypeHolderBase* lhs, *rhs;
} m_exprComponents; } m_exprComponents;
CopyableStream m_stream; CopyableStream m_stream;

View File

@ -41,12 +41,14 @@ namespace Catch {
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
return *this; return *this;
} }
ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { template <typename T>
m_exprComponents.lhs = lhs; ResultBuilder& ResultBuilder::setLhs( T const& lhs ) {
m_exprComponents.lhs = new AnyTypeHolder<T>( lhs );
return *this; return *this;
} }
ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { template <typename T>
m_exprComponents.rhs = rhs; ResultBuilder& ResultBuilder::setRhs( T const& rhs ) {
m_exprComponents.rhs = new AnyTypeHolder<T>( rhs );
return *this; return *this;
} }
ResultBuilder& ResultBuilder::setOp( std::string const& op ) { ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
@ -130,27 +132,31 @@ namespace Catch {
} }
data.message = m_stream.oss.str(); data.message = m_stream.oss.str();
data.reconstructedExpression = reconstructExpression(); if( data.resultType == ResultWas::ExpressionFailed ) {
if( m_exprComponents.testFalse ) { data.reconstructedExpression = reconstructExpression();
if( m_exprComponents.op == "" ) if( m_exprComponents.testFalse ) {
data.reconstructedExpression = "!" + data.reconstructedExpression; if( m_exprComponents.op == "" )
else data.reconstructedExpression = "!" + data.reconstructedExpression;
data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; else
data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
} }
}
return AssertionResult( m_assertionInfo, data ); return AssertionResult( m_assertionInfo, data );
} }
std::string ResultBuilder::reconstructExpression() const { std::string ResultBuilder::reconstructExpression() const {
std::string lhs = m_exprComponents.lhs->toString(),
rhs = m_exprComponents.rhs->toString();
if( m_exprComponents.op == "" ) if( m_exprComponents.op == "" )
return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; return lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + lhs;
else if( m_exprComponents.op == "matches" ) else if( m_exprComponents.op == "matches" )
return m_exprComponents.lhs + " " + m_exprComponents.rhs; return lhs + " " + rhs;
else if( m_exprComponents.op != "!" ) { else if( m_exprComponents.op != "!" ) {
if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && if( lhs.size() + rhs.size() < 40 &&
m_exprComponents.lhs.find("\n") == std::string::npos && lhs.find("\n") == std::string::npos &&
m_exprComponents.rhs.find("\n") == std::string::npos ) rhs.find("\n") == std::string::npos )
return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; return lhs + " " + m_exprComponents.op + " " + rhs;
else else
return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; return lhs + "\n" + m_exprComponents.op + "\n" + rhs;
} }
else else
return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";