Reporter interface uses value types instead of shared ptrs again

This commit is contained in:
Phil Nash 2013-01-03 09:04:46 +00:00
parent 7409075302
commit bcf722eb81
6 changed files with 178 additions and 83 deletions

1
.gitignore vendored
View File

@ -18,3 +18,4 @@ UpgradeLog.XML
projects/XCode4/iOSTest/Build/Intermediates/PrecompiledHeaders projects/XCode4/iOSTest/Build/Intermediates/PrecompiledHeaders
projects/XCode4/iOSTest/Build/Products/Debug-iphonesimulator/iOSTest.app.dSYM/Contents/Resources/DWARF projects/XCode4/iOSTest/Build/Products/Debug-iphonesimulator/iOSTest.app.dSYM/Contents/Resources/DWARF
projects/XCode4/iOSTest/Build projects/XCode4/iOSTest/Build
projects/XCode4/CatchSelfTest/DerivedData

View File

@ -56,9 +56,12 @@ namespace Catch {
TestGroupStats::~TestGroupStats() {} TestGroupStats::~TestGroupStats() {}
TestRunStats::~TestRunStats() {} TestRunStats::~TestRunStats() {}
ThreadedSectionInfo::~ThreadedSectionInfo() {} ThreadedSectionInfo::~ThreadedSectionInfo() {}
TestGroupNode::~TestGroupNode() {}
TestRunNode::~TestRunNode() {}
BasicReporter::~BasicReporter() {} BasicReporter::~BasicReporter() {}
AccumulatingReporter::~AccumulatingReporter() {} StreamingReporterBase::~StreamingReporterBase() {}
CumulativeReporterBase::~CumulativeReporterBase() {}
ConsoleReporter::~ConsoleReporter() {} ConsoleReporter::~ConsoleReporter() {}
IRunner::~IRunner() {} IRunner::~IRunner() {}
IMutableContext::~IMutableContext() {} IMutableContext::~IMutableContext() {}

View File

@ -80,7 +80,7 @@ namespace Catch
bool printed; bool printed;
}; };
struct AssertionStats : SharedImpl<> { struct AssertionStats {
AssertionStats( AssertionResult const& _assertionResult, AssertionStats( AssertionResult const& _assertionResult,
Totals const& _totals ) Totals const& _totals )
: assertionResult( _assertionResult ), : assertionResult( _assertionResult ),
@ -92,7 +92,7 @@ namespace Catch
Totals totals; Totals totals;
}; };
struct SectionStats : SharedImpl<> { struct SectionStats {
SectionStats( SectionInfo const& _sectionInfo, SectionStats( SectionInfo const& _sectionInfo,
Counts const& _assertions, Counts const& _assertions,
bool _missingAssertions ) bool _missingAssertions )
@ -107,7 +107,7 @@ namespace Catch
bool missingAssertions; bool missingAssertions;
}; };
struct TestCaseStats : SharedImpl<> { struct TestCaseStats {
TestCaseStats( TestCaseInfo const& _testInfo, TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals, Totals const& _totals,
std::string const& _stdOut, std::string const& _stdOut,
@ -131,7 +131,7 @@ namespace Catch
bool aborting; bool aborting;
}; };
struct TestGroupStats : SharedImpl<> { struct TestGroupStats {
TestGroupStats( GroupInfo const& _groupInfo, TestGroupStats( GroupInfo const& _groupInfo,
Totals const& _totals, Totals const& _totals,
bool _aborting ) bool _aborting )
@ -139,6 +139,10 @@ namespace Catch
totals( _totals ), totals( _totals ),
aborting( _aborting ) aborting( _aborting )
{} {}
TestGroupStats( GroupInfo const& _groupInfo )
: groupInfo( _groupInfo ),
aborting( false )
{}
virtual ~TestGroupStats(); virtual ~TestGroupStats();
GroupInfo groupInfo; GroupInfo groupInfo;
@ -146,7 +150,7 @@ namespace Catch
bool aborting; bool aborting;
}; };
struct TestRunStats : SharedImpl<> { struct TestRunStats {
TestRunStats( TestRunInfo const& _runInfo, TestRunStats( TestRunInfo const& _runInfo,
Totals const& _totals, Totals const& _totals,
bool _aborting ) bool _aborting )
@ -154,8 +158,13 @@ namespace Catch
totals( _totals ), totals( _totals ),
aborting( _aborting ) aborting( _aborting )
{} {}
TestRunStats( TestRunStats const& _other )
: runInfo( _other.runInfo ),
totals( _other.totals ),
aborting( _other.aborting )
{}
virtual ~TestRunStats(); virtual ~TestRunStats();
TestRunInfo runInfo; TestRunInfo runInfo;
Totals totals; Totals totals;
bool aborting; bool aborting;
@ -178,25 +187,21 @@ namespace Catch
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
virtual void assertionEnded( Ptr<AssertionStats const> const& assertionStats ) = 0; virtual void assertionEnded( AssertionStats const& assertionStats ) = 0;
virtual void sectionEnded( Ptr<SectionStats const> const& sectionStats ) = 0; virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( Ptr<TestCaseStats const> const& testCaseStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( Ptr<TestGroupStats const> const& testGroupStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
virtual void testRunEnded( Ptr<TestRunStats const> const& testRunStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
}; };
// !TBD: Derived helper that implements the streaming interface but holds the stats
// - declares a new interface where methods are called at the end of each event
// - this would be used by the JUnit reporter, for example.
// - it may be used by the basic reporter, too, but that would clear down the stack
// as it goes
struct AccumulatingReporter : SharedImpl<IStreamingReporter> {
AccumulatingReporter( ReporterConfig const& _config ) struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
StreamingReporterBase( ReporterConfig const& _config )
: m_config( _config ), : m_config( _config ),
stream( _config.stream() ) stream( _config.stream() )
{} {}
virtual ~AccumulatingReporter(); virtual ~StreamingReporterBase();
virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
testRunInfo = _testRunInfo; testRunInfo = _testRunInfo;
@ -221,17 +226,17 @@ namespace Catch
} }
} }
virtual void sectionEnded( Ptr<SectionStats const> const& /* _sectionStats */ ) { virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
currentSectionInfo = currentSectionInfo->parent; currentSectionInfo = currentSectionInfo->parent;
unusedSectionInfo = currentSectionInfo; unusedSectionInfo = currentSectionInfo;
} }
virtual void testCaseEnded( Ptr<TestCaseStats const> const& /* _testCaseStats */ ) { virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
unusedTestCaseInfo.reset(); unusedTestCaseInfo.reset();
} }
virtual void testGroupEnded( Ptr<TestGroupStats const> const& /* _testGroupStats */ ) { virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
unusedGroupInfo.reset(); unusedGroupInfo.reset();
} }
virtual void testRunEnded( Ptr<TestRunStats const> const& /* _testRunStats */ ) { virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
currentSectionInfo.reset(); currentSectionInfo.reset();
unusedSectionInfo.reset(); unusedSectionInfo.reset();
unusedTestCaseInfo.reset(); unusedTestCaseInfo.reset();
@ -249,6 +254,92 @@ namespace Catch
std::ostream& stream; std::ostream& stream;
}; };
struct TestGroupNode : TestGroupStats {
TestGroupNode( TestGroupStats const& _stats ) : TestGroupStats( _stats ) {}
// TestGroupNode( GroupInfo const& _info ) : TestGroupStats( _stats ) {}
~TestGroupNode();
};
struct TestRunNode : TestRunStats {
TestRunNode( TestRunStats const& _stats ) : TestRunStats( _stats ) {}
~TestRunNode();
std::vector<TestGroupNode> groups;
};
// !TBD: Derived helper that implements the streaming interface but holds the stats
// - declares a new interface where methods are called at the end of each event
// - this would be used by the JUnit reporter, for example.
// - it may be used by the basic reporter, too, but that would clear down the stack
// as it goes
struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
CumulativeReporterBase( ReporterConfig const& _config )
: m_config( _config ),
stream( _config.stream() )
{}
virtual ~CumulativeReporterBase();
virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
// testRunInfo = _testRunInfo;
}
virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
testGroupNode = TestGroupNode( _groupInfo );
}
virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
// unusedTestCaseInfo = _testInfo;
}
virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
// Ptr<ThreadedSectionInfo> sectionInfo = new ThreadedSectionInfo( _sectionInfo );
// unusedSectionInfo = sectionInfo;
// if( !currentSectionInfo ) {
// currentSectionInfo = sectionInfo;
// }
// else {
// currentSectionInfo->children.push_back( sectionInfo );
// sectionInfo->parent = currentSectionInfo;
// currentSectionInfo = sectionInfo;
// }
}
virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
// currentSectionInfo = currentSectionInfo->parent;
// unusedSectionInfo = currentSectionInfo;
}
virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
// unusedTestCaseInfo.reset();
}
virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
// testGroupNode-> // populate
// Ptr<TestGroupNode> node ( new TestGroupNode( _testGroupStats ) );
// unusedGroupInfo.reset();
}
virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
// currentSectionInfo.reset();
// unusedSectionInfo.reset();
// unusedTestCaseInfo.reset();
// unusedGroupInfo.reset();
// testRunInfo.reset();
}
ReporterConfig m_config;
// Option<TestRunInfo> testRunInfo;
// Option<GroupInfo> unusedGroupInfo;
// Option<TestCaseInfo> unusedTestCaseInfo;
// Ptr<ThreadedSectionInfo> unusedSectionInfo;
// Ptr<ThreadedSectionInfo> currentSectionInfo;
// bool currentSectionOpen;
// Ptr<TestGroupNode> testGroupNode;
Option<TestGroupNode> testGroupNode;
std::ostream& stream;
};
// Deprecated // Deprecated
@ -302,30 +393,30 @@ namespace Catch
// Not on legacy interface // Not on legacy interface
} }
virtual void assertionEnded( Ptr<AssertionStats const> const& assertionStats ) { virtual void assertionEnded( AssertionStats const& assertionStats ) {
m_legacyReporter->Result( assertionStats->assertionResult ); m_legacyReporter->Result( assertionStats.assertionResult );
} }
virtual void sectionEnded( Ptr<SectionStats const> const& sectionStats ) { virtual void sectionEnded( SectionStats const& sectionStats ) {
if( sectionStats->missingAssertions ) if( sectionStats.missingAssertions )
m_legacyReporter->NoAssertionsInSection( sectionStats->sectionInfo.name ); m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
m_legacyReporter->EndSection( sectionStats->sectionInfo.name, sectionStats->assertions ); m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
} }
virtual void testCaseEnded( Ptr<TestCaseStats const> const& testCaseStats ) { virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
if( testCaseStats->missingAssertions ) if( testCaseStats.missingAssertions )
m_legacyReporter->NoAssertionsInTestCase( testCaseStats->testInfo.name ); m_legacyReporter->NoAssertionsInTestCase( testCaseStats.testInfo.name );
m_legacyReporter->EndTestCase m_legacyReporter->EndTestCase
( testCaseStats->testInfo, ( testCaseStats.testInfo,
testCaseStats->totals, testCaseStats.totals,
testCaseStats->stdOut, testCaseStats.stdOut,
testCaseStats->stdErr ); testCaseStats.stdErr );
} }
virtual void testGroupEnded( Ptr<TestGroupStats const> const& testGroupStats ) { virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
if( testGroupStats->aborting ) if( testGroupStats.aborting )
m_legacyReporter->Aborted(); m_legacyReporter->Aborted();
m_legacyReporter->EndGroup( testGroupStats->groupInfo.name, testGroupStats->totals ); m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
} }
virtual void testRunEnded( Ptr<TestRunStats const> const& testRunStats ) { virtual void testRunEnded( TestRunStats const& testRunStats ) {
m_legacyReporter->EndTesting( testRunStats->totals ); m_legacyReporter->EndTesting( testRunStats.totals );
} }
private: private:

View File

@ -73,7 +73,7 @@ namespace Catch {
} }
virtual ~Runner() { virtual ~Runner() {
m_reporter->testRunEnded( new TestRunStats( m_runInfo, m_totals, aborting() ) ); m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
m_context.setRunner( m_prevRunner ); m_context.setRunner( m_prevRunner );
m_context.setConfig( NULL ); m_context.setConfig( NULL );
m_context.setResultCapture( m_prevResultCapture ); m_context.setResultCapture( m_prevResultCapture );
@ -84,7 +84,7 @@ namespace Catch {
m_reporter->testGroupStarting( GroupInfo( testSpec ) ); m_reporter->testGroupStarting( GroupInfo( testSpec ) );
} }
void testGroupEnded( std::string const& testSpec, Totals const& totals ) { void testGroupEnded( std::string const& testSpec, Totals const& totals ) {
m_reporter->testGroupEnded( new TestGroupStats( GroupInfo( testSpec ), totals, aborting() ) ); m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec ), totals, aborting() ) );
} }
Totals runMatching( const std::string& testSpec ) { Totals runMatching( const std::string& testSpec ) {
@ -135,12 +135,12 @@ namespace Catch {
m_totals.testCases += deltaTotals.testCases; m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded( new TestCaseStats( testInfo, m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals, deltaTotals,
redirectedCout, redirectedCout,
redirectedCerr, redirectedCerr,
missingAssertions, missingAssertions,
aborting() ) ); aborting() ) );
delete m_runningTest; delete m_runningTest;
@ -171,13 +171,13 @@ namespace Catch {
std::vector<ScopedInfo*>::const_iterator it = m_scopedInfos.begin(); std::vector<ScopedInfo*>::const_iterator it = m_scopedInfos.begin();
std::vector<ScopedInfo*>::const_iterator itEnd = m_scopedInfos.end(); std::vector<ScopedInfo*>::const_iterator itEnd = m_scopedInfos.end();
for(; it != itEnd; ++it ) for(; it != itEnd; ++it )
m_reporter->assertionEnded( new AssertionStats( (*it)->buildResult( m_lastAssertionInfo ), m_totals ) ); m_reporter->assertionEnded( AssertionStats( (*it)->buildResult( m_lastAssertionInfo ), m_totals ) );
} }
{ {
std::vector<AssertionResult>::const_iterator it = m_assertionResults.begin(); std::vector<AssertionResult>::const_iterator it = m_assertionResults.begin();
std::vector<AssertionResult>::const_iterator itEnd = m_assertionResults.end(); std::vector<AssertionResult>::const_iterator itEnd = m_assertionResults.end();
for(; it != itEnd; ++it ) for(; it != itEnd; ++it )
m_reporter->assertionEnded( new AssertionStats( *it, m_totals ) ); m_reporter->assertionEnded( AssertionStats( *it, m_totals ) );
} }
m_assertionResults.clear(); m_assertionResults.clear();
} }
@ -188,7 +188,7 @@ namespace Catch {
m_totals.assertions.info++; m_totals.assertions.info++;
} }
else else
m_reporter->assertionEnded( new AssertionStats( result, m_totals ) ); m_reporter->assertionEnded( AssertionStats( result, m_totals ) );
// Reset AssertionInfo // Reset AssertionInfo
m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after this line}" , m_lastAssertionInfo.resultDisposition ); m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after this line}" , m_lastAssertionInfo.resultDisposition );
@ -228,7 +228,7 @@ namespace Catch {
} }
m_runningTest->endSection( info.name ); m_runningTest->endSection( info.name );
m_reporter->sectionEnded( new SectionStats( info, assertions, missingAssertions ) ); m_reporter->sectionEnded( SectionStats( info, assertions, missingAssertions ) );
} }
virtual void pushScopedInfo( ScopedInfo* scopedInfo ) { virtual void pushScopedInfo( ScopedInfo* scopedInfo ) {

View File

@ -14,9 +14,9 @@
namespace Catch { namespace Catch {
struct ConsoleReporter : AccumulatingReporter { struct ConsoleReporter : StreamingReporterBase {
ConsoleReporter( ReporterConfig const& _config ) ConsoleReporter( ReporterConfig const& _config )
: AccumulatingReporter( _config ), : StreamingReporterBase( _config ),
m_atLeastOneTestCasePrinted( false ) m_atLeastOneTestCasePrinted( false )
{} {}
@ -95,9 +95,9 @@ namespace Catch {
virtual void assertionStarting( AssertionInfo const& ) { virtual void assertionStarting( AssertionInfo const& ) {
} }
virtual void assertionEnded( Ptr<AssertionStats const> const& _assertionStats ) { virtual void assertionEnded( AssertionStats const& _assertionStats ) {
AssertionResult const& result = _assertionStats->assertionResult; AssertionResult const& result = _assertionStats.assertionResult;
// Drop out if result was successful and we're not printing those // Drop out if result was successful and we're not printing those
if( !m_config.includeSuccessfulResults() && result.isOk() ) if( !m_config.includeSuccessfulResults() && result.isOk() )
@ -257,17 +257,17 @@ namespace Catch {
} }
} }
virtual void sectionEnded( Ptr<SectionStats const> const& _sectionStats ) { virtual void sectionEnded( SectionStats const& _sectionStats ) {
resetLastPrintedLine(); resetLastPrintedLine();
if( _sectionStats->missingAssertions ) { if( _sectionStats.missingAssertions ) {
lazyPrint(); lazyPrint();
TextColour colour( TextColour::ResultError ); TextColour colour( TextColour::ResultError );
stream << "\nNo assertions in section, '" << _sectionStats->sectionInfo.name << "'\n" << std::endl; stream << "\nNo assertions in section, '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
} }
if( currentSectionInfo && currentSectionInfo->printed ) { if( currentSectionInfo && currentSectionInfo->printed ) {
printSummarDivider(); printSummarDivider();
stream << "Summary for section '" << _sectionStats->sectionInfo.name << "':\n"; stream << "Summary for section '" << _sectionStats.sectionInfo.name << "':\n";
Counts const& assertions = _sectionStats->assertions; Counts const& assertions = _sectionStats.assertions;
if( assertions.failed ) { if( assertions.failed ) {
TextColour colour( TextColour::ResultError ); TextColour colour( TextColour::ResultError );
printAssertionCounts( "assertion", assertions ); printAssertionCounts( "assertion", assertions );
@ -279,40 +279,40 @@ namespace Catch {
} }
stream << "\n" << std::endl; stream << "\n" << std::endl;
} }
AccumulatingReporter::sectionEnded( _sectionStats ); StreamingReporterBase::sectionEnded( _sectionStats );
} }
virtual void testCaseEnded( Ptr<TestCaseStats const> const& _testCaseStats ) { virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) {
resetLastPrintedLine(); resetLastPrintedLine();
if( _testCaseStats->missingAssertions ) { if( _testCaseStats.missingAssertions ) {
lazyPrint(); lazyPrint();
TextColour colour( TextColour::ResultError ); TextColour colour( TextColour::ResultError );
stream << "\nNo assertions in test case, '" << _testCaseStats->testInfo.name << "'\n" << std::endl; stream << "\nNo assertions in test case, '" << _testCaseStats.testInfo.name << "'\n" << std::endl;
} }
if( !unusedTestCaseInfo ) { if( !unusedTestCaseInfo ) {
m_atLeastOneTestCasePrinted = true; m_atLeastOneTestCasePrinted = true;
printSummarDivider(); printSummarDivider();
stream << "Summary for test case '" << _testCaseStats->testInfo.name << "':\n"; stream << "Summary for test case '" << _testCaseStats.testInfo.name << "':\n";
printTotals( _testCaseStats->totals ); printTotals( _testCaseStats.totals );
stream << "\n" << std::endl; stream << "\n" << std::endl;
} }
AccumulatingReporter::testCaseEnded( _testCaseStats ); StreamingReporterBase::testCaseEnded( _testCaseStats );
} }
virtual void testGroupEnded( Ptr<TestGroupStats const> const& _testGroupStats ) { virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
if( !unusedGroupInfo ) { if( !unusedGroupInfo ) {
printSummarDivider(); printSummarDivider();
stream << "Summary for group '" << _testGroupStats->groupInfo.name << "':\n"; stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
printTotals( _testGroupStats->totals ); printTotals( _testGroupStats.totals );
stream << "\n" << std::endl; stream << "\n" << std::endl;
} }
AccumulatingReporter::testGroupEnded( _testGroupStats ); StreamingReporterBase::testGroupEnded( _testGroupStats );
} }
virtual void testRunEnded( Ptr<TestRunStats const> const& _testRunStats ) { virtual void testRunEnded( TestRunStats const& _testRunStats ) {
if( m_atLeastOneTestCasePrinted ) if( m_atLeastOneTestCasePrinted )
printTotalsDivider(); printTotalsDivider();
stream << "Summary for all tests in '" << _testRunStats->runInfo.name << "':\n"; stream << "Summary for all tests in '" << _testRunStats.runInfo.name << "':\n";
printTotals( _testRunStats->totals ); printTotals( _testRunStats.totals );
stream << "\n" << std::endl; stream << "\n" << std::endl;
AccumulatingReporter::testRunEnded( _testRunStats ); StreamingReporterBase::testRunEnded( _testRunStats );
} }
private: private:

View File

@ -40,11 +40,11 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& ) {} virtual void testCaseStarting( TestCaseInfo const& ) {}
virtual void sectionStarting( SectionInfo const& ) {} virtual void sectionStarting( SectionInfo const& ) {}
virtual void assertionStarting( AssertionInfo const& ) {} virtual void assertionStarting( AssertionInfo const& ) {}
virtual void assertionEnded( Ptr<AssertionStats const> const& ) {} virtual void assertionEnded( AssertionStats const& ) {}
virtual void sectionEnded( Ptr<SectionStats const> const& ) {} virtual void sectionEnded( SectionStats const& ) {}
virtual void testCaseEnded( Ptr<TestCaseStats const> const& ) {} virtual void testCaseEnded( TestCaseStats const& ) {}
virtual void testGroupEnded( Ptr<TestGroupStats const> const& ) {} virtual void testGroupEnded( TestGroupStats const& ) {}
virtual void testRunEnded( Ptr<TestRunStats const> const& ) {} virtual void testRunEnded( TestRunStats const& ) {}
}; };
class EmbeddedRunner { class EmbeddedRunner {