mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-04 05:59:32 +01:00 
			
		
		
		
	Split out catch_run_context into cpp and hpp file
This commit is contained in:
		@@ -210,6 +210,7 @@ set(IMPL_SOURCES
 | 
			
		||||
        ${HEADER_DIR}/internal/catch_registry_hub.cpp
 | 
			
		||||
        ${HEADER_DIR}/internal/catch_result_builder.cpp
 | 
			
		||||
        ${HEADER_DIR}/internal/catch_result_type.cpp
 | 
			
		||||
        ${HEADER_DIR}/internal/catch_run_context.cpp
 | 
			
		||||
        ${HEADER_DIR}/internal/catch_section.cpp
 | 
			
		||||
        ${HEADER_DIR}/internal/catch_section_info.cpp
 | 
			
		||||
        ${HEADER_DIR}/internal/catch_startup_exception_registry.cpp
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										295
									
								
								include/internal/catch_run_context.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								include/internal/catch_run_context.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,295 @@
 | 
			
		||||
#include "catch_run_context.hpp"
 | 
			
		||||
 | 
			
		||||
namespace Catch {
 | 
			
		||||
 | 
			
		||||
    StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString)
 | 
			
		||||
        : m_stream(stream),
 | 
			
		||||
        m_prevBuf(stream.rdbuf()),
 | 
			
		||||
        m_targetString(targetString) {
 | 
			
		||||
        stream.rdbuf(m_oss.rdbuf());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    StreamRedirect::~StreamRedirect() {
 | 
			
		||||
        m_targetString += m_oss.str();
 | 
			
		||||
        m_stream.rdbuf(m_prevBuf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
 | 
			
		||||
        : m_runInfo(_config->name()),
 | 
			
		||||
        m_context(getCurrentMutableContext()),
 | 
			
		||||
        m_config(_config),
 | 
			
		||||
        m_reporter(std::move(reporter)) {
 | 
			
		||||
        m_context.setRunner(this);
 | 
			
		||||
        m_context.setConfig(m_config);
 | 
			
		||||
        m_context.setResultCapture(this);
 | 
			
		||||
        m_reporter->testRunStarting(m_runInfo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    RunContext::~RunContext() {
 | 
			
		||||
        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) {
 | 
			
		||||
        m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) {
 | 
			
		||||
        m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Totals RunContext::runTest(TestCase const& testCase) {
 | 
			
		||||
        Totals prevTotals = m_totals;
 | 
			
		||||
 | 
			
		||||
        std::string redirectedCout;
 | 
			
		||||
        std::string redirectedCerr;
 | 
			
		||||
 | 
			
		||||
        TestCaseInfo testInfo = testCase.getTestCaseInfo();
 | 
			
		||||
 | 
			
		||||
        m_reporter->testCaseStarting(testInfo);
 | 
			
		||||
 | 
			
		||||
        m_activeTestCase = &testCase;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        ITracker& rootTracker = m_trackerContext.startRun();
 | 
			
		||||
        assert(rootTracker.isSectionTracker());
 | 
			
		||||
        static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
 | 
			
		||||
        do {
 | 
			
		||||
            m_trackerContext.startCycle();
 | 
			
		||||
            m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
 | 
			
		||||
            runCurrentTest(redirectedCout, redirectedCerr);
 | 
			
		||||
        } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
 | 
			
		||||
 | 
			
		||||
        Totals deltaTotals = m_totals.delta(prevTotals);
 | 
			
		||||
        if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
 | 
			
		||||
            deltaTotals.assertions.failed++;
 | 
			
		||||
            deltaTotals.testCases.passed--;
 | 
			
		||||
            deltaTotals.testCases.failed++;
 | 
			
		||||
        }
 | 
			
		||||
        m_totals.testCases += deltaTotals.testCases;
 | 
			
		||||
        m_reporter->testCaseEnded(TestCaseStats(testInfo,
 | 
			
		||||
                                  deltaTotals,
 | 
			
		||||
                                  redirectedCout,
 | 
			
		||||
                                  redirectedCerr,
 | 
			
		||||
                                  aborting()));
 | 
			
		||||
 | 
			
		||||
        m_activeTestCase = nullptr;
 | 
			
		||||
        m_testCaseTracker = nullptr;
 | 
			
		||||
 | 
			
		||||
        return deltaTotals;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IConfigPtr RunContext::config() const {
 | 
			
		||||
        return m_config;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IStreamingReporter& RunContext::reporter() const {
 | 
			
		||||
        return *m_reporter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::assertionEnded(AssertionResult const & result) {
 | 
			
		||||
        if (result.getResultType() == ResultWas::Ok) {
 | 
			
		||||
            m_totals.assertions.passed++;
 | 
			
		||||
        } else if (!result.isOk()) {
 | 
			
		||||
            m_totals.assertions.failed++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We have no use for the return value (whether messages should be cleared), because messages were made scoped
 | 
			
		||||
        // and should be let to clear themselves out.
 | 
			
		||||
        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_lastResult = result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
 | 
			
		||||
        ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
 | 
			
		||||
        if (!sectionTracker.isOpen())
 | 
			
		||||
            return false;
 | 
			
		||||
        m_activeSections.push_back(§ionTracker);
 | 
			
		||||
 | 
			
		||||
        m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
 | 
			
		||||
 | 
			
		||||
        m_reporter->sectionStarting(sectionInfo);
 | 
			
		||||
 | 
			
		||||
        assertions = m_totals.assertions;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool RunContext::testForMissingAssertions(Counts& assertions) {
 | 
			
		||||
        if (assertions.total() != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (!m_config->warnAboutMissingAssertions())
 | 
			
		||||
            return false;
 | 
			
		||||
        if (m_trackerContext.currentTracker().hasChildren())
 | 
			
		||||
            return false;
 | 
			
		||||
        m_totals.assertions.failed++;
 | 
			
		||||
        assertions.failed++;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
 | 
			
		||||
        Counts assertions = m_totals.assertions - endInfo.prevAssertions;
 | 
			
		||||
        bool missingAssertions = testForMissingAssertions(assertions);
 | 
			
		||||
 | 
			
		||||
        if (!m_activeSections.empty()) {
 | 
			
		||||
            m_activeSections.back()->close();
 | 
			
		||||
            m_activeSections.pop_back();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
 | 
			
		||||
        m_messages.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
 | 
			
		||||
        if (m_unfinishedSections.empty())
 | 
			
		||||
            m_activeSections.back()->fail();
 | 
			
		||||
        else
 | 
			
		||||
            m_activeSections.back()->close();
 | 
			
		||||
        m_activeSections.pop_back();
 | 
			
		||||
 | 
			
		||||
        m_unfinishedSections.push_back(endInfo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::pushScopedMessage(MessageInfo const & message) {
 | 
			
		||||
        m_messages.push_back(message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::popScopedMessage(MessageInfo const & message) {
 | 
			
		||||
        m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string RunContext::getCurrentTestName() const {
 | 
			
		||||
        return m_activeTestCase
 | 
			
		||||
            ? m_activeTestCase->getTestCaseInfo().name
 | 
			
		||||
            : std::string();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const AssertionResult * RunContext::getLastResult() const {
 | 
			
		||||
        return &m_lastResult;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::exceptionEarlyReported() {
 | 
			
		||||
        m_shouldReportUnexpected = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
        tempResult.resultType = ResultWas::FatalErrorCondition;
 | 
			
		||||
        tempResult.message = message;
 | 
			
		||||
        AssertionResult result(m_lastAssertionInfo, tempResult);
 | 
			
		||||
 | 
			
		||||
        getResultCapture().assertionEnded(result);
 | 
			
		||||
 | 
			
		||||
        handleUnfinishedSections();
 | 
			
		||||
 | 
			
		||||
        // Recreate section for test case (as we will lose the one that was in scope)
 | 
			
		||||
        TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
 | 
			
		||||
        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
 | 
			
		||||
 | 
			
		||||
        Counts assertions;
 | 
			
		||||
        assertions.failed = 1;
 | 
			
		||||
        SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
 | 
			
		||||
        m_reporter->sectionEnded(testCaseSectionStats);
 | 
			
		||||
 | 
			
		||||
        TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
 | 
			
		||||
 | 
			
		||||
        Totals deltaTotals;
 | 
			
		||||
        deltaTotals.testCases.failed = 1;
 | 
			
		||||
        m_reporter->testCaseEnded(TestCaseStats(testInfo,
 | 
			
		||||
                                  deltaTotals,
 | 
			
		||||
                                  std::string(),
 | 
			
		||||
                                  std::string(),
 | 
			
		||||
                                  false));
 | 
			
		||||
        m_totals.testCases.failed++;
 | 
			
		||||
        testGroupEnded(std::string(), m_totals, 1, 1);
 | 
			
		||||
        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool RunContext::aborting() const {
 | 
			
		||||
        return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
 | 
			
		||||
        TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
 | 
			
		||||
        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
 | 
			
		||||
        m_reporter->sectionStarting(testCaseSection);
 | 
			
		||||
        Counts prevAssertions = m_totals.assertions;
 | 
			
		||||
        double duration = 0;
 | 
			
		||||
        m_shouldReportUnexpected = true;
 | 
			
		||||
        try {
 | 
			
		||||
            m_lastAssertionInfo = AssertionInfo("TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal);
 | 
			
		||||
 | 
			
		||||
            seedRng(*m_config);
 | 
			
		||||
 | 
			
		||||
            Timer timer;
 | 
			
		||||
            timer.start();
 | 
			
		||||
            if (m_reporter->getPreferences().shouldRedirectStdOut) {
 | 
			
		||||
                StreamRedirect coutRedir(cout(), redirectedCout);
 | 
			
		||||
                StreamRedirect cerrRedir(cerr(), redirectedCerr);
 | 
			
		||||
                invokeActiveTestCase();
 | 
			
		||||
            } else {
 | 
			
		||||
                invokeActiveTestCase();
 | 
			
		||||
            }
 | 
			
		||||
            duration = timer.getElapsedSeconds();
 | 
			
		||||
        } catch (TestFailureException&) {
 | 
			
		||||
            // This just means the test was aborted due to failure
 | 
			
		||||
        } 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();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        m_testCaseTracker->close();
 | 
			
		||||
        handleUnfinishedSections();
 | 
			
		||||
        m_messages.clear();
 | 
			
		||||
 | 
			
		||||
        Counts assertions = m_totals.assertions - prevAssertions;
 | 
			
		||||
        bool missingAssertions = testForMissingAssertions(assertions);
 | 
			
		||||
 | 
			
		||||
        if (testCaseInfo.okToFail()) {
 | 
			
		||||
            std::swap(assertions.failedButOk, assertions.failed);
 | 
			
		||||
            m_totals.assertions.failed -= assertions.failedButOk;
 | 
			
		||||
            m_totals.assertions.failedButOk += assertions.failedButOk;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
 | 
			
		||||
        m_reporter->sectionEnded(testCaseSectionStats);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RunContext::invokeActiveTestCase() {
 | 
			
		||||
        FatalConditionHandler fatalConditionHandler; // Handle signals
 | 
			
		||||
        m_activeTestCase->invoke();
 | 
			
		||||
        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.
 | 
			
		||||
        for (std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
 | 
			
		||||
             itEnd = m_unfinishedSections.rend();
 | 
			
		||||
             it != itEnd;
 | 
			
		||||
             ++it)
 | 
			
		||||
            sectionEnded(*it);
 | 
			
		||||
        m_unfinishedSections.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IResultCapture& getResultCapture() {
 | 
			
		||||
        if (IResultCapture* capture = getCurrentContext().getResultCapture())
 | 
			
		||||
            return *capture;
 | 
			
		||||
        else
 | 
			
		||||
            CATCH_INTERNAL_ERROR("No result capture instance");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -30,18 +30,9 @@ namespace Catch {
 | 
			
		||||
    class StreamRedirect {
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        StreamRedirect( std::ostream& stream, std::string& targetString )
 | 
			
		||||
        :   m_stream( stream ),
 | 
			
		||||
            m_prevBuf( stream.rdbuf() ),
 | 
			
		||||
            m_targetString( targetString )
 | 
			
		||||
        {
 | 
			
		||||
            stream.rdbuf( m_oss.rdbuf() );
 | 
			
		||||
        }
 | 
			
		||||
        StreamRedirect(std::ostream& stream, std::string& targetString);
 | 
			
		||||
 | 
			
		||||
        ~StreamRedirect() {
 | 
			
		||||
            m_targetString += m_oss.str();
 | 
			
		||||
            m_stream.rdbuf( m_prevBuf );
 | 
			
		||||
        }
 | 
			
		||||
        ~StreamRedirect();
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        std::ostream& m_stream;
 | 
			
		||||
@@ -54,297 +45,64 @@ namespace Catch {
 | 
			
		||||
 | 
			
		||||
    class RunContext : public IResultCapture, public IRunner {
 | 
			
		||||
 | 
			
		||||
        RunContext( RunContext const& );
 | 
			
		||||
        void operator =( RunContext const& );
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        RunContext( RunContext const& ) = delete;
 | 
			
		||||
        RunContext& operator =( RunContext const& ) = delete;
 | 
			
		||||
 | 
			
		||||
        explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter )
 | 
			
		||||
        :   m_runInfo( _config->name() ),
 | 
			
		||||
            m_context( getCurrentMutableContext() ),
 | 
			
		||||
            m_config( _config ),
 | 
			
		||||
            m_reporter( std::move( reporter ) )
 | 
			
		||||
        {
 | 
			
		||||
            m_context.setRunner( this );
 | 
			
		||||
            m_context.setConfig( m_config );
 | 
			
		||||
            m_context.setResultCapture( this );
 | 
			
		||||
            m_reporter->testRunStarting( m_runInfo );
 | 
			
		||||
        }
 | 
			
		||||
        explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter);
 | 
			
		||||
 | 
			
		||||
        virtual ~RunContext() {
 | 
			
		||||
            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
 | 
			
		||||
        }
 | 
			
		||||
        virtual ~RunContext();
 | 
			
		||||
 | 
			
		||||
        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
 | 
			
		||||
            m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
 | 
			
		||||
        }
 | 
			
		||||
        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
 | 
			
		||||
            m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
 | 
			
		||||
        }
 | 
			
		||||
        void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount);
 | 
			
		||||
        void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount);
 | 
			
		||||
 | 
			
		||||
        Totals runTest( TestCase const& testCase ) {
 | 
			
		||||
            Totals prevTotals = m_totals;
 | 
			
		||||
        Totals runTest(TestCase const& testCase);
 | 
			
		||||
 | 
			
		||||
            std::string redirectedCout;
 | 
			
		||||
            std::string redirectedCerr;
 | 
			
		||||
 | 
			
		||||
            TestCaseInfo testInfo = testCase.getTestCaseInfo();
 | 
			
		||||
 | 
			
		||||
            m_reporter->testCaseStarting( testInfo );
 | 
			
		||||
 | 
			
		||||
            m_activeTestCase = &testCase;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            ITracker& rootTracker = m_trackerContext.startRun();
 | 
			
		||||
            assert( rootTracker.isSectionTracker() );
 | 
			
		||||
            static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
 | 
			
		||||
            do {
 | 
			
		||||
                m_trackerContext.startCycle();
 | 
			
		||||
                m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
 | 
			
		||||
                runCurrentTest( redirectedCout, redirectedCerr );
 | 
			
		||||
            }
 | 
			
		||||
            while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
 | 
			
		||||
 | 
			
		||||
            Totals deltaTotals = m_totals.delta( prevTotals );
 | 
			
		||||
            if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
 | 
			
		||||
                deltaTotals.assertions.failed++;
 | 
			
		||||
                deltaTotals.testCases.passed--;
 | 
			
		||||
                deltaTotals.testCases.failed++;
 | 
			
		||||
            }
 | 
			
		||||
            m_totals.testCases += deltaTotals.testCases;
 | 
			
		||||
            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
 | 
			
		||||
                                                        deltaTotals,
 | 
			
		||||
                                                        redirectedCout,
 | 
			
		||||
                                                        redirectedCerr,
 | 
			
		||||
                                                        aborting() ) );
 | 
			
		||||
 | 
			
		||||
            m_activeTestCase = nullptr;
 | 
			
		||||
            m_testCaseTracker = nullptr;
 | 
			
		||||
 | 
			
		||||
            return deltaTotals;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        IConfigPtr config() const {
 | 
			
		||||
            return m_config;
 | 
			
		||||
        }
 | 
			
		||||
        IStreamingReporter& reporter() const {
 | 
			
		||||
            return *m_reporter;
 | 
			
		||||
        }
 | 
			
		||||
        IConfigPtr config() const;
 | 
			
		||||
        IStreamingReporter& reporter() const;
 | 
			
		||||
 | 
			
		||||
    private: // IResultCapture
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        virtual void assertionEnded( AssertionResult const& result ) {
 | 
			
		||||
            if( result.getResultType() == ResultWas::Ok ) {
 | 
			
		||||
                m_totals.assertions.passed++;
 | 
			
		||||
            }
 | 
			
		||||
            else if( !result.isOk() ) {
 | 
			
		||||
                m_totals.assertions.failed++;
 | 
			
		||||
            }
 | 
			
		||||
        virtual void assertionEnded(AssertionResult const& result);
 | 
			
		||||
 | 
			
		||||
            // We have no use for the return value (whether messages should be cleared), because messages were made scoped
 | 
			
		||||
            // and should be let to clear themselves out.
 | 
			
		||||
            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_lastResult = result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual bool sectionStarted (
 | 
			
		||||
        virtual bool sectionStarted(
 | 
			
		||||
            SectionInfo const& sectionInfo,
 | 
			
		||||
            Counts& assertions
 | 
			
		||||
        )
 | 
			
		||||
        {
 | 
			
		||||
            ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
 | 
			
		||||
            if( !sectionTracker.isOpen() )
 | 
			
		||||
                return false;
 | 
			
		||||
            m_activeSections.push_back( §ionTracker );
 | 
			
		||||
        );
 | 
			
		||||
        bool testForMissingAssertions(Counts& assertions);
 | 
			
		||||
 | 
			
		||||
            m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
 | 
			
		||||
        virtual void sectionEnded(SectionEndInfo const& endInfo);
 | 
			
		||||
 | 
			
		||||
            m_reporter->sectionStarting( sectionInfo );
 | 
			
		||||
        virtual void sectionEndedEarly(SectionEndInfo const& endInfo);
 | 
			
		||||
 | 
			
		||||
            assertions = m_totals.assertions;
 | 
			
		||||
        virtual void pushScopedMessage(MessageInfo const& message);
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        bool testForMissingAssertions( Counts& assertions ) {
 | 
			
		||||
            if( assertions.total() != 0 )
 | 
			
		||||
                return false;
 | 
			
		||||
            if( !m_config->warnAboutMissingAssertions() )
 | 
			
		||||
                return false;
 | 
			
		||||
            if( m_trackerContext.currentTracker().hasChildren() )
 | 
			
		||||
                return false;
 | 
			
		||||
            m_totals.assertions.failed++;
 | 
			
		||||
            assertions.failed++;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        virtual void popScopedMessage(MessageInfo const& message);
 | 
			
		||||
 | 
			
		||||
        virtual void sectionEnded( SectionEndInfo const& endInfo ) {
 | 
			
		||||
            Counts assertions = m_totals.assertions - endInfo.prevAssertions;
 | 
			
		||||
            bool missingAssertions = testForMissingAssertions( assertions );
 | 
			
		||||
        virtual std::string getCurrentTestName() const;
 | 
			
		||||
 | 
			
		||||
            if( !m_activeSections.empty() ) {
 | 
			
		||||
                m_activeSections.back()->close();
 | 
			
		||||
                m_activeSections.pop_back();
 | 
			
		||||
            }
 | 
			
		||||
        virtual const AssertionResult* getLastResult() const;
 | 
			
		||||
 | 
			
		||||
            m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
 | 
			
		||||
            m_messages.clear();
 | 
			
		||||
        }
 | 
			
		||||
        virtual void exceptionEarlyReported();
 | 
			
		||||
 | 
			
		||||
        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
 | 
			
		||||
            if( m_unfinishedSections.empty() )
 | 
			
		||||
                m_activeSections.back()->fail();
 | 
			
		||||
            else
 | 
			
		||||
                m_activeSections.back()->close();
 | 
			
		||||
            m_activeSections.pop_back();
 | 
			
		||||
 | 
			
		||||
            m_unfinishedSections.push_back( endInfo );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual void pushScopedMessage( MessageInfo const& message ) {
 | 
			
		||||
            m_messages.push_back( message );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual void popScopedMessage( MessageInfo const& message ) {
 | 
			
		||||
            m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual std::string getCurrentTestName() const {
 | 
			
		||||
            return m_activeTestCase
 | 
			
		||||
                ? m_activeTestCase->getTestCaseInfo().name
 | 
			
		||||
                : std::string();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual const AssertionResult* getLastResult() const {
 | 
			
		||||
            return &m_lastResult;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual void exceptionEarlyReported() {
 | 
			
		||||
            m_shouldReportUnexpected = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual void 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;
 | 
			
		||||
            tempResult.resultType = ResultWas::FatalErrorCondition;
 | 
			
		||||
            tempResult.message = message;
 | 
			
		||||
            AssertionResult result(m_lastAssertionInfo, tempResult);
 | 
			
		||||
 | 
			
		||||
            getResultCapture().assertionEnded(result);
 | 
			
		||||
 | 
			
		||||
            handleUnfinishedSections();
 | 
			
		||||
 | 
			
		||||
            // Recreate section for test case (as we will lose the one that was in scope)
 | 
			
		||||
            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
 | 
			
		||||
            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
 | 
			
		||||
 | 
			
		||||
            Counts assertions;
 | 
			
		||||
            assertions.failed = 1;
 | 
			
		||||
            SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
 | 
			
		||||
            m_reporter->sectionEnded( testCaseSectionStats );
 | 
			
		||||
 | 
			
		||||
            TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
 | 
			
		||||
 | 
			
		||||
            Totals deltaTotals;
 | 
			
		||||
            deltaTotals.testCases.failed = 1;
 | 
			
		||||
            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
 | 
			
		||||
                                                        deltaTotals,
 | 
			
		||||
                                                        std::string(),
 | 
			
		||||
                                                        std::string(),
 | 
			
		||||
                                                        false ) );
 | 
			
		||||
            m_totals.testCases.failed++;
 | 
			
		||||
            testGroupEnded( std::string(), m_totals, 1, 1 );
 | 
			
		||||
            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
 | 
			
		||||
        }
 | 
			
		||||
        virtual void handleFatalErrorCondition(std::string const& message);
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        // !TBD We need to do this another way!
 | 
			
		||||
        bool aborting() const {
 | 
			
		||||
            return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
 | 
			
		||||
        }
 | 
			
		||||
        bool aborting() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
 | 
			
		||||
        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
 | 
			
		||||
            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
 | 
			
		||||
            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
 | 
			
		||||
            m_reporter->sectionStarting( testCaseSection );
 | 
			
		||||
            Counts prevAssertions = m_totals.assertions;
 | 
			
		||||
            double duration = 0;
 | 
			
		||||
            m_shouldReportUnexpected = true;
 | 
			
		||||
            try {
 | 
			
		||||
                m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
 | 
			
		||||
        void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr);
 | 
			
		||||
 | 
			
		||||
                seedRng( *m_config );
 | 
			
		||||
 | 
			
		||||
                Timer timer;
 | 
			
		||||
                timer.start();
 | 
			
		||||
                if( m_reporter->getPreferences().shouldRedirectStdOut ) {
 | 
			
		||||
                    StreamRedirect coutRedir( Catch::cout(), redirectedCout );
 | 
			
		||||
                    StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
 | 
			
		||||
                    invokeActiveTestCase();
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    invokeActiveTestCase();
 | 
			
		||||
                }
 | 
			
		||||
                duration = timer.getElapsedSeconds();
 | 
			
		||||
            }
 | 
			
		||||
            catch( TestFailureException& ) {
 | 
			
		||||
                // This just means the test was aborted due to failure
 | 
			
		||||
            }
 | 
			
		||||
            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();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            m_testCaseTracker->close();
 | 
			
		||||
            handleUnfinishedSections();
 | 
			
		||||
            m_messages.clear();
 | 
			
		||||
 | 
			
		||||
            Counts assertions = m_totals.assertions - prevAssertions;
 | 
			
		||||
            bool missingAssertions = testForMissingAssertions( assertions );
 | 
			
		||||
 | 
			
		||||
            if( testCaseInfo.okToFail() ) {
 | 
			
		||||
                std::swap( assertions.failedButOk, assertions.failed );
 | 
			
		||||
                m_totals.assertions.failed -= assertions.failedButOk;
 | 
			
		||||
                m_totals.assertions.failedButOk += assertions.failedButOk;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
 | 
			
		||||
            m_reporter->sectionEnded( testCaseSectionStats );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void invokeActiveTestCase() {
 | 
			
		||||
            FatalConditionHandler fatalConditionHandler; // Handle signals
 | 
			
		||||
            m_activeTestCase->invoke();
 | 
			
		||||
            fatalConditionHandler.reset();
 | 
			
		||||
        }
 | 
			
		||||
        void invokeActiveTestCase();
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
 | 
			
		||||
        ResultBuilder makeUnexpectedResultBuilder() const {
 | 
			
		||||
            return ResultBuilder(   m_lastAssertionInfo.macroName,
 | 
			
		||||
                                    m_lastAssertionInfo.lineInfo,
 | 
			
		||||
                                    m_lastAssertionInfo.capturedExpression,
 | 
			
		||||
                                    m_lastAssertionInfo.resultDisposition );
 | 
			
		||||
        }
 | 
			
		||||
        ResultBuilder makeUnexpectedResultBuilder() const;
 | 
			
		||||
 | 
			
		||||
        void handleUnfinishedSections() {
 | 
			
		||||
            // If sections ended prematurely due to an exception we stored their
 | 
			
		||||
            // infos here so we can tear them down outside the unwind process.
 | 
			
		||||
            for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
 | 
			
		||||
                        itEnd = m_unfinishedSections.rend();
 | 
			
		||||
                    it != itEnd;
 | 
			
		||||
                    ++it )
 | 
			
		||||
                sectionEnded( *it );
 | 
			
		||||
            m_unfinishedSections.clear();
 | 
			
		||||
        }
 | 
			
		||||
        void handleUnfinishedSections();
 | 
			
		||||
 | 
			
		||||
        TestRunInfo m_runInfo;
 | 
			
		||||
        IMutableContext& m_context;
 | 
			
		||||
@@ -364,12 +122,7 @@ namespace Catch {
 | 
			
		||||
        bool m_shouldReportUnexpected = true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    IResultCapture& getResultCapture() {
 | 
			
		||||
        if( IResultCapture* capture = getCurrentContext().getResultCapture() )
 | 
			
		||||
            return *capture;
 | 
			
		||||
        else
 | 
			
		||||
            CATCH_INTERNAL_ERROR( "No result capture instance" );
 | 
			
		||||
    }
 | 
			
		||||
    IResultCapture& getResultCapture();
 | 
			
		||||
 | 
			
		||||
} // end namespace Catch
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user