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 { \
std::string matcherAsString = (matcher).toString(); \
__catchResult \
.setLhs( Catch::toString( arg ) ) \
.setLhs( arg ) \
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
.setOp( "matches" ) \
.setResultType( (matcher).match( arg ) ); \

View File

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

View File

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

View File

@ -41,12 +41,14 @@ namespace Catch {
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
return *this;
}
ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
m_exprComponents.lhs = lhs;
template <typename T>
ResultBuilder& ResultBuilder::setLhs( T const& lhs ) {
m_exprComponents.lhs = new AnyTypeHolder<T>( lhs );
return *this;
}
ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
m_exprComponents.rhs = rhs;
template <typename T>
ResultBuilder& ResultBuilder::setRhs( T const& rhs ) {
m_exprComponents.rhs = new AnyTypeHolder<T>( rhs );
return *this;
}
ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
@ -130,6 +132,7 @@ namespace Catch {
}
data.message = m_stream.oss.str();
if( data.resultType == ResultWas::ExpressionFailed ) {
data.reconstructedExpression = reconstructExpression();
if( m_exprComponents.testFalse ) {
if( m_exprComponents.op == "" )
@ -137,20 +140,23 @@ namespace Catch {
else
data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
}
}
return AssertionResult( m_assertionInfo, data );
}
std::string ResultBuilder::reconstructExpression() const {
std::string lhs = m_exprComponents.lhs->toString(),
rhs = m_exprComponents.rhs->toString();
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" )
return m_exprComponents.lhs + " " + m_exprComponents.rhs;
return lhs + " " + rhs;
else if( m_exprComponents.op != "!" ) {
if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
m_exprComponents.lhs.find("\n") == std::string::npos &&
m_exprComponents.rhs.find("\n") == std::string::npos )
return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
if( lhs.size() + rhs.size() < 40 &&
lhs.find("\n") == std::string::npos &&
rhs.find("\n") == std::string::npos )
return lhs + " " + m_exprComponents.op + " " + rhs;
else
return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
return lhs + "\n" + m_exprComponents.op + "\n" + rhs;
}
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}";