mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Merge branch 'reevaluate' into dev-modernize
This commit is contained in:
		| @@ -41,6 +41,10 @@ | ||||
| #include "internal/catch_compiler_capabilities.h" | ||||
| #include "internal/catch_interfaces_tag_alias_registry.h" | ||||
|  | ||||
| #ifndef CATCH_CONFIG_DISABLE_MATCHERS | ||||
| #include "internal/catch_capture_matchers.h" | ||||
| #endif | ||||
|  | ||||
| // These files are included here so the single_include script doesn't put them | ||||
| // in the conditionally compiled sections | ||||
| #include "internal/catch_test_case_info.h" | ||||
| @@ -72,8 +76,8 @@ | ||||
|  | ||||
| #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) | ||||
| #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) | ||||
| #endif// CATCH_CONFIG_DISABLE_MATCHERS | ||||
| #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) | ||||
| @@ -86,8 +90,8 @@ | ||||
|  | ||||
| #define CATCH_CHECK_THROWS( ... )  INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) | ||||
| #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
| #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | ||||
| @@ -132,8 +136,8 @@ | ||||
|  | ||||
| #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) | ||||
| #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
| #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) | ||||
| @@ -146,8 +150,8 @@ | ||||
|  | ||||
| #define CHECK_THROWS( ... )  INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | ||||
| #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
| #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | ||||
|   | ||||
							
								
								
									
										147
									
								
								include/internal/catch_assertionhandler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								include/internal/catch_assertionhandler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| /* | ||||
|  *  Created by Phil on 8/8/2017. | ||||
|  *  Copyright 2017 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
|  | ||||
| #include "catch_assertionhandler.h" | ||||
| #include "catch_assertionresult.h" | ||||
| #include "catch_interfaces_capture.h" | ||||
| #include "catch_interfaces_runner.h" | ||||
| #include "catch_interfaces_config.h" | ||||
| #include "catch_context.h" | ||||
| #include "catch_debugger.h" | ||||
| #include "catch_interfaces_registry_hub.h" | ||||
| #include "catch_capture_matchers.h" | ||||
|  | ||||
| #include <cassert> | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { | ||||
|         expr.streamReconstructedExpression( os ); | ||||
|         return os; | ||||
|     } | ||||
|  | ||||
|     LazyExpression::LazyExpression( bool isNegated ) | ||||
|     :   m_isNegated( isNegated ) | ||||
|     {} | ||||
|  | ||||
|     LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} | ||||
|  | ||||
|     LazyExpression::operator bool() const { | ||||
|         return m_transientExpression != nullptr; | ||||
|     } | ||||
|  | ||||
|     auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { | ||||
|         if( lazyExpr.m_isNegated ) | ||||
|             os << "!"; | ||||
|  | ||||
|         if( lazyExpr ) { | ||||
|             if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) | ||||
|                 os << "(" << *lazyExpr.m_transientExpression << ")"; | ||||
|             else | ||||
|                 os << *lazyExpr.m_transientExpression; | ||||
|         } | ||||
|         else { | ||||
|             os << "{** error - unchecked empty expression requested **}"; | ||||
|         } | ||||
|         return os; | ||||
|     } | ||||
|  | ||||
|     AssertionHandler::AssertionHandler | ||||
|         (   StringRef macroName, | ||||
|             SourceLineInfo const& lineInfo, | ||||
|             StringRef capturedExpression, | ||||
|             ResultDisposition::Flags resultDisposition ) | ||||
|     :   m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } | ||||
|     { | ||||
|         getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); | ||||
|     } | ||||
|     AssertionHandler::~AssertionHandler() { | ||||
|         if ( m_inExceptionGuard ) { | ||||
|             handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ); | ||||
|             getCurrentContext().getResultCapture()->exceptionEarlyReported(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void AssertionHandler::handle( ITransientExpression const& expr ) { | ||||
|  | ||||
|         bool negated = isFalseTest( m_assertionInfo.resultDisposition ); | ||||
|         bool result = expr.getResult() != negated; | ||||
|  | ||||
|         handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); | ||||
|     } | ||||
|     void AssertionHandler::handle( ResultWas::OfType resultType ) { | ||||
|         handle( resultType, nullptr, false ); | ||||
|     } | ||||
|     void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) { | ||||
|         AssertionResultData data( resultType, LazyExpression( false ) ); | ||||
|         data.message = message.c_str(); | ||||
|         handle( data, nullptr ); | ||||
|     } | ||||
|     void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { | ||||
|         AssertionResultData data( resultType, LazyExpression( negated ) ); | ||||
|         handle( data, expr ); | ||||
|     } | ||||
|     void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) { | ||||
|  | ||||
|         getResultCapture().assertionRun(); | ||||
|  | ||||
|         AssertionResult assertionResult{ m_assertionInfo, resultData }; | ||||
|         assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; | ||||
|  | ||||
|         getResultCapture().assertionEnded( assertionResult ); | ||||
|  | ||||
|         if( !assertionResult.isOk() ) { | ||||
|             m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); | ||||
|             m_shouldThrow = | ||||
|                     getCurrentContext().getRunner()->aborting() || | ||||
|                     (m_assertionInfo.resultDisposition & ResultDisposition::Normal); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     auto AssertionHandler::allowThrows() const -> bool { | ||||
|         return getCurrentContext().getConfig()->allowThrows(); | ||||
|     } | ||||
|  | ||||
|     auto AssertionHandler::shouldDebugBreak() const -> bool { | ||||
|         return m_shouldDebugBreak; | ||||
|     } | ||||
|     void AssertionHandler::reactWithDebugBreak() const { | ||||
|         if (m_shouldDebugBreak) { | ||||
|             /////////////////////////////////////////////////////////////////// | ||||
|             // To inspect the state during test, you need to go one level up the callstack | ||||
|             // To go back to the test and change execution, jump over the reactWithoutDebugBreak() call | ||||
|             /////////////////////////////////////////////////////////////////// | ||||
|             CATCH_BREAK_INTO_DEBUGGER(); | ||||
|         } | ||||
|         reactWithoutDebugBreak(); | ||||
|     } | ||||
|     void AssertionHandler::reactWithoutDebugBreak() const { | ||||
|         if( m_shouldThrow ) | ||||
|             throw Catch::TestFailureException(); | ||||
|     } | ||||
|  | ||||
|     void AssertionHandler::useActiveException() { | ||||
|         handle( ResultWas::ThrewException, Catch::translateActiveException().c_str() ); | ||||
|     } | ||||
|  | ||||
|     void AssertionHandler::setExceptionGuard() { | ||||
|         assert( m_inExceptionGuard == false ); | ||||
|         m_inExceptionGuard = true; | ||||
|     } | ||||
|     void AssertionHandler::unsetExceptionGuard() { | ||||
|         assert( m_inExceptionGuard == true ); | ||||
|         m_inExceptionGuard = false; | ||||
|     } | ||||
|  | ||||
|     // This is the overload that takes a string and infers the Equals matcher from it | ||||
|     // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp | ||||
|     void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString  ) { | ||||
|         handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); | ||||
|     } | ||||
|  | ||||
| } // namespace Catch | ||||
							
								
								
									
										73
									
								
								include/internal/catch_assertionhandler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								include/internal/catch_assertionhandler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| /* | ||||
|  *  Created by Phil on 8/8/2017. | ||||
|  *  Copyright 2017 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED | ||||
|  | ||||
| #include "catch_decomposer.h" | ||||
| #include "catch_assertioninfo.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct TestFailureException{}; | ||||
|     struct AssertionResultData; | ||||
|  | ||||
|     class LazyExpression { | ||||
|         friend class AssertionHandler; | ||||
|         friend struct AssertionStats; | ||||
|  | ||||
|         ITransientExpression const* m_transientExpression = nullptr; | ||||
|         bool m_isNegated; | ||||
|     public: | ||||
|         LazyExpression( bool isNegated ); | ||||
|         LazyExpression( LazyExpression const& other ); | ||||
|         LazyExpression& operator = ( LazyExpression const& ) = delete; | ||||
|  | ||||
|         explicit operator bool() const; | ||||
|  | ||||
|         friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; | ||||
|     }; | ||||
|  | ||||
|     class AssertionHandler { | ||||
|         AssertionInfo m_assertionInfo; | ||||
|         bool m_shouldDebugBreak = false; | ||||
|         bool m_shouldThrow = false; | ||||
|         bool m_inExceptionGuard = false; | ||||
|  | ||||
|     public: | ||||
|         AssertionHandler | ||||
|             (   StringRef macroName, | ||||
|                 SourceLineInfo const& lineInfo, | ||||
|                 StringRef capturedExpression, | ||||
|                 ResultDisposition::Flags resultDisposition ); | ||||
|         ~AssertionHandler(); | ||||
|  | ||||
|         void handle( ITransientExpression const& expr ); | ||||
|  | ||||
|         template<typename T> | ||||
|         void handle( ExprLhs<T> const& expr ) { | ||||
|             handle( expr.makeUnaryExpr() ); | ||||
|         } | ||||
|         void handle( ResultWas::OfType resultType ); | ||||
|         void handle( ResultWas::OfType resultType, StringRef const& message ); | ||||
|         void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); | ||||
|         void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); | ||||
|  | ||||
|         auto shouldDebugBreak() const -> bool; | ||||
|         auto allowThrows() const -> bool; | ||||
|         void reactWithDebugBreak() const; | ||||
|         void reactWithoutDebugBreak() const; | ||||
|         void useActiveException(); | ||||
|         void setExceptionGuard(); | ||||
|         void unsetExceptionGuard(); | ||||
|     }; | ||||
|  | ||||
|     void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED | ||||
							
								
								
									
										31
									
								
								include/internal/catch_assertioninfo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								include/internal/catch_assertioninfo.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
|  *  Created by Phil on 8/8/2017. | ||||
|  *  Copyright 2017 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED | ||||
|  | ||||
| #include "catch_result_type.h" | ||||
| #include "catch_common.h" | ||||
| #include "catch_stringref.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct AssertionInfo | ||||
|     { | ||||
|         StringRef macroName; | ||||
|         SourceLineInfo lineInfo; | ||||
|         StringRef capturedExpression; | ||||
|         ResultDisposition::Flags resultDisposition; | ||||
|  | ||||
|         // We want to delete this constructor but a compiler bug in 4.8 means | ||||
|         // the struct is then treated as non-aggregate | ||||
|         //AssertionInfo() = delete; | ||||
|     }; | ||||
|  | ||||
| } // end namespace Catch | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED | ||||
| @@ -10,54 +10,24 @@ | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     std::string AssertionResultData::reconstructExpression() const { | ||||
|  | ||||
|     bool DecomposedExpression::isBinaryExpression() const { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     AssertionInfo::AssertionInfo(   char const * _macroName, | ||||
|                                     SourceLineInfo const& _lineInfo, | ||||
|                                     char const * _capturedExpression, | ||||
|                                     ResultDisposition::Flags _resultDisposition) | ||||
|     :   macroName( _macroName ), | ||||
|         lineInfo( _lineInfo ), | ||||
|         capturedExpression( _capturedExpression ), | ||||
|         resultDisposition( _resultDisposition ) | ||||
|     {} | ||||
|  | ||||
|     void AssertionResultData::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& AssertionResultData::reconstructExpression() const { | ||||
|         if( decomposedExpression != nullptr ) { | ||||
|             decomposedExpression->reconstructExpression( reconstructedExpression ); | ||||
|             if( parenthesized ) { | ||||
|                 reconstructedExpression.insert( 0, 1, '(' ); | ||||
|                 reconstructedExpression.append( 1, ')' ); | ||||
|         if( reconstructedExpression.empty() ) { | ||||
|             if( lazyExpression ) { | ||||
|                 // !TBD Use stringstream for now, but rework above to pass stream in | ||||
|                 std::ostringstream oss; | ||||
|                 oss << lazyExpression; | ||||
|                 reconstructedExpression = oss.str(); | ||||
|             } | ||||
|             if( negated ) { | ||||
|                 reconstructedExpression.insert( 0, 1, '!' ); | ||||
|             } | ||||
|             decomposedExpression = nullptr; | ||||
|         } | ||||
|         return reconstructedExpression; | ||||
|     } | ||||
|  | ||||
|     AssertionResult::AssertionResult() {} | ||||
|  | ||||
|     AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) | ||||
|     :   m_info( info ), | ||||
|         m_resultData( data ) | ||||
|     {} | ||||
|  | ||||
|     AssertionResult::~AssertionResult() {} | ||||
|  | ||||
|     // Result was a success | ||||
|     bool AssertionResult::succeeded() const { | ||||
|         return Catch::isOk( m_resultData.resultType ); | ||||
| @@ -82,16 +52,16 @@ namespace Catch { | ||||
|  | ||||
|     std::string AssertionResult::getExpression() const { | ||||
|         if (isFalseTest(m_info.resultDisposition)) | ||||
|             return '!' + std::string(m_info.capturedExpression); | ||||
|             return '!' + std::string(m_info.capturedExpression.c_str()); | ||||
|         else | ||||
|             return std::string(m_info.capturedExpression); | ||||
|             return std::string(m_info.capturedExpression.c_str()); | ||||
|     } | ||||
|  | ||||
|     std::string AssertionResult::getExpressionInMacro() const { | ||||
|         if( m_info.macroName[0] == 0 ) | ||||
|             return std::string(m_info.capturedExpression); | ||||
|             return std::string(m_info.capturedExpression.c_str()); | ||||
|         else | ||||
|             return std::string(m_info.macroName) + "( " + m_info.capturedExpression + " )"; | ||||
|             return std::string(m_info.macroName.c_str()) + "( " + m_info.capturedExpression.c_str() + " )"; | ||||
|     } | ||||
|  | ||||
|     bool AssertionResult::hasExpandedExpression() const { | ||||
| @@ -99,7 +69,10 @@ namespace Catch { | ||||
|     } | ||||
|  | ||||
|     std::string AssertionResult::getExpandedExpression() const { | ||||
|         return m_resultData.reconstructExpression(); | ||||
|         std::string expr = m_resultData.reconstructExpression(); | ||||
|         return expr.empty() | ||||
|                 ? getExpression() | ||||
|                 : expr; | ||||
|     } | ||||
|  | ||||
|     std::string AssertionResult::getMessage() const { | ||||
| @@ -110,15 +83,7 @@ namespace Catch { | ||||
|     } | ||||
|  | ||||
|     std::string AssertionResult::getTestMacroName() const { | ||||
|         return m_info.macroName; | ||||
|     } | ||||
|  | ||||
|     void AssertionResult::discardDecomposedExpression() const { | ||||
|         m_resultData.decomposedExpression = nullptr; | ||||
|     } | ||||
|  | ||||
|     void AssertionResult::expandDecomposedExpression() const { | ||||
|         m_resultData.reconstructExpression(); | ||||
|         return m_info.macroName.c_str(); | ||||
|     } | ||||
|  | ||||
| } // end namespace Catch | ||||
|   | ||||
| @@ -9,71 +9,36 @@ | ||||
| #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED | ||||
|  | ||||
| #include <string> | ||||
| #include "catch_assertioninfo.h" | ||||
| #include "catch_result_type.h" | ||||
| #include "catch_common.h" | ||||
| #include "catch_stringref.h" | ||||
| #include "catch_assertionhandler.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; | ||||
|  | ||||
|     struct DecomposedExpression | ||||
|     { | ||||
|         DecomposedExpression() = default; | ||||
|         DecomposedExpression( DecomposedExpression const& ) = default; | ||||
|         DecomposedExpression& operator = ( DecomposedExpression const& ) = delete; | ||||
|  | ||||
|         virtual ~DecomposedExpression() = default; | ||||
|         virtual bool isBinaryExpression() const; | ||||
|         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() = default; | ||||
|         AssertionInfo(  char const * _macroName, | ||||
|                         SourceLineInfo const& _lineInfo, | ||||
|                         char const * _capturedExpression, | ||||
|                         ResultDisposition::Flags _resultDisposition); | ||||
|  | ||||
|         char const * macroName = nullptr; | ||||
|         SourceLineInfo lineInfo; | ||||
|         char const * capturedExpression = nullptr; | ||||
|         ResultDisposition::Flags resultDisposition = ResultDisposition::Normal; | ||||
|     }; | ||||
|  | ||||
|     struct AssertionResultData | ||||
|     { | ||||
|         void negate( bool parenthesize ); | ||||
|         std::string const& reconstructExpression() const; | ||||
|         AssertionResultData() = delete; | ||||
|  | ||||
|         AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ) | ||||
|         :   resultType( _resultType ), | ||||
|             lazyExpression( _lazyExpression ) | ||||
|         {} | ||||
|  | ||||
|         mutable DecomposedExpression const* decomposedExpression = nullptr; | ||||
|         mutable std::string reconstructedExpression; | ||||
|         std::string message; | ||||
|         ResultWas::OfType resultType = ResultWas::Unknown; | ||||
|         bool negated = false; | ||||
|         bool parenthesized = false; | ||||
|         std::string message; | ||||
|  | ||||
|         LazyExpression lazyExpression; | ||||
|  | ||||
|         std::string reconstructExpression() const; | ||||
|         mutable std::string reconstructedExpression; | ||||
|     }; | ||||
|  | ||||
|     class AssertionResult { | ||||
|     public: | ||||
|         AssertionResult(); | ||||
|         AssertionResult() = delete; | ||||
|         AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); | ||||
|         ~AssertionResult(); | ||||
|  | ||||
|         AssertionResult( AssertionResult const& )              = default; | ||||
|         AssertionResult( AssertionResult && )                  = default; | ||||
|         AssertionResult& operator = ( AssertionResult const& ) = default; | ||||
|         AssertionResult& operator = ( AssertionResult && )     = default; | ||||
|  | ||||
|         bool isOk() const; | ||||
|         bool succeeded() const; | ||||
| @@ -87,10 +52,8 @@ namespace Catch { | ||||
|         std::string getMessage() const; | ||||
|         SourceLineInfo getSourceInfo() const; | ||||
|         std::string getTestMacroName() const; | ||||
|         void discardDecomposedExpression() const; | ||||
|         void expandDecomposedExpression() const; | ||||
|  | ||||
|     protected: | ||||
|     //protected: | ||||
|         AssertionInfo m_info; | ||||
|         AssertionResultData m_resultData; | ||||
|     }; | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
|  | ||||
| #include "catch_benchmark.h" | ||||
| #include "catch_capture.hpp" | ||||
| #include "catch_interfaces_reporter.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|   | ||||
| @@ -8,14 +8,9 @@ | ||||
| #ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED | ||||
|  | ||||
| #include "catch_result_builder.h" | ||||
| #include "catch_assertionhandler.h" | ||||
| #include "catch_message.h" | ||||
| #include "catch_interfaces_capture.h" | ||||
| #include "catch_debugger.h" | ||||
| #include "catch_common.h" | ||||
| #include "catch_tostring.h" | ||||
| #include "catch_interfaces_runner.h" | ||||
| #include "catch_compiler_capabilities.h" | ||||
|  | ||||
|  | ||||
| #if defined(CATCH_CONFIG_FAST_COMPILE) | ||||
| @@ -23,43 +18,45 @@ | ||||
| // We can speedup compilation significantly by breaking into debugger lower in | ||||
| // the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER | ||||
| // macro in each assertion | ||||
| #define INTERNAL_CATCH_REACT( resultBuilder ) \ | ||||
|     resultBuilder.react(); | ||||
| #define INTERNAL_CATCH_REACT( handler ) \ | ||||
|     handler.reactWithDebugBreak(); | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // Another way to speed-up compilation is to omit local try-catch for REQUIRE* | ||||
| // macros. | ||||
| // This can potentially cause false negative, if the test code catches | ||||
| // the exception before it propagates back up to the runner. | ||||
| #define INTERNAL_CATCH_TRY | ||||
| #define INTERNAL_CATCH_CATCH( capturer, disposition ) | ||||
| #define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard(); | ||||
| #define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard(); | ||||
|  | ||||
| #else // CATCH_CONFIG_FAST_COMPILE | ||||
|  | ||||
| #include "catch_debugger.h" | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // In the event of a failure works out if the debugger needs to be invoked | ||||
| // and/or an exception thrown and takes appropriate action. | ||||
| // This needs to be done as a macro so the debugger will stop in the user | ||||
| // source code rather than in Catch library code | ||||
| #define INTERNAL_CATCH_REACT( resultBuilder ) \ | ||||
|     if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ | ||||
|     resultBuilder.react();  | ||||
| #define INTERNAL_CATCH_REACT( handler ) \ | ||||
|     if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ | ||||
|     handler.reactWithoutDebugBreak(); | ||||
|  | ||||
| #define INTERNAL_CATCH_TRY try | ||||
| #define INTERNAL_CATCH_CATCH( capturer, disposition ) catch(...) { capturer.useActiveException( disposition ); } | ||||
| #define INTERNAL_CATCH_TRY( capturer ) try | ||||
| #define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ | ||||
|         INTERNAL_CATCH_TRY { \ | ||||
|         Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ | ||||
|         INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ | ||||
|             CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ | ||||
|             ( __catchResult <= __VA_ARGS__ ).endExpression(); \ | ||||
|             catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ | ||||
|             CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ | ||||
|         } INTERNAL_CATCH_CATCH( __catchResult, resultDisposition ) \ | ||||
|         INTERNAL_CATCH_REACT( __catchResult ) \ | ||||
|         } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ | ||||
|         INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | ||||
|     } while( Catch::isTrue( false && static_cast<bool>( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look | ||||
|     // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. | ||||
|  | ||||
| @@ -76,117 +73,84 @@ | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ | ||||
|         Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ | ||||
|         try { \ | ||||
|             static_cast<void>(__VA_ARGS__); \ | ||||
|             __catchResult.captureResult( Catch::ResultWas::Ok ); \ | ||||
|             catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ | ||||
|         } \ | ||||
|         catch( ... ) { \ | ||||
|             __catchResult.useActiveException( resultDisposition ); \ | ||||
|             catchAssertionHandler.useActiveException(); \ | ||||
|         } \ | ||||
|         INTERNAL_CATCH_REACT( __catchResult ) \ | ||||
|         INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition); \ | ||||
|         if( __catchResult.allowThrows() ) \ | ||||
|         Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition); \ | ||||
|         if( catchAssertionHandler.allowThrows() ) \ | ||||
|             try { \ | ||||
|                 static_cast<void>(__VA_ARGS__); \ | ||||
|                 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ | ||||
|                 catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ | ||||
|             } \ | ||||
|             catch( ... ) { \ | ||||
|                 __catchResult.captureExpectedException( "" ); \ | ||||
|                 catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ | ||||
|             } \ | ||||
|         else \ | ||||
|             __catchResult.captureResult( Catch::ResultWas::Ok ); \ | ||||
|         INTERNAL_CATCH_REACT( __catchResult ) \ | ||||
|             catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ | ||||
|         INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ | ||||
|         if( __catchResult.allowThrows() ) \ | ||||
|         Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ | ||||
|         if( catchAssertionHandler.allowThrows() ) \ | ||||
|             try { \ | ||||
|                 static_cast<void>(expr); \ | ||||
|                 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ | ||||
|                 catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ | ||||
|             } \ | ||||
|             catch( exceptionType const& ) { \ | ||||
|                 __catchResult.captureResult( Catch::ResultWas::Ok ); \ | ||||
|                 catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ | ||||
|             } \ | ||||
|             catch( ... ) { \ | ||||
|                 __catchResult.useActiveException( resultDisposition ); \ | ||||
|                 catchAssertionHandler.useActiveException(); \ | ||||
|             } \ | ||||
|         else \ | ||||
|             __catchResult.captureResult( Catch::ResultWas::Ok ); \ | ||||
|         INTERNAL_CATCH_REACT( __catchResult ) \ | ||||
|             catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ | ||||
|         INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
|  | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ | ||||
|         __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ | ||||
|         __catchResult.captureResult( messageType ); \ | ||||
|         INTERNAL_CATCH_REACT( __catchResult ) \ | ||||
|         Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ | ||||
|         catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str().c_str() ); \ | ||||
|         INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CATCH_INFO( macroName, log ) \ | ||||
|     Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; | ||||
|  | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ | ||||
|         INTERNAL_CATCH_TRY { \ | ||||
|             __catchResult.captureMatch( arg, matcher, #matcher ); \ | ||||
|         } INTERNAL_CATCH_CATCH( __catchResult, resultDisposition ) \ | ||||
|         INTERNAL_CATCH_REACT( __catchResult ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // Although this is matcher-based, it can be used with just a string | ||||
| #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #matcher, resultDisposition); \ | ||||
|         if( __catchResult.allowThrows() ) \ | ||||
|         Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #matcher, resultDisposition ); \ | ||||
|         if( catchAssertionHandler.allowThrows() ) \ | ||||
|             try { \ | ||||
|                 static_cast<void>(__VA_ARGS__); \ | ||||
|                 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ | ||||
|                 catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ | ||||
|             } \ | ||||
|             catch( ... ) { \ | ||||
|                 __catchResult.captureExpectedException( matcher ); \ | ||||
|                 handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ | ||||
|             } \ | ||||
|         else \ | ||||
|             __catchResult.captureResult( Catch::ResultWas::Ok ); \ | ||||
|         INTERNAL_CATCH_REACT( __catchResult ) \ | ||||
|             catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ | ||||
|         INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
|  | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, expr ) \ | ||||
|     do { \ | ||||
|         Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType ", " #matcher, resultDisposition ); \ | ||||
|         if( __catchResult.allowThrows() ) \ | ||||
|             try { \ | ||||
|                 static_cast<void>(expr); \ | ||||
|                 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ | ||||
|             } \ | ||||
|             catch( exceptionType const& ex ) { \ | ||||
|                 __catchResult.captureMatch( ex, matcher, #matcher ); \ | ||||
|             } \ | ||||
|             catch( ... ) { \ | ||||
|                 __catchResult.useActiveException( resultDisposition ); \ | ||||
|             } \ | ||||
|         else \ | ||||
|             __catchResult.captureResult( Catch::ResultWas::Ok ); \ | ||||
|         INTERNAL_CATCH_REACT( __catchResult ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
|  | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED | ||||
|   | ||||
							
								
								
									
										23
									
								
								include/internal/catch_capture_matchers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								include/internal/catch_capture_matchers.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  *  Created by Phil on 9/8/2017. | ||||
|  *  Copyright 2017 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #include "catch_capture_matchers.h" | ||||
| #include "catch_interfaces_registry_hub.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     using StringMatcher = Matchers::Impl::MatcherBase<std::string>; | ||||
|  | ||||
|     // This is the general overload that takes a any string matcher | ||||
|     // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers | ||||
|     // the Equals matcher (so the header does not mention matchers) | ||||
|     void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString  ) { | ||||
|         MatchExpr<std::string, StringMatcher const&> expr( Catch::translateActiveException(), matcher, matcherString ); | ||||
|         handler.handle( expr ); | ||||
|     } | ||||
|  | ||||
| } // namespace Catch | ||||
							
								
								
									
										87
									
								
								include/internal/catch_capture_matchers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								include/internal/catch_capture_matchers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
|  *  Created by Phil on 9/8/2017 | ||||
|  *  Copyright 2017 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED | ||||
|  | ||||
| #include "catch_capture.hpp" | ||||
| #include "catch_matchers.hpp" | ||||
| #include "catch_matchers_string.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     template<typename ArgT, typename MatcherT> | ||||
|     class MatchExpr : public ITransientExpression { | ||||
|         ArgT const& m_arg; | ||||
|         MatcherT m_matcher; | ||||
|         StringRef m_matcherString; | ||||
|         bool m_result; | ||||
|     public: | ||||
|         MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) | ||||
|         :   m_arg( arg ), | ||||
|             m_matcher( matcher ), | ||||
|             m_matcherString( matcherString ), | ||||
|             m_result( matcher.match( arg ) ) | ||||
|         {} | ||||
|  | ||||
|         auto isBinaryExpression() const -> bool  override { return true; } | ||||
|         auto getResult() const -> bool override { return m_result; } | ||||
|  | ||||
|         void streamReconstructedExpression( std::ostream &os ) const override { | ||||
|             auto matcherAsString = m_matcher.toString(); | ||||
|             os << Catch::Detail::stringify( m_arg ) << ' '; | ||||
|             if( matcherAsString == Detail::unprintableString ) | ||||
|                 os << m_matcherString.c_str(); | ||||
|             else | ||||
|                 os << matcherAsString; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     using StringMatcher = Matchers::Impl::MatcherBase<std::string>; | ||||
|  | ||||
|     void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString  ); | ||||
|  | ||||
|     template<typename ArgT, typename MatcherT> | ||||
|     auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString  ) -> MatchExpr<ArgT, MatcherT> { | ||||
|         return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString ); | ||||
|     } | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ | ||||
|     do { \ | ||||
|         Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ | ||||
|         INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ | ||||
|             catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ | ||||
|         } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ | ||||
|         INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
|  | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ | ||||
|     do { \ | ||||
|         Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #exceptionType ", " #matcher, resultDisposition ); \ | ||||
|         if( catchAssertionHandler.allowThrows() ) \ | ||||
|             try { \ | ||||
|                 static_cast<void>(__VA_ARGS__ ); \ | ||||
|                 catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ | ||||
|             } \ | ||||
|             catch( exceptionType const& ex ) { \ | ||||
|                 catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ | ||||
|             } \ | ||||
|             catch( ... ) { \ | ||||
|                 catchAssertionHandler.useActiveException(); \ | ||||
|             } \ | ||||
|         else \ | ||||
|             catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ | ||||
|         INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | ||||
|     } while( Catch::alwaysFalse() ) | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED | ||||
| @@ -15,7 +15,6 @@ | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     SourceLineInfo::SourceLineInfo() noexcept : file(""), line( 0 ){} | ||||
|     SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept | ||||
|     :   file( _file ), | ||||
|         line( _line ) | ||||
|   | ||||
| @@ -47,10 +47,10 @@ namespace Catch { | ||||
|  | ||||
|     struct SourceLineInfo { | ||||
|  | ||||
|         SourceLineInfo() noexcept; | ||||
|         SourceLineInfo() = delete; | ||||
|         SourceLineInfo( char const* _file, std::size_t _line ) noexcept; | ||||
|  | ||||
|         SourceLineInfo(SourceLineInfo const& other)          = default; | ||||
|         SourceLineInfo( SourceLineInfo const& other )        = default; | ||||
|         SourceLineInfo( SourceLineInfo && )                  = default; | ||||
|         SourceLineInfo& operator = ( SourceLineInfo const& ) = default; | ||||
|         SourceLineInfo& operator = ( SourceLineInfo && )     = default; | ||||
|   | ||||
							
								
								
									
										22
									
								
								include/internal/catch_decomposer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								include/internal/catch_decomposer.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| /* | ||||
|  *  Created by Phil Nash on 8/8/2017. | ||||
|  *  Copyright 2017 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
|  | ||||
| #include "catch_decomposer.h" | ||||
| #include "catch_config.hpp" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ) { | ||||
|         if( lhs.size() + rhs.size() < 40 && | ||||
|                 lhs.find('\n') == std::string::npos && | ||||
|                 rhs.find('\n') == std::string::npos ) | ||||
|             os << lhs << " " << op << " " << rhs; | ||||
|         else | ||||
|             os << lhs << "\n" << op << "\n" << rhs; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										164
									
								
								include/internal/catch_decomposer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								include/internal/catch_decomposer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| /* | ||||
|  *  Created by Phil Nash on 8/8/2017. | ||||
|  *  Copyright 2017 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED | ||||
|  | ||||
| #include "catch_tostring.h" | ||||
| #include "catch_stringref.h" | ||||
|  | ||||
| #include <ostream> | ||||
|  | ||||
| #ifdef _MSC_VER | ||||
| #pragma warning(push) | ||||
| #pragma warning(disable:4389) // '==' : signed/unsigned mismatch | ||||
| #pragma warning(disable:4018) // more "signed/unsigned mismatch" | ||||
| #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) | ||||
| #endif | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct ITransientExpression { | ||||
|         virtual auto isBinaryExpression() const -> bool = 0; | ||||
|         virtual auto getResult() const -> bool = 0; | ||||
|         virtual void streamReconstructedExpression( std::ostream &os ) const = 0; | ||||
|  | ||||
|         // We don't actually need a virtual destructore, but many static analysers | ||||
|         // complain if it's not here :-( | ||||
|         virtual ~ITransientExpression() = default; | ||||
|     }; | ||||
|  | ||||
|     void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ); | ||||
|  | ||||
|     template<typename LhsT, typename RhsT> | ||||
|     class BinaryExpr  : public ITransientExpression { | ||||
|         bool m_result; | ||||
|         LhsT m_lhs; | ||||
|         std::string m_op; | ||||
|         RhsT m_rhs; | ||||
|  | ||||
|         auto isBinaryExpression() const -> bool override { return true; } | ||||
|         auto getResult() const -> bool override { return m_result; } | ||||
|  | ||||
|         void streamReconstructedExpression( std::ostream &os ) const override { | ||||
|             formatReconstructedExpression | ||||
|                     ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); | ||||
|         } | ||||
|  | ||||
|     public: | ||||
|         BinaryExpr( bool comparisionResult, LhsT lhs, StringRef op, RhsT rhs ) | ||||
|         :   m_result( comparisionResult ), | ||||
|             m_lhs( lhs ), | ||||
|             m_op( op.c_str() ), | ||||
|             m_rhs( rhs ) | ||||
|         {} | ||||
|     }; | ||||
|  | ||||
|     template<typename LhsT> | ||||
|     class UnaryExpr : public ITransientExpression { | ||||
|         LhsT m_lhs; | ||||
|  | ||||
|         auto isBinaryExpression() const -> bool override { return false; } | ||||
|         auto getResult() const -> bool override { return m_lhs ? true : false; } | ||||
|  | ||||
|         void streamReconstructedExpression( std::ostream &os ) const override { | ||||
|             os << Catch::Detail::stringify( m_lhs ); | ||||
|         } | ||||
|  | ||||
|     public: | ||||
|         UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) | ||||
|     template<typename LhsT, typename RhsT> | ||||
|     auto compareEqual( LhsT lhs, RhsT&& rhs ) -> bool { return lhs == rhs; }; | ||||
|     template<typename T> | ||||
|     auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }; | ||||
|     template<typename T> | ||||
|     auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }; | ||||
|  | ||||
|     template<typename LhsT, typename RhsT> | ||||
|     auto compareNotEqual( LhsT lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; | ||||
|     template<typename T> | ||||
|     auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }; | ||||
|     template<typename T> | ||||
|     auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }; | ||||
|  | ||||
|  | ||||
|     template<typename LhsT> | ||||
|     class ExprLhs { | ||||
|         LhsT m_lhs; | ||||
|     public: | ||||
|         ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} | ||||
|  | ||||
|         template<typename RhsT> | ||||
|         auto operator == ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const { | ||||
|             return BinaryExpr<LhsT, RhsT&>( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); | ||||
|         } | ||||
|         auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { | ||||
|             return BinaryExpr<LhsT, bool>( m_lhs == rhs, m_lhs, "==", rhs ); | ||||
|         } | ||||
|  | ||||
|         template<typename RhsT> | ||||
|         auto operator != ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const { | ||||
|             return BinaryExpr<LhsT, RhsT&>( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); | ||||
|         } | ||||
|         auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { | ||||
|             return BinaryExpr<LhsT, bool>( m_lhs != rhs, m_lhs, "!=", rhs ); | ||||
|         } | ||||
|  | ||||
|         template<typename RhsT> | ||||
|         auto operator > ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const { | ||||
|             return BinaryExpr<LhsT, RhsT&>( m_lhs > rhs, m_lhs, ">", rhs ); | ||||
|         } | ||||
|         template<typename RhsT> | ||||
|         auto operator < ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const { | ||||
|             return BinaryExpr<LhsT, RhsT&>( m_lhs < rhs, m_lhs, "<", rhs ); | ||||
|         } | ||||
|         template<typename RhsT> | ||||
|         auto operator >= ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const { | ||||
|             return BinaryExpr<LhsT, RhsT&>( m_lhs >= rhs, m_lhs, ">=", rhs ); | ||||
|         } | ||||
|         template<typename RhsT> | ||||
|         auto operator <= ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const { | ||||
|             return BinaryExpr<LhsT, RhsT&>( m_lhs <= rhs, m_lhs, "<=", rhs ); | ||||
|         } | ||||
|  | ||||
|         auto makeUnaryExpr() const -> UnaryExpr<LhsT> { | ||||
|             return UnaryExpr<LhsT>( m_lhs ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     void handleExpression( ITransientExpression const& expr ); | ||||
|  | ||||
|     template<typename T> | ||||
|     void handleExpression( ExprLhs<T> const& expr ) { | ||||
|         handleExpression( expr.makeUnaryExpr() ); | ||||
|     } | ||||
|  | ||||
|     struct Decomposer { | ||||
|         template<typename T> | ||||
|         auto operator <= ( T& lhs ) -> ExprLhs<T&> { | ||||
|             return ExprLhs<T&>( lhs ); | ||||
|         } | ||||
|         template<typename T> | ||||
|         auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { | ||||
|             return ExprLhs<T const&>( lhs ); | ||||
|         } | ||||
|         auto operator <=( bool value ) -> ExprLhs<bool> { | ||||
|             return ExprLhs<bool>( value ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| } // end namespace Catch | ||||
|  | ||||
| #ifdef _MSC_VER | ||||
| #pragma warning(pop) | ||||
| #endif | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED | ||||
| @@ -1,38 +0,0 @@ | ||||
| /* | ||||
|  *  Created by Martin on 01/08/2017. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
|  | ||||
| #include "catch_evaluate.hpp" | ||||
|  | ||||
| #include "catch_enforce.h" | ||||
|  | ||||
| namespace Catch { | ||||
| namespace Internal { | ||||
|  | ||||
|     const char* operatorName(Operator op) { | ||||
|         switch (op) { | ||||
|             case IsEqualTo: | ||||
|                 return "=="; | ||||
|             case IsNotEqualTo: | ||||
|                 return "!="; | ||||
|             case IsLessThan: | ||||
|                 return "<"; | ||||
|             case IsGreaterThan: | ||||
|                 return ">"; | ||||
|             case IsLessThanOrEqualTo: | ||||
|                 return "<="; | ||||
|             case IsGreaterThanOrEqualTo: | ||||
|                 return ">="; | ||||
|             default: | ||||
|                 CATCH_ERROR("Attempting to translate unknown operator!"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // nullptr_t support based on pull request #154 from Konstantin Baumann | ||||
|     std::nullptr_t opCast(std::nullptr_t) { return nullptr; } | ||||
|  | ||||
| } // end of namespace Internal | ||||
| } // end of namespace Catch | ||||
| @@ -1,109 +0,0 @@ | ||||
| /* | ||||
|  *  Created by Phil on 04/03/2011. | ||||
|  *  Copyright 2011 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED | ||||
|  | ||||
| #ifdef _MSC_VER | ||||
| #pragma warning(push) | ||||
| #pragma warning(disable:4389) // '==' : signed/unsigned mismatch | ||||
| #pragma warning(disable:4018) // more "signed/unsigned mismatch" | ||||
| #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) | ||||
| #endif | ||||
|  | ||||
| #include <cstddef> | ||||
|  | ||||
| namespace Catch { | ||||
| namespace Internal { | ||||
|  | ||||
|     enum Operator { | ||||
|         IsEqualTo, | ||||
|         IsNotEqualTo, | ||||
|         IsLessThan, | ||||
|         IsGreaterThan, | ||||
|         IsLessThanOrEqualTo, | ||||
|         IsGreaterThanOrEqualTo | ||||
|     }; | ||||
|  | ||||
|     const char* operatorName(Operator op); | ||||
|  | ||||
|     template<typename T> | ||||
|     T& removeConst(T const &t) { return const_cast<T&>(t); } | ||||
|  | ||||
|  | ||||
|     // So the compare overloads can be operator agnostic we convey the operator as a template | ||||
|     // enum, which is used to specialise an Evaluator for doing the comparison. | ||||
|     template<Operator Op> | ||||
|     struct Evaluator{}; | ||||
|  | ||||
|     template<> | ||||
|     struct Evaluator<IsEqualTo> { | ||||
|         template<typename T1, typename T2> | ||||
|         static bool evaluate( T1 const& lhs, T2 const& rhs) { | ||||
|             return bool(removeConst(lhs) == removeConst(rhs) ); | ||||
|         } | ||||
|         template<typename T> | ||||
|         static bool evaluate( int lhs, T* rhs) { | ||||
|             return reinterpret_cast<void const*>( lhs ) ==  rhs; | ||||
|         } | ||||
|         template<typename T> | ||||
|         static bool evaluate( T* lhs, int rhs) { | ||||
|             return lhs == reinterpret_cast<void const*>( rhs ); | ||||
|         } | ||||
|     }; | ||||
|     template<> | ||||
|     struct Evaluator<IsNotEqualTo> { | ||||
|         template<typename T1, typename T2> | ||||
|         static bool evaluate( T1 const& lhs, T2 const& rhs ) { | ||||
|             return bool(removeConst(lhs) != removeConst(rhs) ); | ||||
|         } | ||||
|         template<typename T> | ||||
|         static bool evaluate( int lhs, T* rhs) { | ||||
|             return reinterpret_cast<void const*>( lhs ) !=  rhs; | ||||
|         } | ||||
|         template<typename T> | ||||
|         static bool evaluate( T* lhs, int rhs) { | ||||
|             return lhs != reinterpret_cast<void const*>( rhs ); | ||||
|         } | ||||
|     }; | ||||
|     template<> | ||||
|     struct Evaluator<IsLessThan> { | ||||
|         template<typename T1, typename T2> | ||||
|         static bool evaluate( T1 const& lhs, T2 const& rhs ) { | ||||
|             return bool(removeConst(lhs) < removeConst(rhs) ); | ||||
|         } | ||||
|     }; | ||||
|     template<> | ||||
|     struct Evaluator<IsGreaterThan> { | ||||
|         template<typename T1, typename T2> | ||||
|         static bool evaluate( T1 const& lhs, T2 const& rhs ) { | ||||
|             return bool(removeConst(lhs) > removeConst(rhs) ); | ||||
|         } | ||||
|     }; | ||||
|     template<> | ||||
|     struct Evaluator<IsGreaterThanOrEqualTo> { | ||||
|         template<typename T1, typename T2> | ||||
|         static bool evaluate( T1 const& lhs, T2 const& rhs ) { | ||||
|             return bool(removeConst(lhs) >= removeConst(rhs) ); | ||||
|         } | ||||
|     }; | ||||
|     template<> | ||||
|     struct Evaluator<IsLessThanOrEqualTo> { | ||||
|         template<typename T1, typename T2> | ||||
|         static bool evaluate( T1 const& lhs, T2 const& rhs ) { | ||||
|             return bool(removeConst(lhs) <= removeConst(rhs) ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| } // end of namespace Internal | ||||
| } // end of namespace Catch | ||||
|  | ||||
| #ifdef _MSC_VER | ||||
| #pragma warning(pop) | ||||
| #endif | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED | ||||
| @@ -6,8 +6,8 @@ | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
|  | ||||
| #include "catch_assertionhandler.h" | ||||
| #include "catch_exception_translator_registry.h" | ||||
| #include "catch_result_builder.h" | ||||
|  | ||||
| #ifdef __OBJC__ | ||||
| #import "Foundation/Foundation.h" | ||||
|   | ||||
| @@ -1,176 +0,0 @@ | ||||
| /* | ||||
|  *  Created by Phil on 11/5/2012. | ||||
|  *  Copyright 2012 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED | ||||
|  | ||||
| #include "catch_result_builder.h" | ||||
| #include "catch_evaluate.hpp" | ||||
| #include "catch_tostring.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
| 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 ) {} | ||||
|  | ||||
|     ExpressionLhs( ExpressionLhs const& ) = default; | ||||
|     ExpressionLhs& operator = ( const ExpressionLhs& ) = delete; | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     BinaryExpression<T, Internal::IsEqualTo, RhsT const&> | ||||
|     operator == ( RhsT const& rhs ) { | ||||
|         return captureExpression<Internal::IsEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&> | ||||
|     operator != ( RhsT const& rhs ) { | ||||
|         return captureExpression<Internal::IsNotEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     BinaryExpression<T, Internal::IsLessThan, RhsT const&> | ||||
|     operator < ( RhsT const& rhs ) { | ||||
|         return captureExpression<Internal::IsLessThan>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     BinaryExpression<T, Internal::IsGreaterThan, RhsT const&> | ||||
|     operator > ( RhsT const& rhs ) { | ||||
|         return captureExpression<Internal::IsGreaterThan>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&> | ||||
|     operator <= ( RhsT const& rhs ) { | ||||
|         return captureExpression<Internal::IsLessThanOrEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     template<typename RhsT> | ||||
|     BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&> | ||||
|     operator >= ( RhsT const& rhs ) { | ||||
|         return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) { | ||||
|         return captureExpression<Internal::IsEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) { | ||||
|         return captureExpression<Internal::IsNotEqualTo>( rhs ); | ||||
|     } | ||||
|  | ||||
|     void endExpression() { | ||||
|         m_truthy = m_lhs ? true : false; | ||||
|         m_rb | ||||
|             .setResultType( m_truthy ) | ||||
|             .endExpression( *this ); | ||||
|     } | ||||
|  | ||||
|     void reconstructExpression( std::string& dest ) const override { | ||||
|         dest = ::Catch::Detail::stringify( m_lhs ); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     template<Internal::Operator Op, typename RhsT> | ||||
|     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 = false; | ||||
| }; | ||||
|  | ||||
| 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 ) {} | ||||
|  | ||||
|     BinaryExpression( BinaryExpression const& ) = default; | ||||
|     BinaryExpression& operator = ( BinaryExpression const& ) = delete; | ||||
|  | ||||
|     void endExpression() const { | ||||
|         m_rb | ||||
|             .setResultType(  Internal::Evaluator<Op>::evaluate( m_lhs, m_rhs ) ) | ||||
|             .endExpression( *this ); | ||||
|     } | ||||
|  | ||||
|     bool isBinaryExpression() const override { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void reconstructExpression( std::string& dest ) const override { | ||||
|         std::string lhs = ::Catch::Detail::stringify( m_lhs ); | ||||
|         std::string rhs = ::Catch::Detail::stringify( 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::operatorName(Op); | ||||
|         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 ) {} | ||||
|  | ||||
|     bool isBinaryExpression() const override { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void reconstructExpression( std::string& dest ) const override { | ||||
|         std::string matcherAsString = m_matcher.toString(); | ||||
|         dest = ::Catch::Detail::stringify( 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 | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED | ||||
| @@ -9,9 +9,6 @@ | ||||
| #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED | ||||
|  | ||||
| #include <string> | ||||
| #include "catch_result_type.h" | ||||
| #include "catch_common.h" | ||||
| #include "catch_interfaces_reporter.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
| @@ -23,6 +20,8 @@ namespace Catch { | ||||
|     struct MessageInfo; | ||||
|     class ScopedMessageBuilder; | ||||
|     struct Counts; | ||||
|     struct BenchmarkInfo; | ||||
|     struct BenchmarkStats; | ||||
|  | ||||
|     struct IResultCapture { | ||||
|  | ||||
|   | ||||
| @@ -37,10 +37,12 @@ namespace Catch { | ||||
|         infoMessages( _infoMessages ), | ||||
|         totals( _totals ) | ||||
|     { | ||||
|         assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; | ||||
|  | ||||
|         if( assertionResult.hasMessage() ) { | ||||
|             // Copy message into messages list. | ||||
|             // !TBD This should have been done earlier, somewhere | ||||
|             MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); | ||||
|             MessageBuilder builder( assertionResult.getTestMacroName().c_str(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); | ||||
|             builder << assertionResult.getMessage(); | ||||
|             builder.m_info.message = builder.m_stream.str(); | ||||
|  | ||||
|   | ||||
| @@ -5,8 +5,6 @@ | ||||
|  * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
|  | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
|  | ||||
| #include "catch_matchers.hpp" | ||||
|  | ||||
| namespace Catch { | ||||
| @@ -26,5 +24,3 @@ using namespace Matchers; | ||||
| using Matchers::Impl::MatcherBase; | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
| @@ -8,8 +8,6 @@ | ||||
| #ifndef TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED | ||||
|  | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
|  | ||||
| #include "catch_common.h" | ||||
|  | ||||
| #include <string> | ||||
| @@ -182,6 +180,4 @@ using Matchers::Impl::MatcherBase; | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED | ||||
|   | ||||
| @@ -6,8 +6,6 @@ | ||||
|  * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
|  | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
|  | ||||
| #include "catch_matchers_string.h" | ||||
| #include "catch_string_manip.h" | ||||
|  | ||||
| @@ -94,5 +92,3 @@ namespace Matchers { | ||||
|  | ||||
| } // namespace Matchers | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| #ifndef TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED | ||||
|  | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
|  | ||||
| #include "catch_matchers.hpp" | ||||
|  | ||||
| #include <string> | ||||
| @@ -68,6 +66,4 @@ namespace Matchers { | ||||
| } // namespace Matchers | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED | ||||
|   | ||||
| @@ -8,9 +8,6 @@ | ||||
| #ifndef TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED | ||||
|  | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
|  | ||||
|  | ||||
| #include "catch_matchers.hpp" | ||||
|  | ||||
| namespace Catch { | ||||
| @@ -115,6 +112,4 @@ namespace Matchers { | ||||
| } // namespace Matchers | ||||
| } // namespace Catch | ||||
|  | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED | ||||
|   | ||||
| @@ -32,7 +32,19 @@ namespace Catch { | ||||
|         static unsigned int globalCount; | ||||
|     }; | ||||
|  | ||||
|     struct MessageBuilder { | ||||
|     struct MessageStream { | ||||
|  | ||||
|         template<typename T> | ||||
|         MessageStream& operator << ( T const& value ) { | ||||
|             m_stream << value; | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         // !TBD reuse a global/ thread-local stream | ||||
|         std::ostringstream m_stream; | ||||
|     }; | ||||
|  | ||||
|     struct MessageBuilder : MessageStream { | ||||
|         MessageBuilder( std::string const& macroName, | ||||
|                         SourceLineInfo const& lineInfo, | ||||
|                         ResultWas::OfType type ); | ||||
| @@ -44,7 +56,6 @@ namespace Catch { | ||||
|         } | ||||
|  | ||||
|         MessageInfo m_info; | ||||
|         std::ostringstream m_stream; | ||||
|     }; | ||||
|  | ||||
|     class ScopedMessage { | ||||
|   | ||||
| @@ -11,8 +11,7 @@ | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) | ||||
|     :   m_lineInfo( lineInfo ) { | ||||
|     NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) { | ||||
|         std::ostringstream oss; | ||||
|         oss << lineInfo << ": function "; | ||||
|         oss << "not implemented"; | ||||
|   | ||||
| @@ -25,7 +25,6 @@ namespace Catch { | ||||
|  | ||||
|     private: | ||||
|         std::string m_what; | ||||
|         SourceLineInfo m_lineInfo; | ||||
|     }; | ||||
|  | ||||
| } // end namespace Catch | ||||
|   | ||||
| @@ -1,193 +0,0 @@ | ||||
| /* | ||||
|  *  Created by Phil on 28/5/2014. | ||||
|  *  Copyright 2014 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
|  | ||||
| #include "catch_result_builder.h" | ||||
| #include "catch_context.h" | ||||
| #include "catch_interfaces_config.h" | ||||
| #include "catch_interfaces_runner.h" | ||||
| #include "catch_interfaces_capture.h" | ||||
| #include "catch_interfaces_registry_hub.h" | ||||
| #include "catch_matchers_string.h" | ||||
| #include "catch_wildcard_pattern.hpp" | ||||
| #include "catch_debugger.h" | ||||
|  | ||||
| #include <cassert> | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     CopyableStream::CopyableStream( CopyableStream const& other ) { | ||||
|         oss << other.oss.str(); | ||||
|     } | ||||
|     CopyableStream& CopyableStream::operator=( CopyableStream const& other ) { | ||||
|         oss.str(std::string()); | ||||
|         oss << other.oss.str(); | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     ResultBuilder::ResultBuilder(   char const* macroName, | ||||
|                                     SourceLineInfo const& lineInfo, | ||||
|                                     char const* capturedExpression, | ||||
|                                     ResultDisposition::Flags resultDisposition ) | ||||
|     :   m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition) | ||||
|     { | ||||
|         getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); | ||||
|     } | ||||
|  | ||||
|     ResultBuilder::~ResultBuilder() { | ||||
| #if defined(CATCH_CONFIG_FAST_COMPILE) | ||||
|         if ( m_guardException ) { | ||||
|             stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; | ||||
|             captureResult( ResultWas::ThrewException ); | ||||
|             getCurrentContext().getResultCapture()->exceptionEarlyReported(); | ||||
|         } | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { | ||||
|         m_data.resultType = result; | ||||
|         return *this; | ||||
|     } | ||||
|     ResultBuilder& ResultBuilder::setResultType( bool result ) { | ||||
|         m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::endExpression( DecomposedExpression const& expr ) { | ||||
|         // Flip bool results if FalseTest flag is set | ||||
|         if( isFalseTest( m_assertionInfo.resultDisposition ) ) { | ||||
|             m_data.negate( expr.isBinaryExpression() ); | ||||
|         } | ||||
|  | ||||
|         getResultCapture().assertionRun(); | ||||
|  | ||||
|         if(getCurrentContext().getConfig()->includeSuccessfulResults() | ||||
|             || m_data.resultType != ResultWas::Ok) { | ||||
|             AssertionResult result = build( expr ); | ||||
|             handleResult( result ); | ||||
|         } | ||||
|         else | ||||
|             getResultCapture().assertionPassed(); | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { | ||||
|         m_assertionInfo.resultDisposition = resultDisposition; | ||||
|         stream().oss << Catch::translateActiveException(); | ||||
|         captureResult( ResultWas::ThrewException ); | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::captureResult( ResultWas::OfType resultType ) { | ||||
|         setResultType( resultType ); | ||||
|         captureExpression(); | ||||
|     } | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
|     void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { | ||||
|         if( expectedMessage.empty() ) | ||||
|             captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() ); | ||||
|         else | ||||
|             captureExpectedException( Matchers::Equals( expectedMessage ) ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) { | ||||
|  | ||||
|         assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); | ||||
|         AssertionResultData data = m_data; | ||||
|         data.resultType = ResultWas::Ok; | ||||
|         data.reconstructedExpression = m_assertionInfo.capturedExpression; | ||||
|  | ||||
|         std::string actualMessage = Catch::translateActiveException(); | ||||
|         if( !matcher.match( actualMessage ) ) { | ||||
|             data.resultType = ResultWas::ExpressionFailed; | ||||
|             data.reconstructedExpression = std::move(actualMessage); | ||||
|         } | ||||
|         AssertionResult result( m_assertionInfo, data ); | ||||
|         handleResult( result ); | ||||
|     } | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
|     void ResultBuilder::captureExpression() { | ||||
|         AssertionResult result = build(); | ||||
|         handleResult( result ); | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::handleResult( AssertionResult const& result ) | ||||
|     { | ||||
|         getResultCapture().assertionEnded( result ); | ||||
|  | ||||
|         if( !result.isOk() ) { | ||||
|             if( getCurrentContext().getConfig()->shouldDebugBreak() ) | ||||
|                 m_shouldDebugBreak = true; | ||||
|             if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) | ||||
|                 m_shouldThrow = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::react() { | ||||
| #if defined(CATCH_CONFIG_FAST_COMPILE) | ||||
|         if (m_shouldDebugBreak) { | ||||
|             /////////////////////////////////////////////////////////////////// | ||||
|             // To inspect the state during test, you need to go one level up the callstack | ||||
|             // To go back to the test and change execution, jump over the throw statement | ||||
|             /////////////////////////////////////////////////////////////////// | ||||
|             CATCH_BREAK_INTO_DEBUGGER(); | ||||
|         } | ||||
| #endif | ||||
|         if( m_shouldThrow ) | ||||
|             throw Catch::TestFailureException(); | ||||
|     } | ||||
|  | ||||
|     bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } | ||||
|     bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } | ||||
|  | ||||
|     AssertionResult ResultBuilder::build() const | ||||
|     { | ||||
|         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; | ||||
|  | ||||
|         if(m_usedStream) | ||||
|             data.message = s_stream().oss.str(); | ||||
|         data.decomposedExpression = &expr; // for lazy reconstruction | ||||
|         return AssertionResult( m_assertionInfo, data ); | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::reconstructExpression( std::string& dest ) const { | ||||
|         dest = m_assertionInfo.capturedExpression; | ||||
|     } | ||||
|  | ||||
|     void ResultBuilder::setExceptionGuard() { | ||||
|         m_guardException = true; | ||||
|     } | ||||
|     void ResultBuilder::unsetExceptionGuard() { | ||||
|         m_guardException = false; | ||||
|     } | ||||
|  | ||||
|     CopyableStream& ResultBuilder::stream() { | ||||
|         if( !m_usedStream ) { | ||||
|             m_usedStream = true; | ||||
|             s_stream().oss.str(""); | ||||
|         } | ||||
|         return s_stream(); | ||||
|     } | ||||
|  | ||||
|     CopyableStream& ResultBuilder::s_stream() { | ||||
|         static CopyableStream s; | ||||
|         return s; | ||||
|     } | ||||
|  | ||||
|  | ||||
| } // end namespace Catch | ||||
| @@ -1,118 +0,0 @@ | ||||
| /* | ||||
|  *  Created by Phil on 28/5/2014. | ||||
|  *  Copyright 2014 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
| #ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED | ||||
|  | ||||
| #include "catch_result_type.h" | ||||
| #include "catch_assertionresult.h" | ||||
| #include "catch_common.h" | ||||
| #include "catch_matchers.hpp" | ||||
|  | ||||
| #include <sstream> | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct TestFailureException{}; | ||||
|  | ||||
|     template<typename T> class ExpressionLhs; | ||||
|  | ||||
|     struct CopyableStream { | ||||
|         CopyableStream() = default; | ||||
|         CopyableStream( CopyableStream const& other ); | ||||
|         CopyableStream& operator=( CopyableStream const& other ); | ||||
|  | ||||
|         std::ostringstream oss; | ||||
|     }; | ||||
|  | ||||
|     class ResultBuilder : public DecomposedExpression { | ||||
|     public: | ||||
|         ResultBuilder(  char const* macroName, | ||||
|                         SourceLineInfo const& lineInfo, | ||||
|                         char const* capturedExpression, | ||||
|                         ResultDisposition::Flags resultDisposition); | ||||
|         ~ResultBuilder(); | ||||
|  | ||||
|         template<typename T> | ||||
|         ExpressionLhs<T const&> operator <= ( T const& operand ); | ||||
|         ExpressionLhs<bool> operator <= ( bool value ); | ||||
|  | ||||
|         template<typename T> | ||||
|         ResultBuilder& operator << ( T const& value ) { | ||||
|             stream().oss << value; | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         ResultBuilder& setResultType( ResultWas::OfType result ); | ||||
|         ResultBuilder& setResultType( bool result ); | ||||
|  | ||||
|         void endExpression( DecomposedExpression const& expr ); | ||||
|  | ||||
|         void reconstructExpression( std::string& dest ) const override; | ||||
|  | ||||
|         AssertionResult build() const; | ||||
|         AssertionResult build( DecomposedExpression const& expr ) const; | ||||
|  | ||||
|         void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); | ||||
|         void captureResult( ResultWas::OfType resultType ); | ||||
|         void captureExpression(); | ||||
| #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | ||||
|         void captureExpectedException( std::string const& expectedMessage ); | ||||
|         void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ); | ||||
| #endif // CATCH_CONFIG_DISABLE_MATCHERS | ||||
|         void handleResult( AssertionResult const& result ); | ||||
|         void react(); | ||||
|         bool shouldDebugBreak() const; | ||||
|         bool allowThrows() const; | ||||
|  | ||||
|         template<typename ArgT, typename MatcherT> | ||||
|         void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); | ||||
|  | ||||
|         void setExceptionGuard(); | ||||
|         void unsetExceptionGuard(); | ||||
|  | ||||
|     private: | ||||
|         AssertionInfo m_assertionInfo; | ||||
|         AssertionResultData m_data; | ||||
|  | ||||
|         CopyableStream& stream(); | ||||
|         static CopyableStream& s_stream(); | ||||
|  | ||||
|         bool m_shouldDebugBreak = false; | ||||
|         bool m_shouldThrow = false; | ||||
|         bool m_guardException = false; | ||||
|         bool m_usedStream = false; | ||||
|     }; | ||||
|  | ||||
| } // namespace Catch | ||||
|  | ||||
| // Include after due to circular dependency: | ||||
| #include "catch_expression_lhs.hpp" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     template<typename T> | ||||
|     ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) { | ||||
|         return ExpressionLhs<T const&>( *this, operand ); | ||||
|     } | ||||
|  | ||||
|     inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) { | ||||
|         return ExpressionLhs<bool>( *this, value ); | ||||
|     } | ||||
|  | ||||
|     template<typename ArgT, typename MatcherT> | ||||
|     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 | ||||
| @@ -32,10 +32,12 @@ namespace Catch { | ||||
|     } | ||||
|  | ||||
|     RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) | ||||
|         : m_runInfo(_config->name()), | ||||
|     :   m_runInfo(_config->name()), | ||||
|         m_context(getCurrentMutableContext()), | ||||
|         m_config(_config), | ||||
|         m_reporter(std::move(reporter)) { | ||||
|         m_reporter(std::move(reporter)), | ||||
|         m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } | ||||
|     { | ||||
|         m_context.setRunner(this); | ||||
|         m_context.setConfig(m_config); | ||||
|         m_context.setResultCapture(this); | ||||
| @@ -118,7 +120,7 @@ namespace Catch { | ||||
|         static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); | ||||
|  | ||||
|         // Reset working state | ||||
|         m_lastAssertionInfo = AssertionInfo("", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition); | ||||
|         m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition }; | ||||
|         m_lastResult = result; | ||||
|     } | ||||
|  | ||||
| @@ -193,7 +195,7 @@ namespace Catch { | ||||
|     } | ||||
|  | ||||
|     const AssertionResult * RunContext::getLastResult() const { | ||||
|         return &m_lastResult; | ||||
|         return &(*m_lastResult); | ||||
|     } | ||||
|  | ||||
|     void RunContext::exceptionEarlyReported() { | ||||
| @@ -203,7 +205,7 @@ namespace Catch { | ||||
|     void RunContext::handleFatalErrorCondition(std::string const & message) { | ||||
|         // Don't rebuild the result -- the stringification itself can cause more fatal errors | ||||
|         // Instead, fake a result data. | ||||
|         AssertionResultData tempResult; | ||||
|         AssertionResultData tempResult( ResultWas::Unknown, { false } ); | ||||
|         tempResult.resultType = ResultWas::FatalErrorCondition; | ||||
|         tempResult.message = message; | ||||
|         AssertionResult result(m_lastAssertionInfo, tempResult); | ||||
| @@ -261,7 +263,7 @@ namespace Catch { | ||||
|         double duration = 0; | ||||
|         m_shouldReportUnexpected = true; | ||||
|         try { | ||||
|             m_lastAssertionInfo = AssertionInfo("TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal); | ||||
|             m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; | ||||
|  | ||||
|             seedRng(*m_config); | ||||
|  | ||||
| @@ -281,7 +283,11 @@ namespace Catch { | ||||
|             // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions | ||||
|             // are reported without translation at the point of origin. | ||||
|             if (m_shouldReportUnexpected) { | ||||
|                 makeUnexpectedResultBuilder().useActiveException(); | ||||
|                 AssertionHandler | ||||
|                     ( m_lastAssertionInfo.macroName, | ||||
|                       m_lastAssertionInfo.lineInfo, | ||||
|                       m_lastAssertionInfo.capturedExpression, | ||||
|                       m_lastAssertionInfo.resultDisposition ).useActiveException(); | ||||
|             } | ||||
|         } | ||||
|         m_testCaseTracker->close(); | ||||
| @@ -307,13 +313,6 @@ namespace Catch { | ||||
|         fatalConditionHandler.reset(); | ||||
|     } | ||||
|  | ||||
|     ResultBuilder RunContext::makeUnexpectedResultBuilder() const { | ||||
|         return ResultBuilder(m_lastAssertionInfo.macroName, | ||||
|                              m_lastAssertionInfo.lineInfo, | ||||
|                              m_lastAssertionInfo.capturedExpression, | ||||
|                              m_lastAssertionInfo.resultDisposition); | ||||
|     } | ||||
|  | ||||
|     void RunContext::handleUnfinishedSections() { | ||||
|         // If sections ended prematurely due to an exception we stored their | ||||
|         // infos here so we can tear them down outside the unwind process. | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
| #include "catch_test_spec.hpp" | ||||
| #include "catch_test_case_tracker.hpp" | ||||
| #include "catch_timer.h" | ||||
| #include "catch_result_builder.h" | ||||
| #include "catch_assertionhandler.h" | ||||
| #include "catch_fatal_condition.h" | ||||
|  | ||||
| #include <string> | ||||
| @@ -117,15 +117,13 @@ namespace Catch { | ||||
|  | ||||
|     private: | ||||
|  | ||||
|         ResultBuilder makeUnexpectedResultBuilder() const; | ||||
|  | ||||
|         void handleUnfinishedSections(); | ||||
|  | ||||
|         TestRunInfo m_runInfo; | ||||
|         IMutableContext& m_context; | ||||
|         TestCase const* m_activeTestCase = nullptr; | ||||
|         ITracker* m_testCaseTracker; | ||||
|         AssertionResult m_lastResult; | ||||
|         Option<AssertionResult> m_lastResult; | ||||
|  | ||||
|         IConfigPtr m_config; | ||||
|         Totals m_totals; | ||||
|   | ||||
| @@ -18,10 +18,7 @@ | ||||
|  | ||||
| namespace Catch { | ||||
|     void prepareExpandedExpression(AssertionResult& result) { | ||||
|         if (result.isOk()) | ||||
|             result.discardDecomposedExpression(); | ||||
|         else | ||||
|             result.expandDecomposedExpression(); | ||||
|         result.getExpandedExpression(); | ||||
|     } | ||||
|  | ||||
|     // Because formatting using c++ streams is stateful, drop down to C is required | ||||
|   | ||||
| @@ -193,14 +193,14 @@ namespace Catch { | ||||
|  | ||||
|         bool assertionEnded(AssertionStats const& assertionStats) override { | ||||
|             assert(!m_sectionStack.empty()); | ||||
|             SectionNode& sectionNode = *m_sectionStack.back(); | ||||
|             sectionNode.assertions.push_back(assertionStats); | ||||
|             // AssertionResult holds a pointer to a temporary DecomposedExpression, | ||||
|             // which getExpandedExpression() calls to build the expression string. | ||||
|             // Our section stack copy of the assertionResult will likely outlive the | ||||
|             // temporary, so it must be expanded or discarded now to avoid calling | ||||
|             // a destroyed object later. | ||||
|             prepareExpandedExpression(sectionNode.assertions.back().assertionResult); | ||||
|             prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) ); | ||||
|             SectionNode& sectionNode = *m_sectionStack.back(); | ||||
|             sectionNode.assertions.push_back(assertionStats); | ||||
|             return true; | ||||
|         } | ||||
|         void sectionEnded(SectionStats const& sectionStats) override { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash