mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-03 21:49:32 +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