| 
									
										
										
										
											2017-09-07 11:24:33 +01:00
										 |  |  | #include "catch_run_context.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-29 15:36:09 +02:00
										 |  |  | #include "catch_context.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-01 18:46:33 +02:00
										 |  |  | #include "catch_enforce.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-30 15:32:44 +02:00
										 |  |  | #include "catch_random_number_generator.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-29 16:44:02 +02:00
										 |  |  | #include "catch_stream.h"
 | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-19 10:13:47 +02:00
										 |  |  | #include <cassert>
 | 
					
						
							| 
									
										
										
										
											2017-07-25 21:57:35 +02:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2017-11-07 18:01:10 +00:00
										 |  |  | #include <sstream>
 | 
					
						
							| 
									
										
										
										
											2017-07-19 10:13:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | namespace Catch { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-05 23:19:28 +00:00
										 |  |  |     class RedirectedStream { | 
					
						
							|  |  |  |         std::ostream& m_originalStream; | 
					
						
							|  |  |  |         std::ostream& m_redirectionStream; | 
					
						
							|  |  |  |         std::streambuf* m_prevBuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) | 
					
						
							|  |  |  |         :   m_originalStream( originalStream ), | 
					
						
							|  |  |  |             m_redirectionStream( redirectionStream ), | 
					
						
							|  |  |  |             m_prevBuf( m_originalStream.rdbuf() ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ~RedirectedStream() { | 
					
						
							|  |  |  |             m_originalStream.rdbuf( m_prevBuf ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class RedirectedStdOut { | 
					
						
							|  |  |  |         ReusableStringStream m_rss; | 
					
						
							|  |  |  |         RedirectedStream m_cout; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} | 
					
						
							|  |  |  |         auto str() const -> std::string { return m_rss.str(); } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // StdErr has two constituent streams in C++, std::cerr and std::clog
 | 
					
						
							|  |  |  |     // This means that we need to redirect 2 streams into 1 to keep proper
 | 
					
						
							|  |  |  |     // order of writes
 | 
					
						
							|  |  |  |     class RedirectedStdErr { | 
					
						
							|  |  |  |         ReusableStringStream m_rss; | 
					
						
							|  |  |  |         RedirectedStream m_cerr; | 
					
						
							|  |  |  |         RedirectedStream m_clog; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         RedirectedStdErr() | 
					
						
							|  |  |  |         :   m_cerr( Catch::cerr(), m_rss.get() ), | 
					
						
							|  |  |  |             m_clog( Catch::clog(), m_rss.get() ) | 
					
						
							|  |  |  |         {} | 
					
						
							|  |  |  |         auto str() const -> std::string { return m_rss.str(); } | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-08-10 11:34:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |     RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) | 
					
						
							| 
									
										
										
										
											2017-08-08 01:02:24 +01:00
										 |  |  |     :   m_runInfo(_config->name()), | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         m_context(getCurrentMutableContext()), | 
					
						
							|  |  |  |         m_config(_config), | 
					
						
							| 
									
										
										
										
											2017-08-08 01:02:24 +01:00
										 |  |  |         m_reporter(std::move(reporter)), | 
					
						
							| 
									
										
										
										
											2018-03-02 16:22:18 +01:00
										 |  |  |         m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, | 
					
						
							| 
									
										
										
										
											2017-11-27 22:21:47 +03:00
										 |  |  |         m_includeSuccessfulResults( m_config->includeSuccessfulResults() ) | 
					
						
							| 
									
										
										
										
											2017-08-08 01:02:24 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-02 16:22:18 +01:00
										 |  |  |         auto const& testInfo = testCase.getTestCaseInfo(); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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++; | 
					
						
							| 
									
										
										
										
											2017-12-02 21:01:59 +03:00
										 |  |  |             m_lastAssertionPassed = true; | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         } else if (!result.isOk()) { | 
					
						
							| 
									
										
										
										
											2017-12-02 21:01:59 +03:00
										 |  |  |             m_lastAssertionPassed = false; | 
					
						
							| 
									
										
										
										
											2017-08-25 11:33:29 +01:00
										 |  |  |             if( m_activeTestCase->getTestCaseInfo().okToFail() ) | 
					
						
							|  |  |  |                 m_totals.assertions.failedButOk++; | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 m_totals.assertions.failed++; | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-12-02 21:01:59 +03:00
										 |  |  |         else { | 
					
						
							|  |  |  |             m_lastAssertionPassed = true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // 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
 | 
					
						
							| 
									
										
										
										
											2017-11-17 18:55:47 +00:00
										 |  |  |         resetAssertionInfo(); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         m_lastResult = result; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-17 18:55:47 +00:00
										 |  |  |     void RunContext::resetAssertionInfo() { | 
					
						
							|  |  |  |         m_lastAssertionInfo.macroName = StringRef(); | 
					
						
							| 
									
										
										
										
											2017-11-21 11:08:08 +00:00
										 |  |  |         m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; | 
					
						
							| 
									
										
										
										
											2017-11-17 18:55:47 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-04 19:23:30 +01:00
										 |  |  |     void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { | 
					
						
							|  |  |  |         m_reporter->benchmarkStarting( info ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { | 
					
						
							|  |  |  |         m_reporter->benchmarkEnded( stats ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 { | 
					
						
							| 
									
										
										
										
											2017-08-08 01:02:24 +01:00
										 |  |  |         return &(*m_lastResult); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void RunContext::exceptionEarlyReported() { | 
					
						
							|  |  |  |         m_shouldReportUnexpected = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 20:05:25 +02:00
										 |  |  |     void RunContext::handleFatalErrorCondition( StringRef message ) { | 
					
						
							| 
									
										
										
										
											2017-09-14 19:57:59 +02:00
										 |  |  |         // First notify reporter that bad things happened
 | 
					
						
							|  |  |  |         m_reporter->fatalErrorEncountered(message); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         // Don't rebuild the result -- the stringification itself can cause more fatal errors
 | 
					
						
							|  |  |  |         // Instead, fake a result data.
 | 
					
						
							| 
									
										
										
										
											2017-08-31 11:46:37 +02:00
										 |  |  |         AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         tempResult.message = message; | 
					
						
							|  |  |  |         AssertionResult result(m_lastAssertionInfo, tempResult); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-27 22:21:47 +03:00
										 |  |  |         assertionEnded(result); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         handleUnfinishedSections(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Recreate section for test case (as we will lose the one that was in scope)
 | 
					
						
							| 
									
										
										
										
											2017-08-31 11:46:37 +02:00
										 |  |  |         auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Counts assertions; | 
					
						
							|  |  |  |         assertions.failed = 1; | 
					
						
							|  |  |  |         SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); | 
					
						
							|  |  |  |         m_reporter->sectionEnded(testCaseSectionStats); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-31 11:46:37 +02:00
										 |  |  |         auto const& testInfo = m_activeTestCase->getTestCaseInfo(); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Totals deltaTotals; | 
					
						
							|  |  |  |         deltaTotals.testCases.failed = 1; | 
					
						
							| 
									
										
										
										
											2017-08-10 17:10:13 +01:00
										 |  |  |         deltaTotals.assertions.failed = 1; | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         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)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 14:30:23 -05:00
										 |  |  |     bool RunContext::lastAssertionPassed() { | 
					
						
							| 
									
										
										
										
											2017-12-02 21:01:59 +03:00
										 |  |  |          return m_lastAssertionPassed; | 
					
						
							| 
									
										
										
										
											2017-06-26 14:30:23 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void RunContext::assertionPassed() { | 
					
						
							| 
									
										
										
										
											2017-12-02 21:01:59 +03:00
										 |  |  |         m_lastAssertionPassed = true; | 
					
						
							| 
									
										
										
										
											2017-06-26 14:30:23 -05:00
										 |  |  |         ++m_totals.assertions.passed; | 
					
						
							| 
									
										
										
										
											2017-11-17 18:55:47 +00:00
										 |  |  |         resetAssertionInfo(); | 
					
						
							| 
									
										
										
										
											2017-06-26 14:30:23 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2017-08-31 11:46:37 +02:00
										 |  |  |         auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); | 
					
						
							|  |  |  |         m_reporter->sectionStarting(testCaseSection); | 
					
						
							|  |  |  |         Counts prevAssertions = m_totals.assertions; | 
					
						
							|  |  |  |         double duration = 0; | 
					
						
							|  |  |  |         m_shouldReportUnexpected = true; | 
					
						
							| 
									
										
										
										
											2018-03-02 16:22:18 +01:00
										 |  |  |         m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-17 18:55:47 +00:00
										 |  |  |         seedRng(*m_config); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-17 18:55:47 +00:00
										 |  |  |         Timer timer; | 
					
						
							|  |  |  |         try { | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |             if (m_reporter->getPreferences().shouldRedirectStdOut) { | 
					
						
							| 
									
										
										
										
											2017-12-05 23:19:28 +00:00
										 |  |  |                 RedirectedStdOut redirectedStdOut; | 
					
						
							|  |  |  |                 RedirectedStdErr redirectedStdErr; | 
					
						
							| 
									
										
										
										
											2017-11-17 18:55:47 +00:00
										 |  |  |                 timer.start(); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |                 invokeActiveTestCase(); | 
					
						
							| 
									
										
										
										
											2017-12-05 23:19:28 +00:00
										 |  |  |                 redirectedCout += redirectedStdOut.str(); | 
					
						
							|  |  |  |                 redirectedCerr += redirectedStdErr.str(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2017-11-17 18:55:47 +00:00
										 |  |  |                 timer.start(); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |                 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.
 | 
					
						
							| 
									
										
										
										
											2017-11-27 22:21:47 +03:00
										 |  |  |             if( m_shouldReportUnexpected ) { | 
					
						
							|  |  |  |                 AssertionReaction dummyReaction; | 
					
						
							|  |  |  |                 handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-01-26 16:52:28 +00:00
										 |  |  |         Counts assertions = m_totals.assertions - prevAssertions; | 
					
						
							|  |  |  |         bool missingAssertions = testForMissingAssertions(assertions); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |         m_testCaseTracker->close(); | 
					
						
							|  |  |  |         handleUnfinishedSections(); | 
					
						
							|  |  |  |         m_messages.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); | 
					
						
							|  |  |  |         m_reporter->sectionEnded(testCaseSectionStats); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void RunContext::invokeActiveTestCase() { | 
					
						
							|  |  |  |         FatalConditionHandler fatalConditionHandler; // Handle signals
 | 
					
						
							|  |  |  |         m_activeTestCase->invoke(); | 
					
						
							|  |  |  |         fatalConditionHandler.reset(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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.
 | 
					
						
							| 
									
										
										
										
											2017-07-18 08:08:17 +01:00
										 |  |  |         for (auto it = m_unfinishedSections.rbegin(), | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |              itEnd = m_unfinishedSections.rend(); | 
					
						
							|  |  |  |              it != itEnd; | 
					
						
							|  |  |  |              ++it) | 
					
						
							|  |  |  |             sectionEnded(*it); | 
					
						
							|  |  |  |         m_unfinishedSections.clear(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-27 22:21:47 +03:00
										 |  |  |     void RunContext::handleExpr( | 
					
						
							|  |  |  |         AssertionInfo const& info, | 
					
						
							|  |  |  |         ITransientExpression const& expr, | 
					
						
							|  |  |  |         AssertionReaction& reaction | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         m_reporter->assertionStarting( info ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool negated = isFalseTest( info.resultDisposition ); | 
					
						
							|  |  |  |         bool result = expr.getResult() != negated; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if( result ) { | 
					
						
							|  |  |  |             if (!m_includeSuccessfulResults) { | 
					
						
							|  |  |  |                 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, | 
					
						
							| 
									
										
										
										
											2017-11-27 22:28:45 +03:00
										 |  |  |             StringRef const& message, | 
					
						
							| 
									
										
										
										
											2017-11-27 22:21:47 +03:00
										 |  |  |             AssertionReaction& reaction | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         m_reporter->assertionStarting( info ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         m_lastAssertionInfo = info; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         AssertionResultData data( resultType, LazyExpression( false ) ); | 
					
						
							|  |  |  |         AssertionResult assertionResult{ info, data }; | 
					
						
							|  |  |  |         assertionEnded( assertionResult ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if( !assertionResult.isOk() ) | 
					
						
							|  |  |  |             populateReaction( reaction ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |     IResultCapture& getResultCapture() { | 
					
						
							| 
									
										
										
										
											2017-08-31 11:46:37 +02:00
										 |  |  |         if (auto* capture = getCurrentContext().getResultCapture()) | 
					
						
							| 
									
										
										
										
											2017-07-15 16:48:21 +02:00
										 |  |  |             return *capture; | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             CATCH_INTERNAL_ERROR("No result capture instance"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-07 16:51:33 +02:00
										 |  |  | } |