2011-12-28 11:23:32 +01:00
/*
2010-11-10 00:24:00 +01: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 07:42:29 +02:00
# ifndef TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
# define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
2010-11-10 00:24:00 +01:00
2011-01-11 10:13:31 +01:00
# include "catch_interfaces_runner.h"
2010-12-31 23:46:51 +01:00
# include "catch_interfaces_reporter.h"
2012-05-11 09:16:39 +02:00
# include "catch_interfaces_exception.h"
2011-01-01 01:29:58 +01:00
# include "catch_config.hpp"
2011-01-05 22:16:54 +01:00
# include "catch_test_registry.hpp"
2012-08-14 20:30:30 +02:00
# include "catch_test_case_info.h"
2010-11-10 00:24:00 +01:00
# include "catch_capture.hpp"
2012-02-23 09:49:52 +01:00
# include "catch_totals.hpp"
2012-05-05 20:32:52 +02:00
# include "catch_running_test.hpp"
2012-08-14 20:35:30 +02:00
# include "catch_test_spec.h"
2010-11-10 00:24:00 +01:00
2011-02-08 09:42:05 +01:00
# include <set>
# include <string>
2012-05-16 09:02:20 +02:00
namespace Catch {
class StreamRedirect {
2011-02-21 09:50:05 +01:00
public :
2012-05-16 09:02:20 +02:00
StreamRedirect ( std : : ostream & stream , std : : string & targetString )
2011-02-21 09:50:05 +01:00
: m_stream ( stream ) ,
m_prevBuf ( stream . rdbuf ( ) ) ,
2012-05-16 09:02:20 +02:00
m_targetString ( targetString )
2011-02-21 09:50:05 +01:00
{
stream . rdbuf ( m_oss . rdbuf ( ) ) ;
}
2012-05-16 09:02:20 +02:00
~ StreamRedirect ( ) {
2011-12-28 11:23:32 +01:00
m_targetString + = m_oss . str ( ) ;
2011-02-21 09:50:05 +01:00
m_stream . rdbuf ( m_prevBuf ) ;
}
private :
std : : ostream & m_stream ;
std : : streambuf * m_prevBuf ;
std : : ostringstream m_oss ;
std : : string & m_targetString ;
} ;
2012-11-04 22:09:22 +01:00
2011-01-28 19:56:26 +01:00
///////////////////////////////////////////////////////////////////////////
2012-05-16 09:02:20 +02:00
class Runner : public IResultCapture , public IRunner {
2010-12-30 00:18:16 +01:00
Runner ( const Runner & ) ;
void operator = ( const Runner & ) ;
2010-11-10 00:24:00 +01:00
public :
2011-01-11 20:48:48 +01:00
2012-11-30 20:15:23 +01:00
explicit Runner ( const Config & config , const Ptr < IStreamingReporter > & reporter )
2012-12-02 00:54:17 +01:00
: m_runInfo ( config . data ( ) . name ) ,
m_context ( getCurrentMutableContext ( ) ) ,
2012-05-21 19:52:09 +02:00
m_runningTest ( NULL ) ,
2011-02-21 09:50:05 +01:00
m_config ( config ) ,
2012-11-30 20:15:23 +01:00
m_reporter ( reporter ) ,
2012-05-21 19:52:09 +02:00
m_prevRunner ( & m_context . getRunner ( ) ) ,
2012-06-08 09:22:56 +02:00
m_prevResultCapture ( & m_context . getResultCapture ( ) ) ,
m_prevConfig ( m_context . getConfig ( ) )
2010-11-10 00:24:00 +01:00
{
2012-05-21 19:52:09 +02:00
m_context . setRunner ( this ) ;
2012-06-05 21:50:47 +02:00
m_context . setConfig ( & m_config ) ;
2012-05-21 19:52:09 +02:00
m_context . setResultCapture ( this ) ;
2012-12-02 00:54:17 +01:00
m_reporter - > testRunStarting ( m_runInfo ) ;
2010-11-10 00:24:00 +01:00
}
2012-08-13 08:46:10 +02:00
virtual ~ Runner ( ) {
2013-01-03 10:04:46 +01:00
m_reporter - > testRunEnded ( TestRunStats ( m_runInfo , m_totals , aborting ( ) ) ) ;
2012-05-21 19:52:09 +02:00
m_context . setRunner ( m_prevRunner ) ;
2012-06-05 21:50:47 +02:00
m_context . setConfig ( NULL ) ;
2012-05-21 19:52:09 +02:00
m_context . setResultCapture ( m_prevResultCapture ) ;
2012-06-08 09:22:56 +02:00
m_context . setConfig ( m_prevConfig ) ;
2010-11-10 00:24:00 +01:00
}
2012-07-16 09:58:28 +02:00
2013-01-13 22:51:44 +01: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 10:13:27 +01:00
}
2013-01-13 22:51:44 +01: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 10:13:27 +01:00
}
2013-01-13 22:51:44 +01:00
Totals runMatching ( const std : : string & testSpec , std : : size_t groupIndex , std : : size_t groupsCount ) {
2012-07-16 09:58:28 +02:00
2012-11-22 20:17:20 +01:00
std : : vector < TestCase > matchingTests = getRegistryHub ( ) . getTestCaseRegistry ( ) . getMatchingTestCases ( testSpec ) ;
2012-08-15 20:12:51 +02:00
2012-08-23 21:08:50 +02:00
Totals totals ;
2012-11-25 22:43:36 +01:00
2013-01-13 22:51:44 +01:00
testGroupStarting ( testSpec , groupIndex , groupsCount ) ;
2012-08-15 20:12:51 +02:00
2012-11-22 20:17:20 +01:00
std : : vector < TestCase > : : const_iterator it = matchingTests . begin ( ) ;
std : : vector < TestCase > : : const_iterator itEnd = matchingTests . end ( ) ;
2012-08-23 21:08:50 +02:00
for ( ; it ! = itEnd ; + + it )
totals + = runTest ( * it ) ;
2012-08-15 20:12:51 +02:00
2013-01-13 22:51:44 +01:00
testGroupEnded ( testSpec , totals , groupIndex , groupsCount ) ;
2012-08-15 20:12:51 +02:00
return totals ;
2010-11-10 00:24:00 +01:00
}
2012-08-15 20:12:51 +02:00
2012-11-25 12:19:55 +01:00
Totals runTest ( const TestCase & testCase ) {
2012-02-23 09:49:52 +01:00
Totals prevTotals = m_totals ;
2011-01-19 20:30:01 +01:00
std : : string redirectedCout ;
std : : string redirectedCerr ;
2012-11-25 12:19:55 +01:00
TestCaseInfo testInfo = testCase . getTestCaseInfo ( ) ;
2012-11-25 22:43:36 +01:00
2012-11-30 20:15:23 +01:00
m_reporter - > testCaseStarting ( testInfo ) ;
2011-01-19 20:30:01 +01:00
2012-11-29 10:05:51 +01:00
m_runningTest = new RunningTest ( testCase ) ;
2010-11-30 07:48:21 +01:00
2012-05-16 09:02:20 +02:00
do {
do {
2011-01-27 00:23:33 +01:00
runCurrentTest ( redirectedCout , redirectedCerr ) ;
}
2012-06-01 20:40:27 +02:00
while ( m_runningTest - > hasUntestedSections ( ) & & ! aborting ( ) ) ;
2010-11-10 00:24:00 +01:00
}
2012-06-01 20:40:27 +02:00
while ( getCurrentContext ( ) . advanceGeneratorsForCurrentTest ( ) & & ! aborting ( ) ) ;
2011-01-19 09:52:25 +01:00
2012-11-21 09:19:23 +01:00
Totals deltaTotals = m_totals . delta ( prevTotals ) ;
2012-11-27 00:28:00 +01:00
bool missingAssertions = false ;
2012-11-21 09:19:23 +01:00
if ( deltaTotals . assertions . total ( ) = = 0 & &
( m_config . data ( ) . warnings & ConfigData : : WarnAbout : : NoAssertions ) ) {
m_totals . assertions . failed + + ;
deltaTotals = m_totals . delta ( prevTotals ) ;
2012-11-27 00:28:00 +01:00
missingAssertions = true ;
2012-11-21 09:19:23 +01:00
}
2012-11-27 00:28:00 +01:00
2012-11-21 09:19:23 +01:00
m_totals . testCases + = deltaTotals . testCases ;
2013-01-03 10:04:46 +01:00
m_reporter - > testCaseEnded ( TestCaseStats ( testInfo ,
deltaTotals ,
redirectedCout ,
redirectedCerr ,
missingAssertions ,
aborting ( ) ) ) ;
2012-11-21 09:19:23 +01:00
2011-02-21 09:50:05 +01:00
delete m_runningTest ;
m_runningTest = NULL ;
2011-01-19 20:30:01 +01:00
2012-08-15 20:12:51 +02:00
return deltaTotals ;
2010-11-10 00:24:00 +01:00
}
2012-02-17 20:50:59 +01:00
2012-06-05 21:50:47 +02:00
const Config & config ( ) const {
return m_config ;
}
2011-01-11 10:13:31 +01:00
private : // IResultCapture
2010-12-31 21:49:58 +01:00
2013-02-02 20:58:04 +01:00
virtual void acceptMessage ( const MessageBuilder & messageBuilder ) {
m_messages . push_back ( messageBuilder . build ( ) ) ;
}
2012-10-29 20:55:13 +01:00
virtual ResultAction : : Value acceptExpression ( const ExpressionResultBuilder & assertionResult , const AssertionInfo & assertionInfo ) {
2012-11-04 22:09:22 +01:00
m_lastAssertionInfo = assertionInfo ;
return actOnCurrentResult ( assertionResult . buildResult ( assertionInfo ) ) ;
2010-12-31 21:49:58 +01:00
}
2013-02-02 20:58:04 +01:00
virtual void assertionEnded ( const AssertionResult & result ) {
2012-05-16 09:02:20 +02:00
if ( result . getResultType ( ) = = ResultWas : : Ok ) {
2012-02-23 09:49:52 +01:00
m_totals . assertions . passed + + ;
2010-12-27 23:18:33 +01:00
}
2012-11-13 10:44:52 +01:00
else if ( ! result . isOk ( ) ) {
2012-02-23 09:49:52 +01:00
m_totals . assertions . failed + + ;
2010-12-27 23:05:13 +01:00
}
2010-12-27 23:18:33 +01:00
2013-02-02 21:36:36 +01:00
m_reporter - > assertionEnded ( AssertionStats ( result , m_messages , m_totals ) ) ;
2012-11-17 18:22:37 +01:00
2013-02-02 21:36:36 +01:00
// Reset working state
2013-02-02 20:58:04 +01:00
m_lastAssertionInfo = AssertionInfo ( " " , m_lastAssertionInfo . lineInfo , " {Unknown expression after the reported line} " , m_lastAssertionInfo . resultDisposition ) ;
m_messages . clear ( ) ;
2010-11-10 00:24:00 +01:00
}
2012-06-01 20:40:27 +02:00
2012-05-16 09:02:20 +02:00
virtual bool sectionStarted (
2012-11-30 09:58:46 +01:00
SectionInfo const & sectionInfo ,
2012-02-23 09:57:51 +01:00
Counts & assertions
2011-01-11 20:48:48 +01:00
)
2010-11-29 20:40:44 +01:00
{
2011-04-21 20:43:55 +02:00
std : : ostringstream oss ;
2012-11-30 09:58:46 +01:00
oss < < sectionInfo . name < < " @ " < < sectionInfo . lineInfo ;
2011-04-21 20:43:55 +02:00
2012-11-04 22:09:22 +01:00
2011-04-21 20:43:55 +02:00
if ( ! m_runningTest - > addSection ( oss . str ( ) ) )
2011-01-19 09:52:25 +01:00
return false ;
2012-11-30 09:58:46 +01:00
m_lastAssertionInfo . lineInfo = sectionInfo . lineInfo ;
2012-11-04 22:39:16 +01:00
2012-11-30 20:15:23 +01:00
m_reporter - > sectionStarting ( sectionInfo ) ;
2012-11-29 10:05:51 +01:00
2012-02-23 09:57:51 +01:00
assertions = m_totals . assertions ;
2010-11-29 23:52:27 +01:00
2010-11-29 20:40:44 +01:00
return true ;
}
2012-11-30 09:58:46 +01:00
virtual void sectionEnded ( SectionInfo const & info , Counts const & prevAssertions ) {
2013-02-19 20:45:09 +01:00
if ( std : : uncaught_exception ( ) ) {
m_unfinishedSections . push_back ( UnfinishedSections ( info , prevAssertions ) ) ;
return ;
}
2012-08-31 09:10:36 +02:00
Counts assertions = m_totals . assertions - prevAssertions ;
2012-11-30 09:58:46 +01:00
bool missingAssertions = false ;
2012-11-21 09:49:20 +01:00
if ( assertions . total ( ) = = 0 & &
2012-08-31 09:10:36 +02:00
( m_config . data ( ) . warnings & ConfigData : : WarnAbout : : NoAssertions ) & &
! m_runningTest - > isBranchSection ( ) ) {
m_totals . assertions . failed + + ;
assertions . failed + + ;
2012-11-30 09:58:46 +01:00
missingAssertions = true ;
2012-08-31 09:10:36 +02:00
}
2013-03-04 12:19:15 +01:00
m_runningTest - > endSection ( info . name , false ) ;
2012-11-30 09:58:46 +01:00
2013-01-03 10:04:46 +01:00
m_reporter - > sectionEnded ( SectionStats ( info , assertions , missingAssertions ) ) ;
2013-02-02 20:58:04 +01:00
m_messages . clear ( ) ;
2010-11-29 20:40:44 +01:00
}
2010-12-27 12:09:34 +01:00
2013-02-02 20:58:04 +01:00
virtual void pushScopedMessage ( ScopedMessageBuilder const & _builder ) {
m_messages . push_back ( _builder . build ( ) ) ;
}
virtual void popScopedMessage ( ScopedMessageBuilder const & _builder ) {
m_messages . erase ( std : : remove ( m_messages . begin ( ) , m_messages . end ( ) , _builder ) , m_messages . end ( ) ) ;
}
2011-01-11 20:48:48 +01:00
2013-02-02 20:58:04 +01:00
virtual bool shouldDebugBreak ( ) const {
2010-12-27 21:49:19 +01:00
return m_config . shouldDebugBreak ( ) ;
}
2011-01-27 00:23:33 +01:00
2012-05-16 09:02:20 +02:00
virtual std : : string getCurrentTestName ( ) const {
2011-02-21 09:50:05 +01:00
return m_runningTest
2012-11-25 12:19:55 +01:00
? m_runningTest - > getTestCase ( ) . getTestCaseInfo ( ) . name
2011-02-21 09:50:05 +01:00
: " " ;
2011-01-27 00:23:33 +01:00
}
2012-02-10 09:30:13 +01:00
2012-10-16 09:27:21 +02:00
virtual const AssertionResult * getLastResult ( ) const {
2012-02-10 09:30:13 +01:00
return & m_lastResult ;
}
2012-06-01 20:40:27 +02:00
2012-08-23 21:08:50 +02:00
public :
// !TBD We need to do this another way!
2012-06-01 20:40:27 +02:00
bool aborting ( ) const {
2012-06-03 00:08:07 +02:00
return m_totals . assertions . failed = = static_cast < std : : size_t > ( m_config . getCutoff ( ) ) ;
2012-06-01 20:40:27 +02:00
}
2012-08-23 21:08:50 +02:00
private :
2012-11-04 22:09:22 +01:00
ResultAction : : Value actOnCurrentResult ( const AssertionResult & result ) {
m_lastResult = result ;
2013-02-02 20:58:04 +01:00
assertionEnded ( m_lastResult ) ;
2012-10-05 19:35:01 +02:00
2012-06-01 20:40:27 +02:00
ResultAction : : Value action = ResultAction : : None ;
2012-11-13 10:44:52 +01:00
if ( ! m_lastResult . isOk ( ) ) {
2012-06-01 20:40:27 +02:00
action = ResultAction : : Failed ;
if ( shouldDebugBreak ( ) )
action = ( ResultAction : : Value ) ( action | ResultAction : : Debug ) ;
if ( aborting ( ) )
action = ( ResultAction : : Value ) ( action | ResultAction : : Abort ) ;
}
return action ;
2011-03-15 19:01:44 +01:00
}
2012-05-16 09:02:20 +02:00
void runCurrentTest ( std : : string & redirectedCout , std : : string & redirectedCerr ) {
try {
2012-11-25 12:19:55 +01:00
m_lastAssertionInfo = AssertionInfo ( " TEST_CASE " , m_runningTest - > getTestCase ( ) . getTestCaseInfo ( ) . lineInfo , " " , ResultDisposition : : Normal ) ;
2011-02-21 09:50:05 +01:00
m_runningTest - > reset ( ) ;
2013-02-04 01:05:16 +01:00
2012-11-30 20:15:23 +01:00
if ( m_reporter - > getPreferences ( ) . shouldRedirectStdOut ) {
2012-02-17 10:28:21 +01:00
StreamRedirect coutRedir ( std : : cout , redirectedCout ) ;
StreamRedirect cerrRedir ( std : : cerr , redirectedCerr ) ;
2012-11-22 20:17:20 +01:00
m_runningTest - > getTestCase ( ) . invoke ( ) ;
2012-02-17 10:28:21 +01:00
}
2012-05-16 09:02:20 +02:00
else {
2012-11-22 20:17:20 +01:00
m_runningTest - > getTestCase ( ) . invoke ( ) ;
2012-02-17 10:28:21 +01:00
}
2011-02-21 09:50:05 +01:00
m_runningTest - > ranToCompletion ( ) ;
2011-01-19 09:52:25 +01:00
}
2012-05-16 09:02:20 +02:00
catch ( TestFailureException & ) {
2011-01-19 09:52:25 +01:00
// This just means the test was aborted due to failure
}
2012-05-16 09:02:20 +02:00
catch ( . . . ) {
2012-11-04 22:09:22 +01:00
ExpressionResultBuilder exResult ( ResultWas : : ThrewException ) ;
exResult < < translateActiveException ( ) ;
actOnCurrentResult ( exResult . buildResult ( m_lastAssertionInfo ) ) ;
2011-01-19 09:52:25 +01:00
}
2013-02-19 20:45:09 +01:00
for ( std : : vector < UnfinishedSections > : : const_iterator it = m_unfinishedSections . begin ( ) ,
itEnd = m_unfinishedSections . end ( ) ;
it ! = itEnd ;
+ + it )
sectionEnded ( it - > info , it - > prevAssertions ) ;
m_unfinishedSections . clear ( ) ;
2013-02-04 01:05:16 +01:00
m_messages . clear ( ) ;
2011-01-19 09:52:25 +01:00
}
2012-05-10 22:46:46 +02:00
2010-11-10 00:24:00 +01:00
private :
2013-02-19 20:45:09 +01:00
struct UnfinishedSections {
UnfinishedSections ( SectionInfo const & _info , Counts const & _prevAssertions )
: info ( _info ) , prevAssertions ( _prevAssertions )
{ }
SectionInfo info ;
Counts prevAssertions ;
} ;
2012-12-02 00:54:17 +01:00
TestRunInfo m_runInfo ;
2012-05-21 19:52:09 +02:00
IMutableContext & m_context ;
2011-02-21 09:50:05 +01:00
RunningTest * m_runningTest ;
2012-10-16 09:27:21 +02:00
AssertionResult m_lastResult ;
2010-12-31 21:49:58 +01:00
2011-01-01 01:20:14 +01:00
const Config & m_config ;
2012-02-23 09:49:52 +01:00
Totals m_totals ;
2012-11-30 20:15:23 +01:00
Ptr < IStreamingReporter > m_reporter ;
2013-02-02 20:58:04 +01:00
std : : vector < MessageInfo > m_messages ;
2011-01-14 09:26:58 +01:00
IRunner * m_prevRunner ;
IResultCapture * m_prevResultCapture ;
2012-06-08 09:22:56 +02:00
const IConfig * m_prevConfig ;
2012-11-04 22:09:22 +01:00
AssertionInfo m_lastAssertionInfo ;
2013-02-19 20:45:09 +01:00
std : : vector < UnfinishedSections > m_unfinishedSections ;
2010-11-10 00:24:00 +01:00
} ;
2012-05-21 19:52:09 +02:00
} // end namespace Catch
2010-11-10 00:24:00 +01:00
2012-09-17 07:42:29 +02:00
# endif // TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED