mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Moved all AssertionHandler logic into RunContext and de-virtualised interface
This makes the assertion handling much less "chatty". AssertionHandler is now just a thin shim over RunContext
This commit is contained in:
		| @@ -15,6 +15,7 @@ | ||||
| #include "catch_debugger.h" | ||||
| #include "catch_interfaces_registry_hub.h" | ||||
| #include "catch_capture_matchers.h" | ||||
| #include "catch_run_context.h" | ||||
|  | ||||
| #include <cassert> | ||||
|  | ||||
| @@ -57,58 +58,19 @@ namespace Catch { | ||||
|             StringRef capturedExpression, | ||||
|             ResultDisposition::Flags resultDisposition ) | ||||
|     :   m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, | ||||
|         m_resultCapture( getResultCapture() ) | ||||
|     { | ||||
|         m_resultCapture.assertionStarting( m_assertionInfo ); | ||||
|     } | ||||
|         m_resultCapture( static_cast<RunContext&>( getResultCapture() ) ) | ||||
|     {} | ||||
|  | ||||
|     AssertionHandler::~AssertionHandler() { | ||||
|         if ( !m_completed ) { | ||||
|             handleMessage(ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"); | ||||
|             m_resultCapture.exceptionEarlyReported(); | ||||
|         } | ||||
|         if ( !m_completed ) | ||||
|             m_resultCapture.handleIncomplete( m_assertionInfo ); | ||||
|     } | ||||
|  | ||||
|     void AssertionHandler::handleExpr( ITransientExpression const& expr ) { | ||||
|  | ||||
|         bool negated = isFalseTest( m_assertionInfo.resultDisposition ); | ||||
|         bool result = expr.getResult() != negated; | ||||
|  | ||||
|         if(result && !getCurrentContext().getConfig()->includeSuccessfulResults()) | ||||
|         { | ||||
|             m_resultCapture.assertionRun(); | ||||
|             m_resultCapture.assertionPassed(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); | ||||
|     } | ||||
|     void AssertionHandler::handle( ResultWas::OfType resultType ) { | ||||
|         handle( resultType, nullptr, false ); | ||||
|         m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); | ||||
|     } | ||||
|     void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const &message) { | ||||
|         AssertionResultData data( resultType, LazyExpression( false ) ); | ||||
|         data.message = message; | ||||
|         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 ) { | ||||
|  | ||||
|         m_resultCapture.assertionRun(); | ||||
|  | ||||
|         AssertionResult assertionResult{ m_assertionInfo, resultData }; | ||||
|         assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; | ||||
|  | ||||
|         m_resultCapture.assertionEnded( assertionResult ); | ||||
|  | ||||
|         if( !assertionResult.isOk() ) { | ||||
|             m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); | ||||
|             m_shouldThrow = | ||||
|                     getCurrentContext().getRunner()->aborting() || | ||||
|                     (m_assertionInfo.resultDisposition & ResultDisposition::Normal); | ||||
|         } | ||||
|         m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); | ||||
|     } | ||||
|  | ||||
|     auto AssertionHandler::allowThrows() const -> bool { | ||||
| @@ -117,7 +79,7 @@ namespace Catch { | ||||
|  | ||||
|     void AssertionHandler::complete() { | ||||
|         setCompleted(); | ||||
|         if( m_shouldDebugBreak ) { | ||||
|         if( m_reaction.shouldDebugBreak ) { | ||||
|  | ||||
|             // If you find your debugger stopping you here then go one level up on the | ||||
|             // call-stack for the code that caused it (typically a failed assertion) | ||||
| @@ -125,7 +87,7 @@ namespace Catch { | ||||
|             // (To go back to the test and change execution, jump over the throw, next) | ||||
|             CATCH_BREAK_INTO_DEBUGGER(); | ||||
|         } | ||||
|         if( m_shouldThrow ) | ||||
|         if( m_reaction.shouldThrow ) | ||||
|             throw Catch::TestFailureException(); | ||||
|     } | ||||
|     void AssertionHandler::setCompleted() { | ||||
| @@ -133,22 +95,22 @@ namespace Catch { | ||||
|     } | ||||
|  | ||||
|     void AssertionHandler::handleUnexpectedInflightException() { | ||||
|         handleMessage(ResultWas::ThrewException, Catch::translateActiveException()); | ||||
|         m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); | ||||
|     } | ||||
|  | ||||
|     void AssertionHandler::handleExceptionThrownAsExpected() { | ||||
|         handle( Catch::ResultWas::Ok ); | ||||
|         m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); | ||||
|     } | ||||
|     void AssertionHandler::handleExceptionNotThrownAsExpected() { | ||||
|         handle( Catch::ResultWas::Ok ); | ||||
|         m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); | ||||
|     } | ||||
|  | ||||
|     void AssertionHandler::handleUnexpectedExceptionNotThrown() { | ||||
|         handle( Catch::ResultWas::DidntThrowException ); | ||||
|         m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); | ||||
|     } | ||||
|  | ||||
|     void AssertionHandler::handleThrowingCallSkipped() { | ||||
|         handle( Catch::ResultWas::Ok ); | ||||
|         m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); | ||||
|     } | ||||
|  | ||||
|     // This is the overload that takes a string and infers the Equals matcher from it | ||||
|   | ||||
| @@ -16,10 +16,12 @@ namespace Catch { | ||||
|     struct TestFailureException{}; | ||||
|     struct AssertionResultData; | ||||
|     struct IResultCapture; | ||||
|     class RunContext; | ||||
|  | ||||
|     class LazyExpression { | ||||
|         friend class AssertionHandler; | ||||
|         friend struct AssertionStats; | ||||
|         friend class RunContext; | ||||
|  | ||||
|         ITransientExpression const* m_transientExpression = nullptr; | ||||
|         bool m_isNegated; | ||||
| @@ -33,12 +35,16 @@ namespace Catch { | ||||
|         friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; | ||||
|     }; | ||||
|  | ||||
|     struct AssertionReaction { | ||||
|         bool shouldDebugBreak = false; | ||||
|         bool shouldThrow = false; | ||||
|     }; | ||||
|  | ||||
|     class AssertionHandler { | ||||
|         AssertionInfo m_assertionInfo; | ||||
|         bool m_shouldDebugBreak = false; | ||||
|         bool m_shouldThrow = false; | ||||
|         AssertionReaction m_reaction; | ||||
|         bool m_completed = false; | ||||
|         IResultCapture& m_resultCapture; | ||||
|         RunContext& m_resultCapture; | ||||
|  | ||||
|     public: | ||||
|         AssertionHandler | ||||
| @@ -67,11 +73,6 @@ namespace Catch { | ||||
|  | ||||
|         // query | ||||
|         auto allowThrows() const -> bool; | ||||
|  | ||||
|     private: | ||||
|         void handle( ResultWas::OfType resultType ); | ||||
|         void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); | ||||
|         void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); | ||||
|     }; | ||||
|  | ||||
|     void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); | ||||
|   | ||||
| @@ -27,8 +27,6 @@ namespace Catch { | ||||
|  | ||||
|         virtual ~IResultCapture(); | ||||
|  | ||||
|         virtual void assertionStarting( AssertionInfo const& info ) = 0; | ||||
|         virtual void assertionEnded( AssertionResult const& result ) = 0; | ||||
|         virtual bool sectionStarted(    SectionInfo const& sectionInfo, | ||||
|                                         Counts& assertions ) = 0; | ||||
|         virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; | ||||
|   | ||||
| @@ -40,7 +40,8 @@ namespace Catch { | ||||
|         m_context(getCurrentMutableContext()), | ||||
|         m_config(_config), | ||||
|         m_reporter(std::move(reporter)), | ||||
|         m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } | ||||
|         m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal }, | ||||
|         m_includeSuccessfulResults( m_config->includeSuccessfulResults() ) | ||||
|     { | ||||
|         m_context.setRunner(this); | ||||
|         m_context.setConfig(m_config); | ||||
| @@ -109,9 +110,6 @@ namespace Catch { | ||||
|         return *m_reporter; | ||||
|     } | ||||
|  | ||||
|     void RunContext::assertionStarting(AssertionInfo const& info) { | ||||
|         m_reporter->assertionStarting( info ); | ||||
|     } | ||||
|     void RunContext::assertionEnded(AssertionResult const & result) { | ||||
|         if (result.getResultType() == ResultWas::Ok) { | ||||
|             m_totals.assertions.passed++; | ||||
| @@ -223,7 +221,7 @@ namespace Catch { | ||||
|         tempResult.message = message; | ||||
|         AssertionResult result(m_lastAssertionInfo, tempResult); | ||||
|  | ||||
|         getResultCapture().assertionEnded(result); | ||||
|         assertionEnded(result); | ||||
|  | ||||
|         handleUnfinishedSections(); | ||||
|  | ||||
| @@ -296,14 +294,9 @@ namespace Catch { | ||||
|         } catch (...) { | ||||
|             // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions | ||||
|             // are reported without translation at the point of origin. | ||||
|             if (m_shouldReportUnexpected) { | ||||
|                 AssertionHandler handler | ||||
|                     ( m_lastAssertionInfo.macroName, | ||||
|                       m_lastAssertionInfo.lineInfo, | ||||
|                       m_lastAssertionInfo.capturedExpression, | ||||
|                       m_lastAssertionInfo.resultDisposition ); | ||||
|                 handler.handleUnexpectedInflightException(); | ||||
|                 handler.setCompleted(); | ||||
|             if( m_shouldReportUnexpected ) { | ||||
|                 AssertionReaction dummyReaction; | ||||
|                 handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); | ||||
|             } | ||||
|         } | ||||
|         m_testCaseTracker->close(); | ||||
| @@ -333,6 +326,119 @@ namespace Catch { | ||||
|         m_unfinishedSections.clear(); | ||||
|     } | ||||
|  | ||||
|     void RunContext::handleExpr( | ||||
|         AssertionInfo const& info, | ||||
|         ITransientExpression const& expr, | ||||
|         AssertionReaction& reaction | ||||
|     ) { | ||||
|         m_reporter->assertionStarting( info ); | ||||
|         assertionRun(); | ||||
|  | ||||
|         bool negated = isFalseTest( info.resultDisposition ); | ||||
|         bool result = expr.getResult() != negated; | ||||
|  | ||||
|         if( result ) { | ||||
|             if (!m_includeSuccessfulResults) { | ||||
|                 assertionRun(); | ||||
|                 assertionPassed(); | ||||
|             } | ||||
|             else { | ||||
|                 reportExpr(info, ResultWas::Ok, &expr, negated); | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); | ||||
|             populateReaction( reaction ); | ||||
|         } | ||||
|     } | ||||
|     void RunContext::reportExpr( | ||||
|             AssertionInfo const &info, | ||||
|             ResultWas::OfType resultType, | ||||
|             ITransientExpression const *expr, | ||||
|             bool negated ) { | ||||
|  | ||||
|         m_lastAssertionInfo = info; | ||||
|         AssertionResultData data( resultType, LazyExpression( negated ) ); | ||||
|  | ||||
|         AssertionResult assertionResult{ info, data }; | ||||
|         assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; | ||||
|  | ||||
|         assertionEnded( assertionResult ); | ||||
|     } | ||||
|  | ||||
|     void RunContext::handleMessage( | ||||
|             AssertionInfo const& info, | ||||
|             ResultWas::OfType resultType, | ||||
|             StringRef const &message, | ||||
|             AssertionReaction& reaction | ||||
|     ) { | ||||
|         m_reporter->assertionStarting( info ); | ||||
|  | ||||
|         m_lastAssertionInfo = info; | ||||
|         assertionRun(); | ||||
|  | ||||
|         AssertionResultData data( resultType, LazyExpression( false ) ); | ||||
|         data.message = message; | ||||
|         AssertionResult assertionResult{ m_lastAssertionInfo, data }; | ||||
|         assertionEnded( assertionResult ); | ||||
|         if( !assertionResult.isOk() ) | ||||
|             populateReaction( reaction ); | ||||
|     } | ||||
|     void RunContext::handleUnexpectedExceptionNotThrown( | ||||
|             AssertionInfo const& info, | ||||
|             AssertionReaction& reaction | ||||
|     ) { | ||||
|         handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); | ||||
|     } | ||||
|  | ||||
|     void RunContext::handleUnexpectedInflightException( | ||||
|             AssertionInfo const& info, | ||||
|             std::string const& message, | ||||
|             AssertionReaction& reaction | ||||
|     ) { | ||||
|         m_lastAssertionInfo = info; | ||||
|         assertionRun(); | ||||
|  | ||||
|         AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); | ||||
|         data.message = message; | ||||
|         AssertionResult assertionResult{ info, data }; | ||||
|         assertionEnded( assertionResult ); | ||||
|         populateReaction( reaction ); | ||||
|     } | ||||
|  | ||||
|     void RunContext::populateReaction( AssertionReaction& reaction ) { | ||||
|         reaction.shouldDebugBreak = m_config->shouldDebugBreak(); | ||||
|         reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); | ||||
|     } | ||||
|  | ||||
|     void RunContext::handleIncomplete( | ||||
|             AssertionInfo const& info | ||||
|     ) { | ||||
|         m_lastAssertionInfo = info; | ||||
|         assertionRun(); | ||||
|  | ||||
|         AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); | ||||
|         data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; | ||||
|         AssertionResult assertionResult{ info, data }; | ||||
|         assertionEnded( assertionResult ); | ||||
|     } | ||||
|     void RunContext::handleNonExpr( | ||||
|             AssertionInfo const &info, | ||||
|             ResultWas::OfType resultType, | ||||
|             AssertionReaction &reaction | ||||
|     ) { | ||||
|         m_lastAssertionInfo = info; | ||||
|         assertionRun(); | ||||
|  | ||||
|         AssertionResultData data( resultType, LazyExpression( false ) ); | ||||
|         AssertionResult assertionResult{ info, data }; | ||||
|         assertionEnded( assertionResult ); | ||||
|  | ||||
|         if( !assertionResult.isOk() ) | ||||
|             populateReaction( reaction ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     IResultCapture& getResultCapture() { | ||||
|         if (auto* capture = getCurrentContext().getResultCapture()) | ||||
|             return *capture; | ||||
|   | ||||
| @@ -75,11 +75,41 @@ namespace Catch { | ||||
|         IConfigPtr config() const; | ||||
|         IStreamingReporter& reporter() const; | ||||
|  | ||||
|     private: // IResultCapture | ||||
|         // Assertion handlers | ||||
|         void handleExpr | ||||
|                 (   AssertionInfo const& info, | ||||
|                     ITransientExpression const& expr, | ||||
|                     AssertionReaction& reaction ); | ||||
|         void handleMessage | ||||
|                 (   AssertionInfo const& info, | ||||
|                     ResultWas::OfType resultType, | ||||
|                     StringRef const &message, | ||||
|                     AssertionReaction& reaction ); | ||||
|         void handleUnexpectedExceptionNotThrown | ||||
|                 (   AssertionInfo const& info, | ||||
|                     AssertionReaction& reaction ); | ||||
|         void handleUnexpectedInflightException | ||||
|                 (   AssertionInfo const& info, | ||||
|                     std::string const& message, | ||||
|                     AssertionReaction& reaction ); | ||||
|         void handleIncomplete | ||||
|                 (   AssertionInfo const& info ); | ||||
|         void handleNonExpr | ||||
|                 (   AssertionInfo const &info, | ||||
|                     ResultWas::OfType resultType, | ||||
|                     AssertionReaction &reaction ); | ||||
|  | ||||
|         void reportExpr | ||||
|                 (AssertionInfo const &info, | ||||
|                  ResultWas::OfType resultType, | ||||
|                  ITransientExpression const *expr, | ||||
|                  bool negated ); | ||||
|  | ||||
|         void assertionStarting(AssertionInfo const& info) override; | ||||
|         void assertionEnded(AssertionResult const& result) override; | ||||
|         void populateReaction( AssertionReaction& reaction ); | ||||
|  | ||||
|     public: // IResultCapture | ||||
|  | ||||
|         void assertionEnded(AssertionResult const& result); // devirt | ||||
|  | ||||
|         bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; | ||||
|         bool testForMissingAssertions(Counts& assertions); | ||||
| @@ -103,9 +133,9 @@ namespace Catch { | ||||
|  | ||||
|         bool lastAssertionPassed() override; | ||||
|  | ||||
|         void assertionPassed() override; | ||||
|         void assertionPassed() override; // devirt | ||||
|  | ||||
|         void assertionRun() override; | ||||
|         void assertionRun() override; // devirt | ||||
|  | ||||
|     public: | ||||
|         // !TBD We need to do this another way! | ||||
| @@ -138,6 +168,7 @@ namespace Catch { | ||||
|         TrackerContext m_trackerContext; | ||||
|         std::size_t m_prevPassed = 0; | ||||
|         bool m_shouldReportUnexpected = true; | ||||
|         bool m_includeSuccessfulResults; | ||||
|     }; | ||||
|  | ||||
|     IResultCapture& getResultCapture(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash