mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	lazily stringify expressions
This commit is contained in:
		 Mickey Rose
					Mickey Rose
				
			
				
					committed by
					
						 Martin Hořeňovský
						Martin Hořeňovský
					
				
			
			
				
	
			
			
			 Martin Hořeňovský
						Martin Hořeňovský
					
				
			
						parent
						
							3b7511e564
						
					
				
				
					commit
					a1e9b841ff
				
			| @@ -13,6 +13,27 @@ | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; | ||||
|  | ||||
|     struct DecomposedExpression | ||||
|     { | ||||
|         virtual ~DecomposedExpression() {} | ||||
|         virtual bool isBinaryExpression() const { | ||||
|             return false; | ||||
|         } | ||||
|         virtual void reconstructExpression( std::string& dest ) const = 0; | ||||
|  | ||||
|         // Only simple binary comparisons can be decomposed. | ||||
|         // If more complex check is required then wrap sub-expressions in parentheses. | ||||
|         template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); | ||||
|         template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); | ||||
|         template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); | ||||
|         template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); | ||||
|         template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); | ||||
|         template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); | ||||
|         template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); | ||||
|     }; | ||||
|  | ||||
|     struct AssertionInfo | ||||
|     { | ||||
|         AssertionInfo() {} | ||||
| @@ -29,11 +50,41 @@ namespace Catch { | ||||
|  | ||||
|     struct AssertionResultData | ||||
|     { | ||||
|         AssertionResultData() : resultType( ResultWas::Unknown ) {} | ||||
|         AssertionResultData() : decomposedExpression( CATCH_NULL ) | ||||
|                               , resultType( ResultWas::Unknown ) | ||||
|                               , negated( false ) | ||||
|                               , parenthesized( false ) {} | ||||
|  | ||||
|         std::string reconstructedExpression; | ||||
|         void negate( bool parenthesize ) { | ||||
|             negated = !negated; | ||||
|             parenthesized = parenthesize; | ||||
|             if( resultType == ResultWas::Ok ) | ||||
|                 resultType = ResultWas::ExpressionFailed; | ||||
|             else if( resultType == ResultWas::ExpressionFailed ) | ||||
|                 resultType = ResultWas::Ok; | ||||
|         } | ||||
|  | ||||
|         std::string const& reconstructExpression() const { | ||||
|             if( decomposedExpression != CATCH_NULL ) { | ||||
|                 decomposedExpression->reconstructExpression( reconstructedExpression ); | ||||
|                 if( parenthesized ) { | ||||
|                     reconstructedExpression.insert( 0, 1, '(' ); | ||||
|                     reconstructedExpression.append( 1, ')' ); | ||||
|                 } | ||||
|                 if( negated ) { | ||||
|                     reconstructedExpression.insert( 0, 1, '!' ); | ||||
|                 } | ||||
|                 decomposedExpression = CATCH_NULL; | ||||
|             } | ||||
|             return reconstructedExpression; | ||||
|         } | ||||
|  | ||||
|         mutable DecomposedExpression const* decomposedExpression; | ||||
|         mutable std::string reconstructedExpression; | ||||
|         std::string message; | ||||
|         ResultWas::OfType resultType; | ||||
|         bool negated; | ||||
|         bool parenthesized; | ||||
|     }; | ||||
|  | ||||
|     class AssertionResult { | ||||
| @@ -60,6 +111,8 @@ namespace Catch { | ||||
|         std::string getMessage() const; | ||||
|         SourceLineInfo getSourceInfo() const; | ||||
|         std::string getTestMacroName() const; | ||||
|         void discardDecomposedExpression() const; | ||||
|         void expandDecomposedExpression() const; | ||||
|  | ||||
|     protected: | ||||
|         AssertionInfo m_info; | ||||
|   | ||||
| @@ -72,7 +72,7 @@ namespace Catch { | ||||
|     } | ||||
|  | ||||
|     std::string AssertionResult::getExpandedExpression() const { | ||||
|         return m_resultData.reconstructedExpression; | ||||
|         return m_resultData.reconstructExpression(); | ||||
|     } | ||||
|  | ||||
|     std::string AssertionResult::getMessage() const { | ||||
| @@ -86,6 +86,14 @@ namespace Catch { | ||||
|         return m_info.macroName; | ||||
|     } | ||||
|  | ||||
|     void AssertionResult::discardDecomposedExpression() const { | ||||
|         m_resultData.decomposedExpression = CATCH_NULL; | ||||
|     } | ||||
|  | ||||
|     void AssertionResult::expandDecomposedExpression() const { | ||||
|         m_resultData.reconstructExpression(); | ||||
|     } | ||||
|  | ||||
| } // end namespace Catch | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED | ||||
|   | ||||
| @@ -132,13 +132,7 @@ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ | ||||
|         try { \ | ||||
|             std::string matcherAsString = (matcher).toString(); \ | ||||
|             __catchResult \ | ||||
|                 .setLhs( Catch::toString( arg ) ) \ | ||||
|                 .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ | ||||
|                 .setOp( "matches" ) \ | ||||
|                 .setResultType( (matcher).match( arg ) ); \ | ||||
|             __catchResult.captureExpression(); \ | ||||
|             __catchResult.captureMatch( arg, matcher, #matcher ); \ | ||||
|         } catch( ... ) { \ | ||||
|             __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ | ||||
|         } \ | ||||
|   | ||||
| @@ -14,90 +14,155 @@ | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
| // Wraps the LHS of an expression and captures the operator and RHS (if any) - | ||||
| // wrapping them all in a ResultBuilder object | ||||
| template<typename T> | ||||
| class ExpressionLhs { | ||||
|     ExpressionLhs& operator = ( ExpressionLhs const& ); | ||||
| #  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | ||||
|     ExpressionLhs& operator = ( ExpressionLhs && ) = delete; | ||||
| #  endif | ||||
| template<typename LhsT, Internal::Operator Op, typename RhsT> | ||||
| class BinaryExpression; | ||||
|  | ||||
| template<typename ArgT, typename MatcherT> | ||||
| class MatchExpression; | ||||
|  | ||||
| // Wraps the LHS of an expression and overloads comparison operators | ||||
| // for also capturing those and RHS (if any) | ||||
| template<typename T> | ||||
| class ExpressionLhs : public DecomposedExpression { | ||||
| public: | ||||
|     ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} | ||||
| #  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | ||||
|     ExpressionLhs( ExpressionLhs const& ) = default; | ||||
|     ExpressionLhs( ExpressionLhs && )     = default; | ||||
| #  endif | ||||
|     ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     ResultBuilder& operator == ( RhsT const& rhs ) { | ||||
|     BinaryExpression<T, Internal::IsEqualTo, RhsT const&> | ||||
|     operator == ( RhsT const& rhs ) const { | ||||
|         return captureExpression<Internal::IsEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     ResultBuilder& operator != ( RhsT const& rhs ) { | ||||
|     BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&> | ||||
|     operator != ( RhsT const& rhs ) const { | ||||
|         return captureExpression<Internal::IsNotEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     ResultBuilder& operator < ( RhsT const& rhs ) { | ||||
|     BinaryExpression<T, Internal::IsLessThan, RhsT const&> | ||||
|     operator < ( RhsT const& rhs ) const { | ||||
|         return captureExpression<Internal::IsLessThan>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     ResultBuilder& operator > ( RhsT const& rhs ) { | ||||
|     BinaryExpression<T, Internal::IsGreaterThan, RhsT const&> | ||||
|     operator > ( RhsT const& rhs ) const { | ||||
|         return captureExpression<Internal::IsGreaterThan>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     ResultBuilder& operator <= ( RhsT const& rhs ) { | ||||
|     BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&> | ||||
|     operator <= ( RhsT const& rhs ) const { | ||||
|         return captureExpression<Internal::IsLessThanOrEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     ResultBuilder& operator >= ( RhsT const& rhs ) { | ||||
|     BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&> | ||||
|     operator >= ( RhsT const& rhs ) const { | ||||
|         return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     ResultBuilder& operator == ( bool rhs ) { | ||||
|     BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) const { | ||||
|         return captureExpression<Internal::IsEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     ResultBuilder& operator != ( bool rhs ) { | ||||
|     BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) const { | ||||
|         return captureExpression<Internal::IsNotEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     void endExpression() { | ||||
|         bool value = m_lhs ? true : false; | ||||
|         m_truthy = m_lhs ? true : false; | ||||
|         m_rb | ||||
|             .setLhs( Catch::toString( value ) ) | ||||
|             .setResultType( value ) | ||||
|             .endExpression(); | ||||
|             .setResultType( m_truthy ) | ||||
|             .endExpression( *this ); | ||||
|     } | ||||
|  | ||||
|     // Only simple binary expressions are allowed on the LHS. | ||||
|     // If more complex compositions are required then place the sub expression in parentheses | ||||
|     template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); | ||||
|     template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); | ||||
|     template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); | ||||
|     template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); | ||||
|     template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); | ||||
|     template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); | ||||
|     virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { | ||||
|         dest = Catch::toString( m_truthy ); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     template<Internal::Operator Op, typename RhsT> | ||||
|     ResultBuilder& captureExpression( RhsT const& rhs ) { | ||||
|         return m_rb | ||||
|             .setResultType( Internal::compare<Op>( m_lhs, rhs ) ) | ||||
|             .setLhs( Catch::toString( m_lhs ) ) | ||||
|             .setRhs( Catch::toString( rhs ) ) | ||||
|             .setOp( Internal::OperatorTraits<Op>::getName() ); | ||||
|     BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const { | ||||
|         return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs ); | ||||
|     } | ||||
|  | ||||
|     template<Internal::Operator Op> | ||||
|     BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const { | ||||
|         return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs ); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     ResultBuilder& m_rb; | ||||
|     T m_lhs; | ||||
|     bool m_truthy; | ||||
| }; | ||||
|  | ||||
| template<typename LhsT, Internal::Operator Op, typename RhsT> | ||||
| class BinaryExpression : public DecomposedExpression { | ||||
| public: | ||||
|     BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) | ||||
|         : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} | ||||
|  | ||||
|     void endExpression() const { | ||||
|         m_rb | ||||
|             .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) ) | ||||
|             .endExpression( *this ); | ||||
|     } | ||||
|  | ||||
|     virtual bool isBinaryExpression() const CATCH_OVERRIDE { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { | ||||
|         std::string lhs = Catch::toString( m_lhs ); | ||||
|         std::string rhs = Catch::toString( m_rhs ); | ||||
|         char delim = lhs.size() + rhs.size() < 40 && | ||||
|                      lhs.find('\n') == std::string::npos && | ||||
|                      rhs.find('\n') == std::string::npos ? ' ' : '\n'; | ||||
|         dest.reserve( 7 + lhs.size() + rhs.size() ); | ||||
|                    // 2 for spaces around operator | ||||
|                    // 2 for operator | ||||
|                    // 2 for parentheses (conditionally added later) | ||||
|                    // 1 for negation (conditionally added later) | ||||
|         dest = lhs; | ||||
|         dest += delim; | ||||
|         dest += Internal::OperatorTraits<Op>::getName(); | ||||
|         dest += delim; | ||||
|         dest += rhs; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     ResultBuilder& m_rb; | ||||
|     LhsT m_lhs; | ||||
|     RhsT m_rhs; | ||||
| }; | ||||
|  | ||||
| template<typename ArgT, typename MatcherT> | ||||
| class MatchExpression : public DecomposedExpression { | ||||
| public: | ||||
|     MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) | ||||
|         : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} | ||||
|  | ||||
|     virtual bool isBinaryExpression() const CATCH_OVERRIDE { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { | ||||
|         std::string matcherAsString = m_matcher.toString(); | ||||
|         dest = Catch::toString( m_arg ); | ||||
|         dest += ' '; | ||||
|         if( matcherAsString == Detail::unprintableString ) | ||||
|             dest += m_matcherString; | ||||
|         else | ||||
|             dest += matcherAsString; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     ArgT m_arg; | ||||
|     MatcherT m_matcher; | ||||
|     char const* m_matcherString; | ||||
| }; | ||||
|  | ||||
| } // end namespace Catch | ||||
|   | ||||
| @@ -19,8 +19,6 @@ namespace Catch { | ||||
|  | ||||
|     template<typename T> class ExpressionLhs; | ||||
|  | ||||
|     struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; | ||||
|  | ||||
|     struct CopyableStream { | ||||
|         CopyableStream() {} | ||||
|         CopyableStream( CopyableStream const& other ) { | ||||
| @@ -34,7 +32,7 @@ namespace Catch { | ||||
|         std::ostringstream oss; | ||||
|     }; | ||||
|  | ||||
|     class ResultBuilder { | ||||
|     class ResultBuilder : public DecomposedExpression { | ||||
|     public: | ||||
|         ResultBuilder(  char const* macroName, | ||||
|                         SourceLineInfo const& lineInfo, | ||||
| @@ -52,19 +50,15 @@ namespace Catch { | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); | ||||
|         template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); | ||||
|  | ||||
|         ResultBuilder& setResultType( ResultWas::OfType result ); | ||||
|         ResultBuilder& setResultType( bool result ); | ||||
|         ResultBuilder& setLhs( std::string const& lhs ); | ||||
|         ResultBuilder& setRhs( std::string const& rhs ); | ||||
|         ResultBuilder& setOp( std::string const& op ); | ||||
|  | ||||
|         void endExpression(); | ||||
|         void endExpression( DecomposedExpression const& expr ); | ||||
|  | ||||
|         virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; | ||||
|  | ||||
|         std::string reconstructExpression() const; | ||||
|         AssertionResult build() const; | ||||
|         AssertionResult build( DecomposedExpression const& expr ) const; | ||||
|  | ||||
|         void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); | ||||
|         void captureResult( ResultWas::OfType resultType ); | ||||
| @@ -76,14 +70,12 @@ namespace Catch { | ||||
|         bool shouldDebugBreak() const; | ||||
|         bool allowThrows() const; | ||||
|  | ||||
|         template<typename ArgT, typename MatcherT> | ||||
|         void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); | ||||
|  | ||||
|     private: | ||||
|         AssertionInfo m_assertionInfo; | ||||
|         AssertionResultData m_data; | ||||
|         struct ExprComponents { | ||||
|             ExprComponents() : testFalse( false ) {} | ||||
|             bool testFalse; | ||||
|             std::string lhs, rhs, op; | ||||
|         } m_exprComponents; | ||||
|         CopyableStream m_stream; | ||||
|  | ||||
|         bool m_shouldDebugBreak; | ||||
| @@ -106,6 +98,14 @@ namespace Catch { | ||||
|         return ExpressionLhs<bool>( *this, value ); | ||||
|     } | ||||
|  | ||||
|     template<typename ArgT, typename MatcherT> | ||||
|     inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, | ||||
|                                              char const* matcherString ) { | ||||
|         MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString ); | ||||
|         setResultType( matcher.match( arg ) ); | ||||
|         endExpression( expr ); | ||||
|     } | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED | ||||
|   | ||||
| @@ -41,22 +41,10 @@ namespace Catch { | ||||
|         m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; | ||||
|         return *this; | ||||
|     } | ||||
|     ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { | ||||
|         m_exprComponents.lhs = lhs; | ||||
|         return *this; | ||||
|     } | ||||
|     ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { | ||||
|         m_exprComponents.rhs = rhs; | ||||
|         return *this; | ||||
|     } | ||||
|     ResultBuilder& ResultBuilder::setOp( std::string const& op ) { | ||||
|         m_exprComponents.op = op; | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::endExpression() { | ||||
|         m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); | ||||
|         captureExpression(); | ||||
|     void ResultBuilder::endExpression( DecomposedExpression const& expr ) { | ||||
|         AssertionResult result = build( expr ); | ||||
|         handleResult( result ); | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { | ||||
| @@ -69,6 +57,7 @@ namespace Catch { | ||||
|         setResultType( resultType ); | ||||
|         captureExpression(); | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { | ||||
|         if( expectedMessage.empty() ) | ||||
|             captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() ); | ||||
| @@ -78,7 +67,7 @@ namespace Catch { | ||||
|  | ||||
|     void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) { | ||||
|  | ||||
|         assert( m_exprComponents.testFalse == false ); | ||||
|         assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); | ||||
|         AssertionResultData data = m_data; | ||||
|         data.resultType = ResultWas::Ok; | ||||
|         data.reconstructedExpression = m_assertionInfo.capturedExpression; | ||||
| @@ -96,6 +85,7 @@ namespace Catch { | ||||
|         AssertionResult result = build(); | ||||
|         handleResult( result ); | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::handleResult( AssertionResult const& result ) | ||||
|     { | ||||
|         getResultCapture().assertionEnded( result ); | ||||
| @@ -107,6 +97,7 @@ namespace Catch { | ||||
|                 m_shouldThrow = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::react() { | ||||
|         if( m_shouldThrow ) | ||||
|             throw Catch::TestFailureException(); | ||||
| @@ -117,43 +108,32 @@ namespace Catch { | ||||
|  | ||||
|     AssertionResult ResultBuilder::build() const | ||||
|     { | ||||
|         assert( m_data.resultType != ResultWas::Unknown ); | ||||
|         return build( *this ); | ||||
|     } | ||||
|  | ||||
|     // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, | ||||
|     //         a temporary DecomposedExpression, which in turn holds references to | ||||
|     //         operands, possibly temporary as well. | ||||
|     //         It should immediately be passed to handleResult; if the expression | ||||
|     //         needs to be reported, its string expansion must be composed before | ||||
|     //         the temporaries are destroyed. | ||||
|     AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const | ||||
|     { | ||||
|         assert( m_data.resultType != ResultWas::Unknown ); | ||||
|         AssertionResultData data = m_data; | ||||
|  | ||||
|         // Flip bool results if testFalse is set | ||||
|         if( m_exprComponents.testFalse ) { | ||||
|             if( data.resultType == ResultWas::Ok ) | ||||
|                 data.resultType = ResultWas::ExpressionFailed; | ||||
|             else if( data.resultType == ResultWas::ExpressionFailed ) | ||||
|                 data.resultType = ResultWas::Ok; | ||||
|         // Flip bool results if FalseTest flag is set | ||||
|         if( isFalseTest( m_assertionInfo.resultDisposition ) ) { | ||||
|             data.negate( expr.isBinaryExpression() ); | ||||
|         } | ||||
|  | ||||
|         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 + ")"; | ||||
|         } | ||||
|         data.decomposedExpression = &expr; // for lazy reconstruction | ||||
|         return AssertionResult( m_assertionInfo, data ); | ||||
|     } | ||||
|     std::string ResultBuilder::reconstructExpression() const { | ||||
|         if( m_exprComponents.op == "" ) | ||||
|             return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.lhs; | ||||
|         else if( m_exprComponents.op == "matches" ) | ||||
|             return m_exprComponents.lhs + " " + m_exprComponents.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; | ||||
|             else | ||||
|                 return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.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}"; | ||||
|  | ||||
|     void ResultBuilder::reconstructExpression( std::string& dest ) const { | ||||
|         dest = m_assertionInfo.capturedExpression; | ||||
|     } | ||||
|  | ||||
| } // end namespace Catch | ||||
|   | ||||
		Reference in New Issue
	
	Block a user