mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 12:17:11 +01:00 
			
		
		
		
	Lazily stringify expressions (closes #556)
This commit is contained in:
		| @@ -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 ) ); \ | ||||
|   | ||||
| @@ -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() ); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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,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}"; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ryan Gonzalez
					Ryan Gonzalez