mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-21 12:05:39 +02:00
JunitReporter reimplemented using the new IStreamingReporter interface
* created new AccumulatingReporterBase class for accumulating test results hierarchically and store them for a single processResults() call after all tests have been executed; sections are currently not handled, since their usage are optional and/or could be nested arbitrarily, which would result in overly complex code, IMHO * JunitReporter reimplemented on top of this new AccumulatingReporterBase class * added support for tracking time spend in each test case, each test group, and overall tests to the base "*Stats" classes; this enables each reporter (derived from IStreamingReporter interface) to report the timings; for now only the JunitReporter takes advantage of that.
This commit is contained in:
@@ -58,11 +58,10 @@ namespace Catch {
|
||||
TestGroupStats::~TestGroupStats() {}
|
||||
TestRunStats::~TestRunStats() {}
|
||||
ThreadedSectionInfo::~ThreadedSectionInfo() {}
|
||||
TestGroupNode::~TestGroupNode() {}
|
||||
TestRunNode::~TestRunNode() {}
|
||||
|
||||
BasicReporter::~BasicReporter() {}
|
||||
StreamingReporterBase::~StreamingReporterBase() {}
|
||||
AccumulatingReporterBase::~AccumulatingReporterBase() {}
|
||||
ConsoleReporter::~ConsoleReporter() {}
|
||||
IRunner::~IRunner() {}
|
||||
IMutableContext::~IMutableContext() {}
|
||||
@@ -86,7 +85,7 @@ namespace Catch {
|
||||
|
||||
INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "basic", BasicReporter )
|
||||
INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
|
||||
INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "junit", JunitReporter )
|
||||
INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
|
||||
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "catch_message.h"
|
||||
#include "catch_option.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <map>
|
||||
@@ -47,10 +48,11 @@ namespace Catch
|
||||
};
|
||||
|
||||
struct TestRunInfo {
|
||||
TestRunInfo( std::string const& _name ) : name( _name ) {}
|
||||
TestRunInfo( std::string const& _name = "" ) : name( _name ) {}
|
||||
std::string name;
|
||||
};
|
||||
struct GroupInfo {
|
||||
GroupInfo() : groupIndex( 0 ), groupsCounts( 0 ) {}
|
||||
GroupInfo( std::string const& _name,
|
||||
std::size_t _groupIndex,
|
||||
std::size_t _groupsCount )
|
||||
@@ -65,6 +67,7 @@ namespace Catch
|
||||
};
|
||||
|
||||
struct SectionInfo {
|
||||
SectionInfo() {}
|
||||
SectionInfo( std::string const& _name,
|
||||
std::string const& _description,
|
||||
SourceLineInfo const& _lineInfo )
|
||||
@@ -113,6 +116,7 @@ namespace Catch
|
||||
};
|
||||
|
||||
struct SectionStats {
|
||||
SectionStats() : missingAssertions( false ) {}
|
||||
SectionStats( SectionInfo const& _sectionInfo,
|
||||
Counts const& _assertions,
|
||||
bool _missingAssertions )
|
||||
@@ -128,14 +132,20 @@ namespace Catch
|
||||
};
|
||||
|
||||
struct TestCaseStats {
|
||||
TestCaseStats()
|
||||
: missingAssertions( false ),
|
||||
aborting( false)
|
||||
{}
|
||||
TestCaseStats( TestCaseInfo const& _testInfo,
|
||||
Totals const& _totals,
|
||||
double _timeSecs,
|
||||
std::string const& _stdOut,
|
||||
std::string const& _stdErr,
|
||||
bool _missingAssertions,
|
||||
bool _aborting )
|
||||
: testInfo( _testInfo ),
|
||||
totals( _totals ),
|
||||
timeSecs( _timeSecs ),
|
||||
stdOut( _stdOut ),
|
||||
stdErr( _stdErr ),
|
||||
missingAssertions( _missingAssertions ),
|
||||
@@ -145,6 +155,7 @@ namespace Catch
|
||||
|
||||
TestCaseInfo testInfo;
|
||||
Totals totals;
|
||||
double timeSecs;
|
||||
std::string stdOut;
|
||||
std::string stdErr;
|
||||
bool missingAssertions;
|
||||
@@ -152,41 +163,51 @@ namespace Catch
|
||||
};
|
||||
|
||||
struct TestGroupStats {
|
||||
TestGroupStats()
|
||||
: aborting( false )
|
||||
{}
|
||||
|
||||
TestGroupStats( GroupInfo const& _groupInfo,
|
||||
Totals const& _totals,
|
||||
double _timeSecs,
|
||||
bool _aborting )
|
||||
: groupInfo( _groupInfo ),
|
||||
totals( _totals ),
|
||||
timeSecs( _timeSecs ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
TestGroupStats( GroupInfo const& _groupInfo )
|
||||
: groupInfo( _groupInfo ),
|
||||
timeSecs( 0.0 ),
|
||||
aborting( false )
|
||||
{}
|
||||
virtual ~TestGroupStats();
|
||||
|
||||
GroupInfo groupInfo;
|
||||
Totals totals;
|
||||
double timeSecs;
|
||||
bool aborting;
|
||||
};
|
||||
|
||||
struct TestRunStats {
|
||||
TestRunStats()
|
||||
: timeSecs( 0.0 ),
|
||||
aborting( false )
|
||||
{}
|
||||
TestRunStats( TestRunInfo const& _runInfo,
|
||||
Totals const& _totals,
|
||||
double _timeSecs,
|
||||
bool _aborting )
|
||||
: runInfo( _runInfo ),
|
||||
totals( _totals ),
|
||||
timeSecs( _timeSecs ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
TestRunStats( TestRunStats const& _other )
|
||||
: runInfo( _other.runInfo ),
|
||||
totals( _other.totals ),
|
||||
aborting( _other.aborting )
|
||||
{}
|
||||
virtual ~TestRunStats();
|
||||
|
||||
TestRunInfo runInfo;
|
||||
Totals totals;
|
||||
double timeSecs;
|
||||
bool aborting;
|
||||
};
|
||||
|
||||
@@ -276,21 +297,83 @@ namespace Catch
|
||||
std::vector<Ptr<ThreadedSectionInfo> > m_rootSections;
|
||||
};
|
||||
|
||||
struct TestGroupNode : TestGroupStats {
|
||||
TestGroupNode( TestGroupStats const& _stats ) : TestGroupStats( _stats ) {}
|
||||
// TestGroupNode( GroupInfo const& _info ) : TestGroupStats( _stats ) {}
|
||||
~TestGroupNode();
|
||||
struct AccumulatingReporterBase : SharedImpl<IStreamingReporter> {
|
||||
protected:
|
||||
struct AccumTestCaseStats {
|
||||
TestCaseStats testCase;
|
||||
std::vector<AssertionStats> tests;
|
||||
};
|
||||
struct AccumTestGroupStats {
|
||||
TestGroupStats testGroup;
|
||||
std::vector<AccumTestCaseStats> testCases;
|
||||
};
|
||||
struct AccumTestRunStats {
|
||||
TestRunStats testRun;
|
||||
std::vector<AccumTestGroupStats> testGroups;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
struct TestRunNode : TestRunStats {
|
||||
|
||||
TestRunNode( TestRunStats const& _stats ) : TestRunStats( _stats ) {}
|
||||
~TestRunNode();
|
||||
public:
|
||||
virtual ~AccumulatingReporterBase();
|
||||
|
||||
std::vector<TestGroupNode> groups;
|
||||
virtual void testRunStarting( TestRunInfo const& testRunInfo ) {
|
||||
(void)testRunInfo;
|
||||
assert( m_accumGroups.empty() );
|
||||
assert( m_accumCases.empty() );
|
||||
assert( m_accumTests.empty() );
|
||||
}
|
||||
virtual void testGroupStarting( GroupInfo const& groupInfo ) {
|
||||
(void)groupInfo;
|
||||
assert( m_accumCases.empty() );
|
||||
assert( m_accumTests.empty() );
|
||||
}
|
||||
virtual void testCaseStarting( TestCaseInfo const& testInfo ) {
|
||||
(void)testInfo;
|
||||
assert( m_accumTests.empty() );
|
||||
}
|
||||
virtual void sectionStarting( SectionInfo const& sectionInfo ) {
|
||||
(void)sectionInfo;
|
||||
}
|
||||
virtual void assertionStarting( AssertionInfo const& assertionInfo ) {
|
||||
(void)assertionInfo;
|
||||
}
|
||||
|
||||
virtual void assertionEnded( AssertionStats const& assertionStats ) {
|
||||
m_accumTests.push_back( assertionStats );
|
||||
}
|
||||
virtual void sectionEnded( SectionStats const& sectionStats ) {
|
||||
(void)sectionStats;
|
||||
}
|
||||
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
|
||||
AccumTestCaseStats stats;
|
||||
stats.testCase = testCaseStats;
|
||||
std::swap(stats.tests, m_accumTests);
|
||||
m_accumCases.push_back( stats );
|
||||
}
|
||||
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
|
||||
assert( m_accumTests.empty() );
|
||||
AccumTestGroupStats stats;
|
||||
stats.testGroup = testGroupStats;
|
||||
std::swap(stats.testCases, m_accumCases);
|
||||
m_accumGroups.push_back( stats );
|
||||
}
|
||||
virtual void testRunEnded( TestRunStats const& testRunStats ) {
|
||||
assert( m_accumTests.empty() );
|
||||
assert( m_accumCases.empty() );
|
||||
AccumTestRunStats stats;
|
||||
stats.testRun = testRunStats;
|
||||
std::swap(stats.testGroups, m_accumGroups);
|
||||
|
||||
processResults( stats );
|
||||
}
|
||||
|
||||
virtual void processResults( AccumTestRunStats const& testRun ) = 0;
|
||||
|
||||
private:
|
||||
std::vector<AccumTestGroupStats> m_accumGroups;
|
||||
std::vector<AccumTestCaseStats> m_accumCases;
|
||||
std::vector<AssertionStats> m_accumTests;
|
||||
};
|
||||
|
||||
|
||||
// Deprecated
|
||||
struct IReporter : IShared {
|
||||
virtual ~IReporter();
|
||||
@@ -327,8 +410,9 @@ namespace Catch
|
||||
};
|
||||
|
||||
inline std::string trim( std::string const& str ) {
|
||||
std::string::size_type start = str.find_first_not_of( "\n\r\t " );
|
||||
std::string::size_type end = str.find_last_not_of( "\n\r\t " );
|
||||
const char* const stripAway = "\n\r\t ";
|
||||
std::string::size_type start = str.find_first_not_of( stripAway );
|
||||
std::string::size_type end = str.find_last_not_of( stripAway );
|
||||
|
||||
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
|
||||
}
|
||||
|
@@ -22,8 +22,20 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
// C++11 specific start
|
||||
#include <chrono>
|
||||
// C++11 specific end
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// C++11 specific start
|
||||
typedef decltype(std::chrono::high_resolution_clock::now()) time_point;
|
||||
static inline time_point time_now() { return std::chrono::high_resolution_clock::now(); }
|
||||
static inline double time_diff_secs(time_point const& end, time_point const& start) {
|
||||
return (1e-6 * std::chrono::duration_cast<std::chrono::microseconds>(end - start).count());
|
||||
}
|
||||
// C++11 specific end
|
||||
|
||||
class StreamRedirect {
|
||||
|
||||
public:
|
||||
@@ -64,7 +76,9 @@ namespace Catch {
|
||||
m_reporter( reporter ),
|
||||
m_prevRunner( &m_context.getRunner() ),
|
||||
m_prevResultCapture( &m_context.getResultCapture() ),
|
||||
m_prevConfig( m_context.getConfig() )
|
||||
m_prevConfig( m_context.getConfig() ),
|
||||
m_startRun( time_now() ),
|
||||
m_startGroup( m_startRun )
|
||||
{
|
||||
m_context.setRunner( this );
|
||||
m_context.setConfig( m_config );
|
||||
@@ -73,7 +87,8 @@ namespace Catch {
|
||||
}
|
||||
|
||||
virtual ~RunContext() {
|
||||
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
|
||||
double timing = time_diff_secs( time_now() , m_startRun );
|
||||
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, timing, aborting() ) );
|
||||
m_context.setRunner( m_prevRunner );
|
||||
m_context.setConfig( NULL );
|
||||
m_context.setResultCapture( m_prevResultCapture );
|
||||
@@ -82,9 +97,11 @@ namespace Catch {
|
||||
|
||||
void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
|
||||
m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
|
||||
m_startGroup = time_now();
|
||||
}
|
||||
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() ) );
|
||||
double timing = time_diff_secs( time_now() , m_startGroup );
|
||||
m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, timing, aborting() ) );
|
||||
}
|
||||
|
||||
Totals runMatching( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
|
||||
@@ -116,6 +133,7 @@ namespace Catch {
|
||||
|
||||
m_runningTest = new RunningTest( testCase );
|
||||
|
||||
time_point timeStart = time_now();
|
||||
do {
|
||||
do {
|
||||
runCurrentTest( redirectedCout, redirectedCerr );
|
||||
@@ -123,6 +141,7 @@ namespace Catch {
|
||||
while( m_runningTest->hasUntestedSections() && !aborting() );
|
||||
}
|
||||
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
|
||||
time_point timeEnd = time_now();
|
||||
|
||||
Totals deltaTotals = m_totals.delta( prevTotals );
|
||||
bool missingAssertions = false;
|
||||
@@ -136,6 +155,7 @@ namespace Catch {
|
||||
|
||||
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
||||
deltaTotals,
|
||||
time_diff_secs( timeEnd, timeStart ),
|
||||
redirectedCout,
|
||||
redirectedCerr,
|
||||
missingAssertions,
|
||||
@@ -323,6 +343,8 @@ namespace Catch {
|
||||
Ptr<IConfig const> m_prevConfig;
|
||||
AssertionInfo m_lastAssertionInfo;
|
||||
std::vector<UnfinishedSections> m_unfinishedSections;
|
||||
time_point m_startRun;
|
||||
time_point m_startGroup;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -24,6 +24,7 @@ namespace Catch {
|
||||
struct ITestCase;
|
||||
|
||||
struct TestCaseInfo {
|
||||
TestCaseInfo() : isHidden( false ) {}
|
||||
TestCaseInfo( std::string const& _name,
|
||||
std::string const& _className,
|
||||
std::string const& _description,
|
||||
@@ -31,8 +32,6 @@ namespace Catch {
|
||||
bool _isHidden,
|
||||
SourceLineInfo const& _lineInfo );
|
||||
|
||||
TestCaseInfo( TestCaseInfo const& other );
|
||||
|
||||
std::string name;
|
||||
std::string className;
|
||||
std::string description;
|
||||
|
@@ -51,16 +51,6 @@ namespace Catch {
|
||||
tagsAsString = oss.str();
|
||||
}
|
||||
|
||||
TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
|
||||
: name( other.name ),
|
||||
className( other.className ),
|
||||
description( other.description ),
|
||||
tags( other.tags ),
|
||||
tagsAsString( other.tagsAsString ),
|
||||
lineInfo( other.lineInfo ),
|
||||
isHidden( other.isHidden )
|
||||
{}
|
||||
|
||||
TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
|
||||
|
||||
TestCase::TestCase( TestCase const& other )
|
||||
|
Reference in New Issue
Block a user