mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-26 23:36:11 +01:00
Added cutoff option to command line
Aborts testing after a certain number of assertion failures
This commit is contained in:
parent
163088a11f
commit
19b2aa6187
@ -84,6 +84,7 @@ namespace Catch {
|
|||||||
<< "\t-s, --success\n"
|
<< "\t-s, --success\n"
|
||||||
<< "\t-b, --break\n"
|
<< "\t-b, --break\n"
|
||||||
<< "\t-n, --name <name>\n\n"
|
<< "\t-n, --name <name>\n\n"
|
||||||
|
<< "\t-c, --cutoff [#]\n\n"
|
||||||
<< "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl;
|
<< "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl;
|
||||||
}
|
}
|
||||||
inline void showHelp( std::string exeName ) {
|
inline void showHelp( std::string exeName ) {
|
||||||
|
@ -52,7 +52,8 @@ inline bool isTrue( bool value ){ return value; }
|
|||||||
#define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \
|
#define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \
|
||||||
if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) \
|
if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) \
|
||||||
{ \
|
{ \
|
||||||
if( internal_catch_action == Catch::ResultAction::DebugFailed ) BreakIntoDebugger(); \
|
if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \
|
||||||
|
if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \
|
||||||
if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \
|
if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \
|
||||||
if( Catch::isTrue( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \
|
if( Catch::isTrue( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,19 @@ namespace Catch {
|
|||||||
throw std::domain_error( cmd.name() + " does not accept arguments" );
|
throw std::domain_error( cmd.name() + " does not accept arguments" );
|
||||||
config.setShowHelp( true );
|
config.setShowHelp( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( Command cmd = parser.find( "-c", "--cutoff" ) ) {
|
||||||
|
if( cmd.argsCount() > 1 )
|
||||||
|
throw std::domain_error( cmd.name() + " only accepts 0-1 arguments" );
|
||||||
|
int threshold = 1;
|
||||||
|
if( cmd.argsCount() == 1 )
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << cmd[0];
|
||||||
|
ss >> threshold;
|
||||||
|
}
|
||||||
|
config.setCutoff( threshold );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch( std::exception& ex ) {
|
catch( std::exception& ex ) {
|
||||||
config.setError( ex.what() );
|
config.setError( ex.what() );
|
||||||
|
@ -50,7 +50,8 @@ namespace Catch {
|
|||||||
m_showHelp( false ),
|
m_showHelp( false ),
|
||||||
m_streambuf( NULL ),
|
m_streambuf( NULL ),
|
||||||
m_os( std::cout.rdbuf() ),
|
m_os( std::cout.rdbuf() ),
|
||||||
m_includeWhichResults( Include::FailedOnly )
|
m_includeWhichResults( Include::FailedOnly ),
|
||||||
|
m_cutoff( -1 )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~Config() {
|
~Config() {
|
||||||
@ -165,6 +166,14 @@ namespace Catch {
|
|||||||
return m_includeWhichResults == Include::SuccessfulResults;
|
return m_includeWhichResults == Include::SuccessfulResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getCutoff() const {
|
||||||
|
return m_cutoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCutoff( int cutoff ) {
|
||||||
|
m_cutoff = cutoff;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ptr<IReporter> m_reporter;
|
Ptr<IReporter> m_reporter;
|
||||||
std::string m_filename;
|
std::string m_filename;
|
||||||
@ -177,6 +186,7 @@ namespace Catch {
|
|||||||
mutable std::ostream m_os;
|
mutable std::ostream m_os;
|
||||||
Include::WhichResults m_includeWhichResults;
|
Include::WhichResults m_includeWhichResults;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
int m_cutoff;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NewConfig {
|
struct NewConfig {
|
||||||
|
@ -38,6 +38,7 @@ namespace Catch
|
|||||||
virtual void StartSection( const std::string& sectionName, const std::string& description ) = 0;
|
virtual void StartSection( const std::string& sectionName, const std::string& description ) = 0;
|
||||||
virtual void EndSection( const std::string& sectionName, const Counts& assertions ) = 0;
|
virtual void EndSection( const std::string& sectionName, const Counts& assertions ) = 0;
|
||||||
virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0;
|
virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0;
|
||||||
|
virtual void Aborted() = 0;
|
||||||
virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr ) = 0;
|
virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr ) = 0;
|
||||||
virtual void Result( const ResultInfo& result ) = 0;
|
virtual void Result( const ResultInfo& result ) = 0;
|
||||||
};
|
};
|
||||||
|
@ -30,9 +30,9 @@ struct ResultWas { enum OfType {
|
|||||||
|
|
||||||
struct ResultAction { enum Value {
|
struct ResultAction { enum Value {
|
||||||
None,
|
None,
|
||||||
Failed = 1, // Failure - but no debug break if Debug bit not set
|
Failed = 1, // Failure - but no debug break if Debug bit not set
|
||||||
DebugFailed = 3 // Indicates that the debugger should break, if possible
|
Debug = 2, // If this bit is set, invoke the debugger
|
||||||
|
Abort = 4 // Test run should abort
|
||||||
}; };
|
}; };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,13 @@ namespace Catch {
|
|||||||
const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests();
|
const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests();
|
||||||
for( std::size_t i=0; i < allTests.size(); ++i ) {
|
for( std::size_t i=0; i < allTests.size(); ++i ) {
|
||||||
if( runHiddenTests || !allTests[i].isHidden() )
|
if( runHiddenTests || !allTests[i].isHidden() )
|
||||||
runTest( allTests[i] );
|
{
|
||||||
|
if( aborting() ) {
|
||||||
|
m_reporter->Aborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
runTest( allTests[i] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +95,10 @@ namespace Catch {
|
|||||||
std::size_t testsRun = 0;
|
std::size_t testsRun = 0;
|
||||||
for( std::size_t i=0; i < allTests.size(); ++i ) {
|
for( std::size_t i=0; i < allTests.size(); ++i ) {
|
||||||
if( testSpec.matches( allTests[i].getName() ) ) {
|
if( testSpec.matches( allTests[i].getName() ) ) {
|
||||||
|
if( aborting() ) {
|
||||||
|
m_reporter->Aborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
runTest( allTests[i] );
|
runTest( allTests[i] );
|
||||||
testsRun++;
|
testsRun++;
|
||||||
}
|
}
|
||||||
@ -108,14 +118,14 @@ namespace Catch {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
do {
|
do {
|
||||||
m_reporter->StartGroup( "test case run" );
|
// m_reporter->StartGroup( "test case run" );
|
||||||
m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() );
|
m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() );
|
||||||
runCurrentTest( redirectedCout, redirectedCerr );
|
runCurrentTest( redirectedCout, redirectedCerr );
|
||||||
m_reporter->EndGroup( "test case run", m_totals.delta( prevTotals ) );
|
// m_reporter->EndGroup( "test case run", m_totals.delta( prevTotals ) );
|
||||||
}
|
}
|
||||||
while( m_runningTest->hasUntestedSections() );
|
while( m_runningTest->hasUntestedSections() && !aborting() );
|
||||||
}
|
}
|
||||||
while( getCurrentContext().advanceGeneratorsForCurrentTest() );
|
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
|
||||||
|
|
||||||
delete m_runningTest;
|
delete m_runningTest;
|
||||||
m_runningTest = NULL;
|
m_runningTest = NULL;
|
||||||
@ -219,17 +229,26 @@ namespace Catch {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool aborting() const {
|
||||||
|
return m_totals.assertions.failed == m_config.getCutoff();
|
||||||
|
}
|
||||||
|
|
||||||
ResultAction::Value actOnCurrentResult() {
|
ResultAction::Value actOnCurrentResult() {
|
||||||
testEnded( m_currentResult );
|
testEnded( m_currentResult );
|
||||||
m_lastResult = m_currentResult;
|
m_lastResult = m_currentResult;
|
||||||
|
|
||||||
m_currentResult = ResultInfoBuilder();
|
m_currentResult = ResultInfoBuilder();
|
||||||
if( m_lastResult.ok() )
|
|
||||||
return ResultAction::None;
|
ResultAction::Value action = ResultAction::None;
|
||||||
else if( shouldDebugBreak() )
|
|
||||||
return ResultAction::DebugFailed;
|
if( !m_lastResult.ok() ) {
|
||||||
else
|
action = ResultAction::Failed;
|
||||||
return ResultAction::Failed;
|
if( shouldDebugBreak() )
|
||||||
|
action = (ResultAction::Value)( action | ResultAction::Debug );
|
||||||
|
if( aborting() )
|
||||||
|
action = (ResultAction::Value)( action | ResultAction::Abort );
|
||||||
|
}
|
||||||
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
|
void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
|
||||||
|
@ -57,7 +57,8 @@ namespace Catch {
|
|||||||
public:
|
public:
|
||||||
BasicReporter( const IReporterConfig& config )
|
BasicReporter( const IReporterConfig& config )
|
||||||
: m_config( config ),
|
: m_config( config ),
|
||||||
m_firstSectionInTestCase( true )
|
m_firstSectionInTestCase( true ),
|
||||||
|
m_aborted( false )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static std::string getDescription() {
|
static std::string getDescription() {
|
||||||
@ -66,29 +67,29 @@ namespace Catch {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ReportCounts( const std::string& label, const Counts& counts ) {
|
void ReportCounts( const std::string& label, const Counts& counts, const std::string& allPrefix = "All " ) {
|
||||||
if( counts.passed )
|
if( counts.passed )
|
||||||
m_config.stream() << counts.failed << " of " << counts.total() << " " << label << "s failed";
|
m_config.stream() << counts.failed << " of " << counts.total() << " " << label << "s failed";
|
||||||
else
|
else
|
||||||
m_config.stream() << ( counts.failed > 1 ? "All " : "" ) << pluralise( counts.failed, label ) << " failed";
|
m_config.stream() << ( counts.failed > 1 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReportCounts( const Totals& totals ) {
|
void ReportCounts( const Totals& totals, const std::string& allPrefix = "All " ) {
|
||||||
if( totals.assertions.total() == 0 ) {
|
if( totals.assertions.total() == 0 ) {
|
||||||
m_config.stream() << "No tests ran";
|
m_config.stream() << "No tests ran";
|
||||||
}
|
}
|
||||||
else if( totals.assertions.failed ) {
|
else if( totals.assertions.failed ) {
|
||||||
TextColour colour( TextColour::ResultError );
|
TextColour colour( TextColour::ResultError );
|
||||||
ReportCounts( "test case", totals.testCases );
|
ReportCounts( "test case", totals.testCases, allPrefix );
|
||||||
if( totals.testCases.failed > 0 ) {
|
if( totals.testCases.failed > 0 ) {
|
||||||
m_config.stream() << " (";
|
m_config.stream() << " (";
|
||||||
ReportCounts( "assertion", totals.assertions );
|
ReportCounts( "assertion", totals.assertions, allPrefix );
|
||||||
m_config.stream() << ")";
|
m_config.stream() << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TextColour colour( TextColour::ResultSuccess );
|
TextColour colour( TextColour::ResultSuccess );
|
||||||
m_config.stream() << "All tests passed ("
|
m_config.stream() << allPrefix << "tests passed ("
|
||||||
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
|
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
|
||||||
<< pluralise( totals.testCases.passed, "test case" ) << ")";
|
<< pluralise( totals.testCases.passed, "test case" ) << ")";
|
||||||
}
|
}
|
||||||
@ -104,10 +105,20 @@ namespace Catch {
|
|||||||
m_testingSpan = SpanInfo();
|
m_testingSpan = SpanInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Aborted() {
|
||||||
|
m_aborted = true;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void EndTesting( const Totals& totals ) {
|
virtual void EndTesting( const Totals& totals ) {
|
||||||
// Output the overall test results even if "Started Testing" was not emitted
|
// Output the overall test results even if "Started Testing" was not emitted
|
||||||
m_config.stream() << "\n[Testing completed. ";
|
if( m_aborted ) {
|
||||||
ReportCounts( totals);
|
m_config.stream() << "\n[Testing aborted. ";
|
||||||
|
ReportCounts( totals, "The first " );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_config.stream() << "\n[Testing completed. ";
|
||||||
|
ReportCounts( totals );
|
||||||
|
}
|
||||||
m_config.stream() << "]\n" << std::endl;
|
m_config.stream() << "]\n" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,6 +325,7 @@ namespace Catch {
|
|||||||
SpanInfo m_groupSpan;
|
SpanInfo m_groupSpan;
|
||||||
SpanInfo m_testSpan;
|
SpanInfo m_testSpan;
|
||||||
std::vector<SpanInfo> m_sectionSpans;
|
std::vector<SpanInfo> m_sectionSpans;
|
||||||
|
bool m_aborted;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@ -146,6 +146,10 @@ namespace Catch {
|
|||||||
m_stdErr << stdErr << "\n";
|
m_stdErr << stdErr << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Aborted() {
|
||||||
|
// !TBD
|
||||||
|
}
|
||||||
|
|
||||||
virtual void EndTesting( const Totals& ) {
|
virtual void EndTesting( const Totals& ) {
|
||||||
std::ostream& str = m_config.stream();
|
std::ostream& str = m_config.stream();
|
||||||
{
|
{
|
||||||
|
@ -123,6 +123,10 @@ namespace Catch {
|
|||||||
m_xml.endElement();
|
m_xml.endElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Aborted() {
|
||||||
|
// !TBD
|
||||||
|
}
|
||||||
|
|
||||||
virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
|
virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
|
||||||
m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
|
m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
|
||||||
m_xml.endElement();
|
m_xml.endElement();
|
||||||
|
@ -98,29 +98,21 @@ TEST_CASE( "Sections/nested3", "nested SECTION tests" )
|
|||||||
CHECK( runner.getLog() ==
|
CHECK( runner.getLog() ==
|
||||||
"\\[tc] ./Sections/nested/a/b\n"
|
"\\[tc] ./Sections/nested/a/b\n"
|
||||||
|
|
||||||
" \\[g] test case run\n"
|
" \\ [s] c\n"
|
||||||
" \\ [s] c\n"
|
" \\ [s] d (leaf)\n"
|
||||||
" \\ [s] d (leaf)\n"
|
" / [s] d (leaf)\n"
|
||||||
" / [s] d (leaf)\n"
|
" / [s] c\n"
|
||||||
" / [s] c\n"
|
|
||||||
" /[g] test case run\n"
|
|
||||||
|
|
||||||
" \\[g] test case run\n"
|
" \\ [s] c\n"
|
||||||
" \\ [s] c\n"
|
" \\ [s] e (leaf)\n"
|
||||||
" \\ [s] e (leaf)\n"
|
" / [s] e (leaf)\n"
|
||||||
" / [s] e (leaf)\n"
|
" / [s] c\n"
|
||||||
" / [s] c\n"
|
|
||||||
" /[g] test case run\n"
|
|
||||||
|
|
||||||
" \\[g] test case run\n"
|
" \\ [s] c\n"
|
||||||
" \\ [s] c\n"
|
" / [s] c\n"
|
||||||
" / [s] c\n"
|
|
||||||
" /[g] test case run\n"
|
|
||||||
|
|
||||||
" \\[g] test case run\n"
|
" \\ [s] f (leaf)\n"
|
||||||
" \\ [s] f (leaf)\n"
|
" / [s] f (leaf)\n"
|
||||||
" / [s] f (leaf)\n"
|
|
||||||
" /[g] test case run\n"
|
|
||||||
|
|
||||||
"/[tc] ./Sections/nested/a/b\n" );
|
"/[tc] ./Sections/nested/a/b\n" );
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ TEST_CASE( "selftest/parser", "" ) {
|
|||||||
CHECK( config.getTestSpecs().empty() );
|
CHECK( config.getTestSpecs().empty() );
|
||||||
CHECK( config.shouldDebugBreak() == false );
|
CHECK( config.shouldDebugBreak() == false );
|
||||||
CHECK( config.showHelp() == false );
|
CHECK( config.showHelp() == false );
|
||||||
|
CHECK( config.getCutoff() == -1 );
|
||||||
CHECK( dynamic_cast<Catch::BasicReporter*>( config.getReporter().get() ) );
|
CHECK( dynamic_cast<Catch::BasicReporter*>( config.getReporter().get() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,4 +201,39 @@ TEST_CASE( "selftest/parser", "" ) {
|
|||||||
REQUIRE_THAT( config.getMessage(), Contains( "not accept" ) );
|
REQUIRE_THAT( config.getMessage(), Contains( "not accept" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION( "cutoff", "" ) {
|
||||||
|
SECTION( "-c", "" ) {
|
||||||
|
const char* argv[] = { "test", "-c" };
|
||||||
|
Catch::Config config;
|
||||||
|
CHECK( parseIntoConfig( argv, config ) );
|
||||||
|
|
||||||
|
REQUIRE( config.getCutoff() == 1 );
|
||||||
|
}
|
||||||
|
SECTION( "-c/2", "" ) {
|
||||||
|
const char* argv[] = { "test", "-c", "2" };
|
||||||
|
Catch::Config config;
|
||||||
|
CHECK( parseIntoConfig( argv, config ) );
|
||||||
|
|
||||||
|
REQUIRE( config.getCutoff() == 2 );
|
||||||
|
}
|
||||||
|
SECTION( "-c/error", "cutoff only takes one argument" ) {
|
||||||
|
const char* argv[] = { "test", "-c", "1", "2" };
|
||||||
|
Catch::Config config;
|
||||||
|
CHECK( parseIntoConfig( argv, config ) == false );
|
||||||
|
|
||||||
|
REQUIRE_THAT( config.getMessage(), Contains( "accepts" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION( "combinations", "" ) {
|
||||||
|
SECTION( "-c -b", "" ) {
|
||||||
|
const char* argv[] = { "test", "-c", "-b" };
|
||||||
|
Catch::Config config;
|
||||||
|
CHECK( parseIntoConfig( argv, config ) );
|
||||||
|
|
||||||
|
REQUIRE( config.getCutoff() == 1 );
|
||||||
|
REQUIRE( config.shouldDebugBreak() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,8 @@ namespace Catch {
|
|||||||
openLabel( recordTestCases, testInfo.getName() );
|
openLabel( recordTestCases, testInfo.getName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Aborted(){}
|
||||||
|
|
||||||
virtual void EndTestCase( const TestCaseInfo& testInfo,
|
virtual void EndTestCase( const TestCaseInfo& testInfo,
|
||||||
const Totals&,
|
const Totals&,
|
||||||
const std::string&,
|
const std::string&,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Generated: 2012-05-31 19:40:06.141562
|
* Generated: 2012-06-01 19:40:15.883536
|
||||||
* ----------------------------------------------------------
|
* ----------------------------------------------------------
|
||||||
* This file has been merged from multiple headers. Please don't edit it directly
|
* This file has been merged from multiple headers. Please don't edit it directly
|
||||||
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
|
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
|
||||||
@ -424,6 +424,7 @@ namespace Catch
|
|||||||
virtual void StartSection( const std::string& sectionName, const std::string& description ) = 0;
|
virtual void StartSection( const std::string& sectionName, const std::string& description ) = 0;
|
||||||
virtual void EndSection( const std::string& sectionName, const Counts& assertions ) = 0;
|
virtual void EndSection( const std::string& sectionName, const Counts& assertions ) = 0;
|
||||||
virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0;
|
virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0;
|
||||||
|
virtual void Aborted() = 0;
|
||||||
virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr ) = 0;
|
virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr ) = 0;
|
||||||
virtual void Result( const ResultInfo& result ) = 0;
|
virtual void Result( const ResultInfo& result ) = 0;
|
||||||
};
|
};
|
||||||
@ -768,9 +769,9 @@ struct ResultWas { enum OfType {
|
|||||||
|
|
||||||
struct ResultAction { enum Value {
|
struct ResultAction { enum Value {
|
||||||
None,
|
None,
|
||||||
Failed = 1, // Failure - but no debug break if Debug bit not set
|
Failed = 1, // Failure - but no debug break if Debug bit not set
|
||||||
DebugFailed = 3 // Indicates that the debugger should break, if possible
|
Debug = 2, // If this bit is set, invoke the debugger
|
||||||
|
Abort = 4 // Test run should abort
|
||||||
}; };
|
}; };
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1469,7 +1470,8 @@ inline bool isTrue( bool value ){ return value; }
|
|||||||
#define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \
|
#define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \
|
||||||
if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) \
|
if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) \
|
||||||
{ \
|
{ \
|
||||||
if( internal_catch_action == Catch::ResultAction::DebugFailed ) BreakIntoDebugger(); \
|
if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \
|
||||||
|
if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \
|
||||||
if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \
|
if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \
|
||||||
if( Catch::isTrue( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \
|
if( Catch::isTrue( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \
|
||||||
}
|
}
|
||||||
@ -2401,7 +2403,8 @@ namespace Catch {
|
|||||||
m_showHelp( false ),
|
m_showHelp( false ),
|
||||||
m_streambuf( NULL ),
|
m_streambuf( NULL ),
|
||||||
m_os( std::cout.rdbuf() ),
|
m_os( std::cout.rdbuf() ),
|
||||||
m_includeWhichResults( Include::FailedOnly )
|
m_includeWhichResults( Include::FailedOnly ),
|
||||||
|
m_cutoff( -1 )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~Config() {
|
~Config() {
|
||||||
@ -2516,6 +2519,14 @@ namespace Catch {
|
|||||||
return m_includeWhichResults == Include::SuccessfulResults;
|
return m_includeWhichResults == Include::SuccessfulResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getCutoff() const {
|
||||||
|
return m_cutoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCutoff( int cutoff ) {
|
||||||
|
m_cutoff = cutoff;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ptr<IReporter> m_reporter;
|
Ptr<IReporter> m_reporter;
|
||||||
std::string m_filename;
|
std::string m_filename;
|
||||||
@ -2528,6 +2539,7 @@ namespace Catch {
|
|||||||
mutable std::ostream m_os;
|
mutable std::ostream m_os;
|
||||||
Include::WhichResults m_includeWhichResults;
|
Include::WhichResults m_includeWhichResults;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
int m_cutoff;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NewConfig {
|
struct NewConfig {
|
||||||
@ -2786,7 +2798,13 @@ namespace Catch {
|
|||||||
const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests();
|
const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests();
|
||||||
for( std::size_t i=0; i < allTests.size(); ++i ) {
|
for( std::size_t i=0; i < allTests.size(); ++i ) {
|
||||||
if( runHiddenTests || !allTests[i].isHidden() )
|
if( runHiddenTests || !allTests[i].isHidden() )
|
||||||
runTest( allTests[i] );
|
{
|
||||||
|
if( aborting() ) {
|
||||||
|
m_reporter->Aborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
runTest( allTests[i] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2797,6 +2815,10 @@ namespace Catch {
|
|||||||
std::size_t testsRun = 0;
|
std::size_t testsRun = 0;
|
||||||
for( std::size_t i=0; i < allTests.size(); ++i ) {
|
for( std::size_t i=0; i < allTests.size(); ++i ) {
|
||||||
if( testSpec.matches( allTests[i].getName() ) ) {
|
if( testSpec.matches( allTests[i].getName() ) ) {
|
||||||
|
if( aborting() ) {
|
||||||
|
m_reporter->Aborted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
runTest( allTests[i] );
|
runTest( allTests[i] );
|
||||||
testsRun++;
|
testsRun++;
|
||||||
}
|
}
|
||||||
@ -2816,14 +2838,14 @@ namespace Catch {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
do {
|
do {
|
||||||
m_reporter->StartGroup( "test case run" );
|
// m_reporter->StartGroup( "test case run" );
|
||||||
m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() );
|
m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() );
|
||||||
runCurrentTest( redirectedCout, redirectedCerr );
|
runCurrentTest( redirectedCout, redirectedCerr );
|
||||||
m_reporter->EndGroup( "test case run", m_totals.delta( prevTotals ) );
|
// m_reporter->EndGroup( "test case run", m_totals.delta( prevTotals ) );
|
||||||
}
|
}
|
||||||
while( m_runningTest->hasUntestedSections() );
|
while( m_runningTest->hasUntestedSections() && !aborting() );
|
||||||
}
|
}
|
||||||
while( getCurrentContext().advanceGeneratorsForCurrentTest() );
|
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
|
||||||
|
|
||||||
delete m_runningTest;
|
delete m_runningTest;
|
||||||
m_runningTest = NULL;
|
m_runningTest = NULL;
|
||||||
@ -2927,17 +2949,26 @@ namespace Catch {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool aborting() const {
|
||||||
|
return m_totals.assertions.failed == m_config.getCutoff();
|
||||||
|
}
|
||||||
|
|
||||||
ResultAction::Value actOnCurrentResult() {
|
ResultAction::Value actOnCurrentResult() {
|
||||||
testEnded( m_currentResult );
|
testEnded( m_currentResult );
|
||||||
m_lastResult = m_currentResult;
|
m_lastResult = m_currentResult;
|
||||||
|
|
||||||
m_currentResult = ResultInfoBuilder();
|
m_currentResult = ResultInfoBuilder();
|
||||||
if( m_lastResult.ok() )
|
|
||||||
return ResultAction::None;
|
ResultAction::Value action = ResultAction::None;
|
||||||
else if( shouldDebugBreak() )
|
|
||||||
return ResultAction::DebugFailed;
|
if( !m_lastResult.ok() ) {
|
||||||
else
|
action = ResultAction::Failed;
|
||||||
return ResultAction::Failed;
|
if( shouldDebugBreak() )
|
||||||
|
action = (ResultAction::Value)( action | ResultAction::Debug );
|
||||||
|
if( aborting() )
|
||||||
|
action = (ResultAction::Value)( action | ResultAction::Abort );
|
||||||
|
}
|
||||||
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
|
void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
|
||||||
@ -3565,6 +3596,19 @@ namespace Catch {
|
|||||||
throw std::domain_error( cmd.name() + " does not accept arguments" );
|
throw std::domain_error( cmd.name() + " does not accept arguments" );
|
||||||
config.setShowHelp( true );
|
config.setShowHelp( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( Command cmd = parser.find( "-c", "--cutoff" ) ) {
|
||||||
|
if( cmd.argsCount() > 1 )
|
||||||
|
throw std::domain_error( cmd.name() + " only accepts 0-1 arguments" );
|
||||||
|
int threshold = 1;
|
||||||
|
if( cmd.argsCount() == 1 )
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << cmd[0];
|
||||||
|
ss >> threshold;
|
||||||
|
}
|
||||||
|
config.setCutoff( threshold );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch( std::exception& ex ) {
|
catch( std::exception& ex ) {
|
||||||
config.setError( ex.what() );
|
config.setError( ex.what() );
|
||||||
@ -3694,7 +3738,8 @@ namespace Catch {
|
|||||||
public:
|
public:
|
||||||
BasicReporter( const IReporterConfig& config )
|
BasicReporter( const IReporterConfig& config )
|
||||||
: m_config( config ),
|
: m_config( config ),
|
||||||
m_firstSectionInTestCase( true )
|
m_firstSectionInTestCase( true ),
|
||||||
|
m_aborted( false )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static std::string getDescription() {
|
static std::string getDescription() {
|
||||||
@ -3703,29 +3748,29 @@ namespace Catch {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ReportCounts( const std::string& label, const Counts& counts ) {
|
void ReportCounts( const std::string& label, const Counts& counts, const std::string& allPrefix = "All " ) {
|
||||||
if( counts.passed )
|
if( counts.passed )
|
||||||
m_config.stream() << counts.failed << " of " << counts.total() << " " << label << "s failed";
|
m_config.stream() << counts.failed << " of " << counts.total() << " " << label << "s failed";
|
||||||
else
|
else
|
||||||
m_config.stream() << ( counts.failed > 1 ? "All " : "" ) << pluralise( counts.failed, label ) << " failed";
|
m_config.stream() << ( counts.failed > 1 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReportCounts( const Totals& totals ) {
|
void ReportCounts( const Totals& totals, const std::string& allPrefix = "All " ) {
|
||||||
if( totals.assertions.total() == 0 ) {
|
if( totals.assertions.total() == 0 ) {
|
||||||
m_config.stream() << "No tests ran";
|
m_config.stream() << "No tests ran";
|
||||||
}
|
}
|
||||||
else if( totals.assertions.failed ) {
|
else if( totals.assertions.failed ) {
|
||||||
TextColour colour( TextColour::ResultError );
|
TextColour colour( TextColour::ResultError );
|
||||||
ReportCounts( "test case", totals.testCases );
|
ReportCounts( "test case", totals.testCases, allPrefix );
|
||||||
if( totals.testCases.failed > 0 ) {
|
if( totals.testCases.failed > 0 ) {
|
||||||
m_config.stream() << " (";
|
m_config.stream() << " (";
|
||||||
ReportCounts( "assertion", totals.assertions );
|
ReportCounts( "assertion", totals.assertions, allPrefix );
|
||||||
m_config.stream() << ")";
|
m_config.stream() << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TextColour colour( TextColour::ResultSuccess );
|
TextColour colour( TextColour::ResultSuccess );
|
||||||
m_config.stream() << "All tests passed ("
|
m_config.stream() << allPrefix << "tests passed ("
|
||||||
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
|
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
|
||||||
<< pluralise( totals.testCases.passed, "test case" ) << ")";
|
<< pluralise( totals.testCases.passed, "test case" ) << ")";
|
||||||
}
|
}
|
||||||
@ -3741,10 +3786,20 @@ namespace Catch {
|
|||||||
m_testingSpan = SpanInfo();
|
m_testingSpan = SpanInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Aborted() {
|
||||||
|
m_aborted = true;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void EndTesting( const Totals& totals ) {
|
virtual void EndTesting( const Totals& totals ) {
|
||||||
// Output the overall test results even if "Started Testing" was not emitted
|
// Output the overall test results even if "Started Testing" was not emitted
|
||||||
m_config.stream() << "\n[Testing completed. ";
|
if( m_aborted ) {
|
||||||
ReportCounts( totals);
|
m_config.stream() << "\n[Testing aborted. ";
|
||||||
|
ReportCounts( totals, "The first " );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_config.stream() << "\n[Testing completed. ";
|
||||||
|
ReportCounts( totals );
|
||||||
|
}
|
||||||
m_config.stream() << "]\n" << std::endl;
|
m_config.stream() << "]\n" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3951,6 +4006,7 @@ namespace Catch {
|
|||||||
SpanInfo m_groupSpan;
|
SpanInfo m_groupSpan;
|
||||||
SpanInfo m_testSpan;
|
SpanInfo m_testSpan;
|
||||||
std::vector<SpanInfo> m_sectionSpans;
|
std::vector<SpanInfo> m_sectionSpans;
|
||||||
|
bool m_aborted;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
@ -4268,6 +4324,10 @@ namespace Catch {
|
|||||||
m_xml.endElement();
|
m_xml.endElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Aborted() {
|
||||||
|
// !TBD
|
||||||
|
}
|
||||||
|
|
||||||
virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
|
virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
|
||||||
m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
|
m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
|
||||||
m_xml.endElement();
|
m_xml.endElement();
|
||||||
@ -4416,6 +4476,10 @@ namespace Catch {
|
|||||||
m_stdErr << stdErr << "\n";
|
m_stdErr << stdErr << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Aborted() {
|
||||||
|
// !TBD
|
||||||
|
}
|
||||||
|
|
||||||
virtual void EndTesting( const Totals& ) {
|
virtual void EndTesting( const Totals& ) {
|
||||||
std::ostream& str = m_config.stream();
|
std::ostream& str = m_config.stream();
|
||||||
{
|
{
|
||||||
@ -4557,6 +4621,7 @@ namespace Catch {
|
|||||||
<< "\t-s, --success\n"
|
<< "\t-s, --success\n"
|
||||||
<< "\t-b, --break\n"
|
<< "\t-b, --break\n"
|
||||||
<< "\t-n, --name <name>\n\n"
|
<< "\t-n, --name <name>\n\n"
|
||||||
|
<< "\t-c, --cutoff [#]\n\n"
|
||||||
<< "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl;
|
<< "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl;
|
||||||
}
|
}
|
||||||
inline void showHelp( std::string exeName ) {
|
inline void showHelp( std::string exeName ) {
|
||||||
|
Loading…
Reference in New Issue
Block a user