2011-12-28 10:23:32 +00:00
/*
2010-11-09 23:24:00 +00:00
* Created by Phil on 22/10/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
2012-09-17 01:42:29 -04:00
#ifndef TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
2010-11-09 23:24:00 +00:00
2011-01-11 09:13:31 +00:00
#include "catch_interfaces_runner.h"
2010-12-31 22:46:51 +00:00
#include "catch_interfaces_reporter.h"
2012-05-11 08:16:39 +01:00
#include "catch_interfaces_exception.h"
2011-01-01 00:29:58 +00:00
#include "catch_config.hpp"
2011-01-05 21:16:54 +00:00
#include "catch_test_registry.hpp"
2012-08-14 19:30:30 +01:00
#include "catch_test_case_info.h"
2010-11-09 23:24:00 +00:00
#include "catch_capture.hpp"
2012-02-23 08:49:52 +00:00
#include "catch_totals.hpp"
2014-05-16 18:28:58 +01:00
#include "catch_test_spec.hpp"
2013-07-24 19:13:08 +01:00
#include "catch_test_case_tracker.hpp"
2013-08-07 18:56:35 +01:00
#include "catch_timer.h"
2014-05-28 18:53:01 +01:00
#include "catch_result_builder.h"
2014-08-22 08:07:39 +01:00
#include "catch_fatal_condition.hpp"
2010-11-09 23:24:00 +00:00
2011-02-08 08:42:05 +00:00
#include <set>
#include <string>
2012-05-16 08:02:20 +01:00
namespace Catch {
class StreamRedirect {
2013-07-03 19:14:59 +01:00
2011-02-21 08:50:05 +00:00
public :
2012-05-16 08:02:20 +01:00
StreamRedirect ( std :: ostream & stream , std :: string & targetString )
2011-02-21 08:50:05 +00:00
: m_stream ( stream ),
m_prevBuf ( stream . rdbuf () ),
2013-07-03 19:14:59 +01:00
m_targetString ( targetString )
{
2011-02-21 08:50:05 +00:00
stream . rdbuf ( m_oss . rdbuf () );
}
2013-07-03 19:14:59 +01:00
2012-05-16 08:02:20 +01:00
~ StreamRedirect () {
2011-12-28 10:23:32 +00:00
m_targetString += m_oss . str ();
2011-02-21 08:50:05 +00:00
m_stream . rdbuf ( m_prevBuf );
}
2013-07-03 19:14:59 +01:00
2011-02-21 08:50:05 +00:00
private :
std :: ostream & m_stream ;
std :: streambuf * m_prevBuf ;
std :: ostringstream m_oss ;
std :: string & m_targetString ;
};
2012-11-04 21:09:22 +00:00
2011-01-28 18:56:26 +00:00
///////////////////////////////////////////////////////////////////////////
2012-05-16 08:02:20 +01:00
2013-06-05 08:18:52 +01:00
class RunContext : public IResultCapture , public IRunner {
2013-07-03 19:14:59 +01:00
2013-06-05 08:18:52 +01:00
RunContext ( RunContext const & );
void operator = ( RunContext const & );
2013-07-03 19:14:59 +01:00
2010-11-09 23:24:00 +00:00
public :
2011-01-11 19:48:48 +00:00
2015-07-01 07:50:53 +01:00
explicit RunContext ( Ptr < IConfig const > const & _config , Ptr < IStreamingReporter > const & reporter )
: m_runInfo ( _config -> name () ),
2012-12-01 23:54:17 +00:00
m_context ( getCurrentMutableContext () ),
2015-07-01 07:33:27 +01:00
m_activeTestCase ( CATCH_NULL ),
2015-07-01 07:50:53 +01:00
m_config ( _config ),
2015-09-28 01:09:06 -07:00
m_reporter ( reporter )
2010-11-09 23:24:00 +00:00
{
2012-05-21 18:52:09 +01:00
m_context . setRunner ( this );
2013-05-28 18:51:53 +01:00
m_context . setConfig ( m_config );
2012-05-21 18:52:09 +01:00
m_context . setResultCapture ( this );
2012-12-01 23:54:17 +00:00
m_reporter -> testRunStarting ( m_runInfo );
2010-11-09 23:24:00 +00:00
}
2013-07-03 19:14:59 +01:00
2013-06-05 08:18:52 +01:00
virtual ~ RunContext () {
2013-01-03 09:04:46 +00:00
m_reporter -> testRunEnded ( TestRunStats ( m_runInfo , m_totals , aborting () ) );
2010-11-09 23:24:00 +00:00
}
2012-07-16 08:58:28 +01:00
2013-01-13 21:51:44 +00:00
void testGroupStarting ( std :: string const & testSpec , std :: size_t groupIndex , std :: size_t groupsCount ) {
m_reporter -> testGroupStarting ( GroupInfo ( testSpec , groupIndex , groupsCount ) );
2012-11-30 09:13:27 +00:00
}
2013-01-13 21:51:44 +00:00
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 () ) );
2012-11-30 09:13:27 +00:00
}
2013-04-23 18:58:56 +01:00
Totals runTest ( TestCase const & testCase ) {
2012-02-23 08:49:52 +00:00
Totals prevTotals = m_totals ;
2011-01-19 19:30:01 +00:00
std :: string redirectedCout ;
std :: string redirectedCerr ;
2012-11-25 11:19:55 +00:00
TestCaseInfo testInfo = testCase . getTestCaseInfo ();
2012-11-25 21:43:36 +00:00
2012-11-30 19:15:23 +00:00
m_reporter -> testCaseStarting ( testInfo );
2013-07-03 19:14:59 +01:00
2013-07-25 07:49:00 +01:00
m_activeTestCase = & testCase ;
2015-11-04 18:01:28 +00:00
2010-11-30 06:48:21 +00:00
2012-05-16 08:02:20 +01:00
do {
2015-11-03 07:29:23 +00:00
m_trackerContext . startRun ();
2012-05-16 08:02:20 +01:00
do {
2015-11-02 19:21:46 +00:00
m_trackerContext . startCycle ();
m_testCaseTracker = & SectionTracker :: acquire ( m_trackerContext , testInfo . name );
2011-01-26 23:23:33 +00:00
runCurrentTest ( redirectedCout , redirectedCerr );
}
2015-11-02 19:21:46 +00:00
while ( ! m_testCaseTracker -> isSuccessfullyCompleted () && ! aborting () );
2010-11-09 23:24:00 +00:00
}
2015-11-03 07:38:14 +00:00
// !TBD: deprecated - this will be replaced by indexed trackers
2012-06-01 19:40:27 +01:00
while ( getCurrentContext (). advanceGeneratorsForCurrentTest () && ! aborting () );
2011-01-19 08:52:25 +00:00
2012-11-21 08:19:23 +00:00
Totals deltaTotals = m_totals . delta ( prevTotals );
2016-03-14 19:13:34 +00:00
if ( testInfo . expectedToFail () && deltaTotals . testCases . passed > 0 ) {
deltaTotals . assertions . failed ++ ;
deltaTotals . testCases . passed -- ;
deltaTotals . testCases . failed ++ ;
}
2012-11-21 08:19:23 +00:00
m_totals . testCases += deltaTotals . testCases ;
2013-01-03 09:04:46 +00:00
m_reporter -> testCaseEnded ( TestCaseStats ( testInfo ,
deltaTotals ,
redirectedCout ,
redirectedCerr ,
aborting () ) );
2012-11-21 08:19:23 +00:00
2015-07-01 07:33:27 +01:00
m_activeTestCase = CATCH_NULL ;
2015-11-02 19:21:46 +00:00
m_testCaseTracker = CATCH_NULL ;
2011-01-19 19:30:01 +00:00
2012-08-15 19:12:51 +01:00
return deltaTotals ;
2010-11-09 23:24:00 +00:00
}
2012-02-17 19:50:59 +00:00
2013-05-28 18:51:53 +01:00
Ptr < IConfig const > config () const {
2012-06-05 20:50:47 +01:00
return m_config ;
}
2013-07-03 19:14:59 +01:00
2011-01-11 09:13:31 +00:00
private : // IResultCapture
2010-12-31 20:49:58 +00:00
2013-04-23 18:58:56 +01:00
virtual void assertionEnded ( AssertionResult const & result ) {
2012-05-16 08:02:20 +01:00
if ( result . getResultType () == ResultWas :: Ok ) {
2012-02-23 08:49:52 +00:00
m_totals . assertions . passed ++ ;
2010-12-27 22:18:33 +00:00
}
2012-11-13 09:44:52 +00:00
else if ( ! result . isOk () ) {
2012-02-23 08:49:52 +00:00
m_totals . assertions . failed ++ ;
2010-12-27 22:05:13 +00:00
}
2013-07-03 19:14:59 +01:00
2013-06-28 16:25:49 +01:00
if ( m_reporter -> assertionEnded ( AssertionStats ( result , m_messages , m_totals ) ) )
m_messages . clear ();
2012-11-17 17:22:37 +00:00
2013-02-02 20:36:36 +00:00
// Reset working state
2013-02-02 19:58:04 +00:00
m_lastAssertionInfo = AssertionInfo ( "" , m_lastAssertionInfo . lineInfo , "{Unknown expression after the reported line}" , m_lastAssertionInfo . resultDisposition );
2014-05-28 18:53:01 +01:00
m_lastResult = result ;
2010-11-09 23:24:00 +00:00
}
2013-07-03 19:14:59 +01:00
2012-05-16 08:02:20 +01:00
virtual bool sectionStarted (
2012-11-30 08:58:46 +00:00
SectionInfo const & sectionInfo ,
2012-02-23 08:57:51 +00:00
Counts & assertions
2011-01-11 19:48:48 +00:00
)
2010-11-29 19:40:44 +00:00
{
2011-04-21 19:43:55 +01:00
std :: ostringstream oss ;
2012-11-30 08:58:46 +00:00
oss << sectionInfo . name << "@" << sectionInfo . lineInfo ;
2011-04-21 19:43:55 +01:00
2015-11-02 19:21:46 +00:00
ITracker & sectionTracker = SectionTracker :: acquire ( m_trackerContext , oss . str () );
if ( ! sectionTracker . isOpen () )
2011-01-19 08:52:25 +00:00
return false ;
2015-11-02 19:21:46 +00:00
m_activeSections . push_back ( & sectionTracker );
2015-11-04 18:01:28 +00:00
2012-11-30 08:58:46 +00:00
m_lastAssertionInfo . lineInfo = sectionInfo . lineInfo ;
2012-11-04 21:39:16 +00:00
2012-11-30 19:15:23 +00:00
m_reporter -> sectionStarting ( sectionInfo );
2012-11-29 09:05:51 +00:00
2012-02-23 08:57:51 +00:00
assertions = m_totals . assertions ;
2013-07-03 19:14:59 +01:00
2010-11-29 19:40:44 +00:00
return true ;
}
2013-07-26 19:26:08 +01:00
bool testForMissingAssertions ( Counts & assertions ) {
2015-11-02 19:21:46 +00:00
if ( assertions . total () != 0 )
return false ;
2015-11-03 17:05:08 +00:00
if ( ! m_config -> warnAboutMissingAssertions () )
2015-11-02 19:21:46 +00:00
return false ;
if ( m_trackerContext . currentTracker (). hasChildren () )
2013-07-26 19:26:08 +01:00
return false ;
m_totals . assertions . failed ++ ;
assertions . failed ++ ;
return true ;
}
2015-11-04 18:01:28 +00:00
2015-09-26 18:12:21 -07:00
virtual void sectionEnded ( SectionEndInfo const & endInfo ) {
Counts assertions = m_totals . assertions - endInfo . prevAssertions ;
2013-07-26 19:26:08 +01:00
bool missingAssertions = testForMissingAssertions ( assertions );
2015-11-04 18:01:28 +00:00
2015-11-02 19:21:46 +00:00
if ( ! m_activeSections . empty () ) {
m_activeSections . back () -> close ();
m_activeSections . pop_back ();
}
2015-11-04 18:01:28 +00:00
2015-09-26 18:12:21 -07:00
m_reporter -> sectionEnded ( SectionStats ( endInfo . sectionInfo , assertions , endInfo . durationInSeconds , missingAssertions ) );
2013-02-02 19:58:04 +00:00
m_messages . clear ();
2010-11-29 19:40:44 +00:00
}
2010-12-27 11:09:34 +00:00
2015-09-26 18:12:21 -07:00
virtual void sectionEndedEarly ( SectionEndInfo const & endInfo ) {
2015-11-02 19:21:46 +00:00
if ( m_unfinishedSections . empty () )
m_activeSections . back () -> fail ();
else
m_activeSections . back () -> close ();
m_activeSections . pop_back ();
2015-11-04 18:01:28 +00:00
2015-09-26 18:12:21 -07:00
m_unfinishedSections . push_back ( endInfo );
}
2015-11-04 18:01:28 +00:00
2013-06-28 17:09:57 +01:00
virtual void pushScopedMessage ( MessageInfo const & message ) {
m_messages . push_back ( message );
2013-02-02 19:58:04 +00:00
}
2013-07-03 19:14:59 +01:00
2013-06-28 17:09:57 +01:00
virtual void popScopedMessage ( MessageInfo const & message ) {
m_messages . erase ( std :: remove ( m_messages . begin (), m_messages . end (), message ), m_messages . end () );
2013-02-02 19:58:04 +00:00
}
2011-01-11 19:48:48 +00:00
2012-05-16 08:02:20 +01:00
virtual std :: string getCurrentTestName () const {
2013-07-25 07:49:00 +01:00
return m_activeTestCase
? m_activeTestCase -> getTestCaseInfo (). name
2011-02-21 08:50:05 +00:00
: "" ;
2011-01-26 23:23:33 +00:00
}
2012-02-10 08:30:13 +00:00
2012-10-16 08:27:21 +01:00
virtual const AssertionResult * getLastResult () const {
2013-07-03 19:14:59 +01:00
return & m_lastResult ;
2012-02-10 08:30:13 +00:00
}
2012-06-01 19:40:27 +01:00
2014-08-22 19:33:28 +01:00
virtual void handleFatalErrorCondition ( std :: string const & message ) {
ResultBuilder resultBuilder = makeUnexpectedResultBuilder ();
resultBuilder . setResultType ( ResultWas :: FatalErrorCondition );
resultBuilder << message ;
resultBuilder . captureExpression ();
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 ,
"" ,
"" ,
false ) );
m_totals . testCases . failed ++ ;
testGroupEnded ( "" , m_totals , 1 , 1 );
m_reporter -> testRunEnded ( TestRunStats ( m_runInfo , m_totals , false ) );
}
2012-08-23 20:08:50 +01:00
public :
// !TBD We need to do this another way!
2012-06-01 19:40:27 +01:00
bool aborting () const {
2013-05-28 18:51:53 +01:00
return m_totals . assertions . failed == static_cast < std :: size_t > ( m_config -> abortAfter () );
2012-06-01 19:40:27 +01:00
}
2012-08-23 20:08:50 +01:00
private :
2012-05-16 08:02:20 +01:00
void runCurrentTest ( std :: string & redirectedCout , std :: string & redirectedCerr ) {
2013-07-25 07:49:00 +01:00
TestCaseInfo const & testCaseInfo = m_activeTestCase -> getTestCaseInfo ();
2014-07-09 07:39:57 +01:00
SectionInfo testCaseSection ( testCaseInfo . lineInfo , testCaseInfo . name , testCaseInfo . description );
2013-07-24 19:13:08 +01:00
m_reporter -> sectionStarting ( testCaseSection );
2013-07-26 19:19:44 +01:00
Counts prevAssertions = m_totals . assertions ;
2013-08-07 18:56:35 +01:00
double duration = 0 ;
2012-05-16 08:02:20 +01:00
try {
2013-07-24 19:13:08 +01:00
m_lastAssertionInfo = AssertionInfo ( "TEST_CASE" , testCaseInfo . lineInfo , "" , ResultDisposition :: Normal );
2013-07-03 19:14:59 +01:00
2015-07-02 23:02:35 +01:00
seedRng ( * m_config );
2015-11-04 18:01:28 +00:00
2013-08-07 18:56:35 +01:00
Timer timer ;
timer . start ();
2012-11-30 19:15:23 +00:00
if ( m_reporter -> getPreferences (). shouldRedirectStdOut ) {
2014-10-02 19:08:19 +01:00
StreamRedirect coutRedir ( Catch :: cout (), redirectedCout );
StreamRedirect cerrRedir ( Catch :: cerr (), redirectedCerr );
2014-08-22 08:07:39 +01:00
invokeActiveTestCase ();
2012-02-17 09:28:21 +00:00
}
2012-05-16 08:02:20 +01:00
else {
2014-08-22 08:07:39 +01:00
invokeActiveTestCase ();
2012-02-17 09:28:21 +00:00
}
2013-08-07 18:56:35 +01:00
duration = timer . getElapsedSeconds ();
2011-01-19 08:52:25 +00:00
}
2012-05-16 08:02:20 +01:00
catch ( TestFailureException & ) {
2011-01-19 08:52:25 +00:00
// This just means the test was aborted due to failure
}
2012-05-16 08:02:20 +01:00
catch (...) {
2014-08-22 08:07:39 +01:00
makeUnexpectedResultBuilder (). useActiveException ();
2011-01-19 08:52:25 +00:00
}
2015-11-02 19:21:46 +00:00
m_testCaseTracker -> close ();
2014-08-22 19:33:28 +01:00
handleUnfinishedSections ();
2013-02-04 00:05:16 +00:00
m_messages . clear ();
2013-07-26 19:19:44 +01:00
Counts assertions = m_totals . assertions - prevAssertions ;
2013-07-26 19:26:08 +01:00
bool missingAssertions = testForMissingAssertions ( assertions );
2013-07-26 19:19:44 +01:00
2014-07-03 08:09:57 +01:00
if ( testCaseInfo . okToFail () ) {
std :: swap ( assertions . failedButOk , assertions . failed );
m_totals . assertions . failed -= assertions . failedButOk ;
m_totals . assertions . failedButOk += assertions . failedButOk ;
}
2013-08-07 18:56:35 +01:00
SectionStats testCaseSectionStats ( testCaseSection , assertions , duration , missingAssertions );
2013-07-24 19:13:08 +01:00
m_reporter -> sectionEnded ( testCaseSectionStats );
2011-01-19 08:52:25 +00:00
}
2012-05-10 21:46:46 +01:00
2014-08-22 08:07:39 +01:00
void invokeActiveTestCase () {
FatalConditionHandler fatalConditionHandler ; // Handle signals
m_activeTestCase -> invoke ();
2014-10-02 18:28:45 +01:00
fatalConditionHandler . reset ();
2014-08-22 08:07:39 +01:00
}
2010-11-09 23:24:00 +00:00
private :
2014-08-22 19:33:28 +01:00
ResultBuilder makeUnexpectedResultBuilder () const {
return ResultBuilder ( m_lastAssertionInfo . macroName . c_str (),
m_lastAssertionInfo . lineInfo ,
m_lastAssertionInfo . capturedExpression . c_str (),
m_lastAssertionInfo . resultDisposition );
}
2015-11-04 18:01:28 +00:00
2014-08-22 19:33:28 +01:00
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.
2015-09-26 18:12:21 -07:00
for ( std :: vector < SectionEndInfo >:: const_reverse_iterator it = m_unfinishedSections . rbegin (),
2014-08-22 19:33:28 +01:00
itEnd = m_unfinishedSections . rend ();
it != itEnd ;
++ it )
2015-09-26 18:12:21 -07:00
sectionEnded ( * it );
2014-08-22 19:33:28 +01:00
m_unfinishedSections . clear ();
}
2012-12-01 23:54:17 +00:00
TestRunInfo m_runInfo ;
2012-05-21 18:52:09 +01:00
IMutableContext & m_context ;
2013-07-25 07:49:00 +01:00
TestCase const * m_activeTestCase ;
2015-11-02 19:21:46 +00:00
ITracker * m_testCaseTracker ;
ITracker * m_currentSectionTracker ;
2012-10-16 08:27:21 +01:00
AssertionResult m_lastResult ;
2010-12-31 20:49:58 +00:00
2013-05-28 18:51:53 +01:00
Ptr < IConfig const > m_config ;
2012-02-23 08:49:52 +00:00
Totals m_totals ;
2012-11-30 19:15:23 +00:00
Ptr < IStreamingReporter > m_reporter ;
2013-02-02 19:58:04 +00:00
std :: vector < MessageInfo > m_messages ;
2012-11-04 21:09:22 +00:00
AssertionInfo m_lastAssertionInfo ;
2015-09-26 18:12:21 -07:00
std :: vector < SectionEndInfo > m_unfinishedSections ;
2015-11-02 19:21:46 +00:00
std :: vector < ITracker *> m_activeSections ;
TrackerContext m_trackerContext ;
2010-11-09 23:24:00 +00:00
};
2013-07-03 19:14:59 +01:00
2014-05-28 18:53:01 +01:00
IResultCapture & getResultCapture () {
if ( IResultCapture * capture = getCurrentContext (). getResultCapture () )
return * capture ;
else
throw std :: logic_error ( "No result capture instance" );
}
2012-05-21 18:52:09 +01:00
} // end namespace Catch
2010-11-09 23:24:00 +00:00
2012-09-17 01:42:29 -04:00
#endif // TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED