mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-01 12:55:40 +02:00
First cut of Timer class.
- started integrating with reporters (now (optionally) supported in console reporter). - introduced Node<> template to help with cumulative reporting and used it instead of ThreadedSectionInfo.
This commit is contained in:
@@ -24,15 +24,21 @@ namespace Catch {
|
||||
|
||||
inline void addWarning( ConfigData& config, std::string const& _warning ) {
|
||||
if( _warning == "NoAssertions" )
|
||||
config.warnings = (ConfigData::WarnAbout::What)( config.warnings | ConfigData::WarnAbout::NoAssertions );
|
||||
config.warnings = (WarnAbout::What)( config.warnings | WarnAbout::NoAssertions );
|
||||
else
|
||||
throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
|
||||
|
||||
}
|
||||
inline void setVerbosity( ConfigData& config, int level ) {
|
||||
// !TBD: accept strings?
|
||||
config.verbosity = (ConfigData::Verbosity::Level)level;
|
||||
config.verbosity = (Verbosity::Level)level;
|
||||
}
|
||||
inline void setShowDurations( ConfigData& config, bool _showDurations ) {
|
||||
config.showDurations = _showDurations
|
||||
? ShowDurations::Always
|
||||
: ShowDurations::Never;
|
||||
}
|
||||
|
||||
|
||||
inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
|
||||
|
||||
@@ -121,6 +127,12 @@ namespace Catch {
|
||||
.describe( "which test or tests to use" )
|
||||
.argName( "test name, pattern or tags" );
|
||||
|
||||
cli.bind( &setShowDurations )
|
||||
.describe( "show test durations" )
|
||||
.shortOpt( "d")
|
||||
.longOpt( "durations" )
|
||||
.argName( "durations" );
|
||||
|
||||
return cli;
|
||||
}
|
||||
|
||||
|
@@ -26,17 +26,6 @@ namespace Catch {
|
||||
|
||||
struct ConfigData {
|
||||
|
||||
struct Verbosity { enum Level {
|
||||
NoOutput = 0,
|
||||
Quiet,
|
||||
Normal
|
||||
}; };
|
||||
|
||||
struct WarnAbout { enum What {
|
||||
Nothing = 0x00,
|
||||
NoAssertions = 0x01
|
||||
}; };
|
||||
|
||||
ConfigData()
|
||||
: listTests( false ),
|
||||
listTags( false ),
|
||||
@@ -47,7 +36,8 @@ namespace Catch {
|
||||
showHelp( false ),
|
||||
abortAfter( -1 ),
|
||||
verbosity( Verbosity::Normal ),
|
||||
warnings( WarnAbout::Nothing )
|
||||
warnings( WarnAbout::Nothing ),
|
||||
showDurations( ShowDurations::DefaultForReporter )
|
||||
{}
|
||||
|
||||
bool listTests;
|
||||
@@ -63,6 +53,7 @@ namespace Catch {
|
||||
|
||||
Verbosity::Level verbosity;
|
||||
WarnAbout::What warnings;
|
||||
ShowDurations::OrNot showDurations;
|
||||
|
||||
std::string reporterName;
|
||||
std::string outputFilename;
|
||||
@@ -166,7 +157,9 @@ namespace Catch {
|
||||
virtual std::ostream& stream() const { return m_os; }
|
||||
virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||
virtual bool warnAboutMissingAssertions() const { return m_data.warnings & ConfigData::WarnAbout::NoAssertions; }
|
||||
virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
|
||||
virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
|
||||
|
||||
|
||||
private:
|
||||
ConfigData m_data;
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "catch_text.hpp"
|
||||
#include "catch_message.hpp"
|
||||
#include "catch_legacy_reporter_adapter.hpp"
|
||||
#include "catch_timer.hpp"
|
||||
|
||||
#include "../reporters/catch_reporter_basic.hpp"
|
||||
#include "../reporters/catch_reporter_xml.hpp"
|
||||
@@ -57,7 +58,6 @@ namespace Catch {
|
||||
TestCaseStats::~TestCaseStats() {}
|
||||
TestGroupStats::~TestGroupStats() {}
|
||||
TestRunStats::~TestRunStats() {}
|
||||
ThreadedSectionInfo::~ThreadedSectionInfo() {}
|
||||
TestGroupNode::~TestGroupNode() {}
|
||||
TestRunNode::~TestRunNode() {}
|
||||
|
||||
|
@@ -30,7 +30,7 @@ namespace Catch {
|
||||
virtual void assertionEnded( AssertionResult const& result ) = 0;
|
||||
virtual bool sectionStarted( SectionInfo const& sectionInfo,
|
||||
Counts& assertions ) = 0;
|
||||
virtual void sectionEnded( SectionInfo const& name, Counts const& assertions ) = 0;
|
||||
virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||
|
||||
|
@@ -15,6 +15,23 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct Verbosity { enum Level {
|
||||
NoOutput = 0,
|
||||
Quiet,
|
||||
Normal
|
||||
}; };
|
||||
|
||||
struct WarnAbout { enum What {
|
||||
Nothing = 0x00,
|
||||
NoAssertions = 0x01
|
||||
}; };
|
||||
|
||||
struct ShowDurations { enum OrNot {
|
||||
DefaultForReporter,
|
||||
Always,
|
||||
Never
|
||||
}; };
|
||||
|
||||
struct IConfig : IShared {
|
||||
|
||||
virtual ~IConfig();
|
||||
@@ -26,6 +43,7 @@ namespace Catch {
|
||||
virtual bool shouldDebugBreak() const = 0;
|
||||
virtual bool warnAboutMissingAssertions() const = 0;
|
||||
virtual int abortAfter() const = 0;
|
||||
virtual ShowDurations::OrNot showDurations() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -46,6 +46,20 @@ namespace Catch
|
||||
bool shouldRedirectStdOut;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Node : SharedImpl<> {
|
||||
Node( T const& _value, Node* _parent = NULL )
|
||||
: value( _value ),
|
||||
parent( _parent )
|
||||
{}
|
||||
virtual ~Node() {}
|
||||
|
||||
T value;
|
||||
std::vector<Ptr<Node> > children;
|
||||
Node* parent;
|
||||
};
|
||||
|
||||
struct TestRunInfo {
|
||||
TestRunInfo( std::string const& _name ) : name( _name ) {}
|
||||
std::string name;
|
||||
@@ -78,17 +92,6 @@ namespace Catch
|
||||
SourceLineInfo lineInfo;
|
||||
};
|
||||
|
||||
struct ThreadedSectionInfo : SectionInfo, SharedImpl<> {
|
||||
ThreadedSectionInfo( SectionInfo const& _sectionInfo, ThreadedSectionInfo* _parent = NULL )
|
||||
: SectionInfo( _sectionInfo ),
|
||||
parent( _parent )
|
||||
{}
|
||||
virtual ~ThreadedSectionInfo();
|
||||
|
||||
std::vector<Ptr<ThreadedSectionInfo> > children;
|
||||
ThreadedSectionInfo* parent;
|
||||
};
|
||||
|
||||
struct AssertionStats {
|
||||
AssertionStats( AssertionResult const& _assertionResult,
|
||||
std::vector<MessageInfo> const& _infoMessages,
|
||||
@@ -117,15 +120,18 @@ namespace Catch
|
||||
struct SectionStats {
|
||||
SectionStats( SectionInfo const& _sectionInfo,
|
||||
Counts const& _assertions,
|
||||
double _durationInSeconds,
|
||||
bool _missingAssertions )
|
||||
: sectionInfo( _sectionInfo ),
|
||||
assertions( _assertions ),
|
||||
durationInSeconds( _durationInSeconds ),
|
||||
missingAssertions( _missingAssertions )
|
||||
{}
|
||||
virtual ~SectionStats();
|
||||
|
||||
SectionInfo sectionInfo;
|
||||
Counts assertions;
|
||||
double durationInSeconds;
|
||||
bool missingAssertions;
|
||||
};
|
||||
|
||||
@@ -189,6 +195,7 @@ namespace Catch
|
||||
bool aborting;
|
||||
};
|
||||
|
||||
|
||||
struct IStreamingReporter : IShared {
|
||||
virtual ~IStreamingReporter();
|
||||
|
||||
@@ -236,7 +243,7 @@ namespace Catch
|
||||
unusedTestCaseInfo = _testInfo;
|
||||
}
|
||||
virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
|
||||
Ptr<ThreadedSectionInfo> sectionInfo = new ThreadedSectionInfo( _sectionInfo );
|
||||
Ptr<Node<SectionInfo> > sectionInfo = new Node<SectionInfo>( _sectionInfo );
|
||||
if( !currentSectionInfo ) {
|
||||
currentSectionInfo = sectionInfo;
|
||||
m_rootSections.push_back( currentSectionInfo );
|
||||
@@ -268,11 +275,11 @@ namespace Catch
|
||||
Option<TestRunInfo> testRunInfo;
|
||||
Option<GroupInfo> unusedGroupInfo;
|
||||
Option<TestCaseInfo> unusedTestCaseInfo;
|
||||
Ptr<ThreadedSectionInfo> currentSectionInfo;
|
||||
Ptr<Node<SectionInfo> > currentSectionInfo;
|
||||
std::ostream& stream;
|
||||
|
||||
// !TBD: This should really go in the TestCaseStats class
|
||||
std::vector<Ptr<ThreadedSectionInfo> > m_rootSections;
|
||||
std::vector<Ptr<Node<SectionInfo> > > m_rootSections;
|
||||
};
|
||||
|
||||
struct TestGroupNode : TestGroupStats {
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "catch_totals.hpp"
|
||||
#include "catch_test_spec.h"
|
||||
#include "catch_test_case_tracker.hpp"
|
||||
#include "catch_timer.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -194,9 +195,9 @@ namespace Catch {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions ) {
|
||||
virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
|
||||
if( std::uncaught_exception() ) {
|
||||
m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions ) );
|
||||
m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -205,7 +206,7 @@ namespace Catch {
|
||||
|
||||
m_testCaseTracker->leaveSection();
|
||||
|
||||
m_reporter->sectionEnded( SectionStats( info, assertions, missingAssertions ) );
|
||||
m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
|
||||
m_messages.clear();
|
||||
}
|
||||
|
||||
@@ -260,10 +261,13 @@ namespace Catch {
|
||||
SectionInfo testCaseSection( testCaseInfo.name, testCaseInfo.description, testCaseInfo.lineInfo );
|
||||
m_reporter->sectionStarting( testCaseSection );
|
||||
Counts prevAssertions = m_totals.assertions;
|
||||
double duration = 0;
|
||||
try {
|
||||
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
|
||||
TestCaseTracker::Guard guard( *m_testCaseTracker );
|
||||
|
||||
Timer timer;
|
||||
timer.start();
|
||||
if( m_reporter->getPreferences().shouldRedirectStdOut ) {
|
||||
StreamRedirect coutRedir( std::cout, redirectedCout );
|
||||
StreamRedirect cerrRedir( std::cerr, redirectedCerr );
|
||||
@@ -272,6 +276,7 @@ namespace Catch {
|
||||
else {
|
||||
m_activeTestCase->invoke();
|
||||
}
|
||||
duration = timer.getElapsedSeconds();
|
||||
}
|
||||
catch( TestFailureException& ) {
|
||||
// This just means the test was aborted due to failure
|
||||
@@ -287,25 +292,26 @@ namespace Catch {
|
||||
itEnd = m_unfinishedSections.end();
|
||||
it != itEnd;
|
||||
++it )
|
||||
sectionEnded( it->info, it->prevAssertions );
|
||||
sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
|
||||
m_unfinishedSections.clear();
|
||||
m_messages.clear();
|
||||
|
||||
Counts assertions = m_totals.assertions - prevAssertions;
|
||||
bool missingAssertions = testForMissingAssertions( assertions );
|
||||
|
||||
SectionStats testCaseSectionStats( testCaseSection, assertions, missingAssertions );
|
||||
SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
|
||||
m_reporter->sectionEnded( testCaseSectionStats );
|
||||
}
|
||||
|
||||
private:
|
||||
struct UnfinishedSections {
|
||||
UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions )
|
||||
: info( _info ), prevAssertions( _prevAssertions )
|
||||
UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
|
||||
: info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
|
||||
{}
|
||||
|
||||
SectionInfo info;
|
||||
Counts prevAssertions;
|
||||
double durationInSeconds;
|
||||
};
|
||||
|
||||
TestRunInfo m_runInfo;
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "catch_capture.hpp"
|
||||
#include "catch_totals.hpp"
|
||||
#include "catch_compiler_capabilities.h"
|
||||
#include "catch_timer.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -23,11 +24,13 @@ namespace Catch {
|
||||
std::string const& description = "" )
|
||||
: m_info( name, description, lineInfo ),
|
||||
m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( m_info, m_assertions ) )
|
||||
{}
|
||||
{
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
~Section() {
|
||||
if( m_sectionIncluded )
|
||||
getCurrentContext().getResultCapture().sectionEnded( m_info, m_assertions );
|
||||
getCurrentContext().getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
|
||||
}
|
||||
|
||||
// This indicates whether the section should be executed or not
|
||||
@@ -41,6 +44,7 @@ namespace Catch {
|
||||
std::string m_name;
|
||||
Counts m_assertions;
|
||||
bool m_sectionIncluded;
|
||||
Timer m_timer;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
33
include/internal/catch_timer.h
Normal file
33
include/internal/catch_timer.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Created by Phil on 05/08/2013.
|
||||
* Copyright 2013 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)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
|
||||
|
||||
#ifdef WIN32
|
||||
typedef unsigned long long uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
Timer() : m_ticks( 0 ) {}
|
||||
void start();
|
||||
unsigned int getElapsedNanoseconds() const;
|
||||
unsigned int getElapsedMilliseconds() const;
|
||||
double getElapsedSeconds() const;
|
||||
|
||||
private:
|
||||
uint64_t m_ticks;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
|
62
include/internal/catch_timer.hpp
Normal file
62
include/internal/catch_timer.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Created by Phil on 05/08/2013.
|
||||
* Copyright 2013 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)
|
||||
*/
|
||||
|
||||
#include "catch_timer.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wc++11-long-long"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
#ifdef WIN32
|
||||
uint64_t getCurrentTicks() {
|
||||
static uint64_t hz=0, hzo=0;
|
||||
if (!hz) {
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&hz);
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&hzo);
|
||||
}
|
||||
uint64_t t;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&t);
|
||||
return ((t-hzo)*1000000)/hz;
|
||||
}
|
||||
#else
|
||||
uint64_t getCurrentTicks() {
|
||||
timeval t;
|
||||
gettimeofday(&t,NULL);
|
||||
return (uint64_t)t.tv_sec * 1000000ull + (uint64_t)t.tv_usec;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Timer::start() {
|
||||
m_ticks = getCurrentTicks();
|
||||
}
|
||||
unsigned int Timer::getElapsedNanoseconds() const {
|
||||
return (unsigned int)(getCurrentTicks() - m_ticks);
|
||||
}
|
||||
unsigned int Timer::getElapsedMilliseconds() const {
|
||||
return (unsigned int)((getCurrentTicks() - m_ticks)/1000);
|
||||
}
|
||||
double Timer::getElapsedSeconds() const {
|
||||
return (getCurrentTicks() - m_ticks)/1000000.0;
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
@@ -69,6 +69,8 @@ namespace Catch {
|
||||
stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
|
||||
}
|
||||
m_headerPrinted = false;
|
||||
if( m_config->showDurations() == ShowDurations::Always )
|
||||
stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
|
||||
StreamingReporterBase::sectionEnded( _sectionStats );
|
||||
}
|
||||
|
||||
@@ -263,20 +265,20 @@ namespace Catch {
|
||||
assert( currentSectionInfo );
|
||||
if( currentSectionInfo ) {
|
||||
Colour colourGuard( Colour::Headers );
|
||||
std::vector<ThreadedSectionInfo*> sections;
|
||||
for( ThreadedSectionInfo* section = currentSectionInfo.get();
|
||||
std::vector<Node<SectionInfo>*> sections;
|
||||
for( Node<SectionInfo>* section = currentSectionInfo.get();
|
||||
section;
|
||||
section = section->parent )
|
||||
sections.push_back( section );
|
||||
|
||||
// Sections
|
||||
std::vector<ThreadedSectionInfo*>::const_reverse_iterator
|
||||
std::vector<Node<SectionInfo>*>::const_reverse_iterator
|
||||
it = sections.rbegin(), itEnd = sections.rend();
|
||||
for( ++it; it != itEnd; ++it ) // Skip first section (test case)
|
||||
printHeaderString( (*it)->name, 2 );
|
||||
printHeaderString( (*it)->value.name, 2 );
|
||||
}
|
||||
SourceLineInfo lineInfo = currentSectionInfo
|
||||
? currentSectionInfo->lineInfo
|
||||
? currentSectionInfo->value.lineInfo
|
||||
: unusedTestCaseInfo->lineInfo;
|
||||
|
||||
if( !lineInfo.empty() ){
|
||||
|
@@ -82,7 +82,7 @@ namespace Catch {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void StartTesting(){}
|
||||
virtual void StartTesting() {}
|
||||
|
||||
virtual void StartGroup( const std::string& groupName ) {
|
||||
if( groupName.empty() )
|
||||
@@ -189,7 +189,10 @@ namespace Catch {
|
||||
xml.writeAttribute( "failures", it->m_failuresCount );
|
||||
xml.writeAttribute( "tests", it->m_testsCount );
|
||||
xml.writeAttribute( "hostname", "tbd" );
|
||||
xml.writeAttribute( "time", "tbd" );
|
||||
if( m_config.fullConfig()->showDurations() == ShowDurations::Never )
|
||||
xml.writeAttribute( "time", it->m_timeInSeconds );
|
||||
else
|
||||
xml.writeAttribute( "time", "" );
|
||||
xml.writeAttribute( "timestamp", "tbd" );
|
||||
|
||||
OutputTestCases( xml, *it );
|
||||
@@ -207,7 +210,10 @@ namespace Catch {
|
||||
XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
|
||||
xml.writeAttribute( "classname", it->m_className );
|
||||
xml.writeAttribute( "name", it->m_name );
|
||||
xml.writeAttribute( "time", "tbd" );
|
||||
if( m_config.fullConfig()->showDurations() == ShowDurations::Never )
|
||||
xml.writeAttribute( "time", "" );
|
||||
else
|
||||
xml.writeAttribute( "time", stats.m_timeInSeconds );
|
||||
|
||||
OutputTestResult( xml, *it );
|
||||
|
||||
|
Reference in New Issue
Block a user