diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index 11305d93..b14f7a23 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -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 @@ -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( 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 diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h index 2f408d25..6ea7d6f6 100644 --- a/include/internal/catch_assertionhandler.h +++ b/include/internal/catch_assertionhandler.h @@ -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 ); diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h index 5b370114..7efa510a 100644 --- a/include/internal/catch_interfaces_capture.h +++ b/include/internal/catch_interfaces_capture.h @@ -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; diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index d334275e..b12f26fa 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -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; diff --git a/include/internal/catch_run_context.h b/include/internal/catch_run_context.h index 22c4d76a..9ef101e4 100644 --- a/include/internal/catch_run_context.h +++ b/include/internal/catch_run_context.h @@ -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();