From ebf172be0b976a184b7693ebc9ab0a1eb9577f19 Mon Sep 17 00:00:00 2001 From: Ryan Gonzalez Date: Thu, 24 Dec 2015 11:37:28 -0600 Subject: [PATCH] Lazily stringify expressions (closes #556) --- include/internal/catch_capture.hpp | 2 +- include/internal/catch_expression_lhs.hpp | 6 ++-- include/internal/catch_result_builder.h | 24 +++++++++++--- include/internal/catch_result_builder.hpp | 40 +++++++++++++---------- 4 files changed, 47 insertions(+), 25 deletions(-) diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 22cf6959..5a333a86 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -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 ) ); \ diff --git a/include/internal/catch_expression_lhs.hpp b/include/internal/catch_expression_lhs.hpp index 51b803e5..d3f1d8df 100644 --- a/include/internal/catch_expression_lhs.hpp +++ b/include/internal/catch_expression_lhs.hpp @@ -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( m_lhs, rhs ) ) - .setLhs( Catch::toString( m_lhs ) ) - .setRhs( Catch::toString( rhs ) ) + .setLhs( m_lhs ) + .setRhs( rhs ) .setOp( Internal::OperatorTraits::getName() ); } diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h index 89002660..49a621e6 100644 --- a/include/internal/catch_result_builder.h +++ b/include/internal/catch_result_builder.h @@ -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 + 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 + ResultBuilder& setLhs( T const& lhs ); + template + 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; diff --git a/include/internal/catch_result_builder.hpp b/include/internal/catch_result_builder.hpp index d453fecf..570a3265 100644 --- a/include/internal/catch_result_builder.hpp +++ b/include/internal/catch_result_builder.hpp @@ -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 + ResultBuilder& ResultBuilder::setLhs( T const& lhs ) { + m_exprComponents.lhs = new AnyTypeHolder( lhs ); return *this; } - ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { - m_exprComponents.rhs = rhs; + template + ResultBuilder& ResultBuilder::setRhs( T const& rhs ) { + m_exprComponents.rhs = new AnyTypeHolder( rhs ); return *this; } ResultBuilder& ResultBuilder::setOp( std::string const& op ) { @@ -130,27 +132,31 @@ namespace Catch { } data.message = m_stream.oss.str(); - data.reconstructedExpression = reconstructExpression(); - if( m_exprComponents.testFalse ) { - if( m_exprComponents.op == "" ) - data.reconstructedExpression = "!" + data.reconstructedExpression; - else - data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + if( data.resultType == ResultWas::ExpressionFailed ) { + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + 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}";