From 19b2aa6187092367e2bb57e1288dc48618b235e0 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Fri, 1 Jun 2012 19:40:27 +0100 Subject: [PATCH] Added cutoff option to command line Aborts testing after a certain number of assertion failures --- include/catch_runner.hpp | 1 + include/internal/catch_capture.hpp | 3 +- include/internal/catch_commandline.hpp | 13 +++ include/internal/catch_config.hpp | 12 +- include/internal/catch_interfaces_reporter.h | 3 +- include/internal/catch_result_type.h | 6 +- include/internal/catch_runner_impl.hpp | 43 +++++-- include/reporters/catch_reporter_basic.hpp | 30 +++-- include/reporters/catch_reporter_junit.hpp | 4 + include/reporters/catch_reporter_xml.hpp | 4 + projects/SelfTest/MiscTests.cpp | 32 ++--- projects/SelfTest/TestMain.cpp | 36 ++++++ projects/SelfTest/catch_self_test.hpp | 2 + single_include/catch.hpp | 117 ++++++++++++++----- 14 files changed, 233 insertions(+), 73 deletions(-) diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index 5be943de..107502f3 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -84,6 +84,7 @@ namespace Catch { << "\t-s, --success\n" << "\t-b, --break\n" << "\t-n, --name \n\n" + << "\t-c, --cutoff [#]\n\n" << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; } inline void showHelp( std::string exeName ) { diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 90cd1982..84233c3f 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -52,7 +52,8 @@ inline bool isTrue( bool value ){ return value; } #define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \ 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( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \ } diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index f1e49da3..75358563 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -161,6 +161,19 @@ namespace Catch { throw std::domain_error( cmd.name() + " does not accept arguments" ); 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 ) { config.setError( ex.what() ); diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp index a15904b2..23d60bb2 100644 --- a/include/internal/catch_config.hpp +++ b/include/internal/catch_config.hpp @@ -50,7 +50,8 @@ namespace Catch { m_showHelp( false ), m_streambuf( NULL ), m_os( std::cout.rdbuf() ), - m_includeWhichResults( Include::FailedOnly ) + m_includeWhichResults( Include::FailedOnly ), + m_cutoff( -1 ) {} ~Config() { @@ -165,6 +166,14 @@ namespace Catch { return m_includeWhichResults == Include::SuccessfulResults; } + int getCutoff() const { + return m_cutoff; + } + + void setCutoff( int cutoff ) { + m_cutoff = cutoff; + } + private: Ptr m_reporter; std::string m_filename; @@ -177,6 +186,7 @@ namespace Catch { mutable std::ostream m_os; Include::WhichResults m_includeWhichResults; std::string m_name; + int m_cutoff; }; struct NewConfig { diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h index 0be38773..47cf1830 100644 --- a/include/internal/catch_interfaces_reporter.h +++ b/include/internal/catch_interfaces_reporter.h @@ -38,7 +38,8 @@ namespace Catch 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 StartTestCase( const TestCaseInfo& testInfo ) = 0; - virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr ) = 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 Result( const ResultInfo& result ) = 0; }; diff --git a/include/internal/catch_result_type.h b/include/internal/catch_result_type.h index f7d14ed9..6f61f8c0 100644 --- a/include/internal/catch_result_type.h +++ b/include/internal/catch_result_type.h @@ -30,9 +30,9 @@ struct ResultWas { enum OfType { struct ResultAction { enum Value { None, - Failed = 1, // Failure - but no debug break if Debug bit not set - DebugFailed = 3 // Indicates that the debugger should break, if possible - + Failed = 1, // Failure - but no debug break if Debug bit not set + Debug = 2, // If this bit is set, invoke the debugger + Abort = 4 // Test run should abort }; }; } diff --git a/include/internal/catch_runner_impl.hpp b/include/internal/catch_runner_impl.hpp index 13e6a5a4..5f54dca9 100644 --- a/include/internal/catch_runner_impl.hpp +++ b/include/internal/catch_runner_impl.hpp @@ -78,7 +78,13 @@ namespace Catch { const std::vector& allTests = getCurrentContext().getTestCaseRegistry().getAllTests(); for( std::size_t i=0; i < allTests.size(); ++i ) { 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; for( std::size_t i=0; i < allTests.size(); ++i ) { if( testSpec.matches( allTests[i].getName() ) ) { + if( aborting() ) { + m_reporter->Aborted(); + break; + } runTest( allTests[i] ); testsRun++; } @@ -108,14 +118,14 @@ namespace Catch { do { do { - m_reporter->StartGroup( "test case run" ); +// m_reporter->StartGroup( "test case run" ); m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() ); 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; m_runningTest = NULL; @@ -168,7 +178,7 @@ namespace Catch { else m_reporter->Result( result ); } - + virtual bool sectionStarted ( const std::string& name, const std::string& description, @@ -218,18 +228,27 @@ namespace Catch { } private: + + bool aborting() const { + return m_totals.assertions.failed == m_config.getCutoff(); + } ResultAction::Value actOnCurrentResult() { testEnded( m_currentResult ); m_lastResult = m_currentResult; m_currentResult = ResultInfoBuilder(); - if( m_lastResult.ok() ) - return ResultAction::None; - else if( shouldDebugBreak() ) - return ResultAction::DebugFailed; - else - return ResultAction::Failed; + + ResultAction::Value action = ResultAction::None; + + if( !m_lastResult.ok() ) { + action = 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 ) { diff --git a/include/reporters/catch_reporter_basic.hpp b/include/reporters/catch_reporter_basic.hpp index b8afa422..f5fc6ee1 100644 --- a/include/reporters/catch_reporter_basic.hpp +++ b/include/reporters/catch_reporter_basic.hpp @@ -57,7 +57,8 @@ namespace Catch { public: BasicReporter( const IReporterConfig& config ) : m_config( config ), - m_firstSectionInTestCase( true ) + m_firstSectionInTestCase( true ), + m_aborted( false ) {} static std::string getDescription() { @@ -66,29 +67,29 @@ namespace Catch { 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 ) m_config.stream() << counts.failed << " of " << counts.total() << " " << label << "s failed"; 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 ) { m_config.stream() << "No tests ran"; } else if( totals.assertions.failed ) { TextColour colour( TextColour::ResultError ); - ReportCounts( "test case", totals.testCases ); + ReportCounts( "test case", totals.testCases, allPrefix ); if( totals.testCases.failed > 0 ) { m_config.stream() << " ("; - ReportCounts( "assertion", totals.assertions ); + ReportCounts( "assertion", totals.assertions, allPrefix ); m_config.stream() << ")"; } } else { TextColour colour( TextColour::ResultSuccess ); - m_config.stream() << "All tests passed (" + m_config.stream() << allPrefix << "tests passed (" << pluralise( totals.assertions.passed, "assertion" ) << " in " << pluralise( totals.testCases.passed, "test case" ) << ")"; } @@ -104,10 +105,20 @@ namespace Catch { m_testingSpan = SpanInfo(); } + virtual void Aborted() { + m_aborted = true; + } + virtual void EndTesting( const Totals& totals ) { // Output the overall test results even if "Started Testing" was not emitted - m_config.stream() << "\n[Testing completed. "; - ReportCounts( totals); + if( m_aborted ) { + 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; } @@ -314,6 +325,7 @@ namespace Catch { SpanInfo m_groupSpan; SpanInfo m_testSpan; std::vector m_sectionSpans; + bool m_aborted; }; } // end namespace Catch diff --git a/include/reporters/catch_reporter_junit.hpp b/include/reporters/catch_reporter_junit.hpp index cfe45a86..0f9dbd93 100644 --- a/include/reporters/catch_reporter_junit.hpp +++ b/include/reporters/catch_reporter_junit.hpp @@ -146,6 +146,10 @@ namespace Catch { m_stdErr << stdErr << "\n"; } + virtual void Aborted() { + // !TBD + } + virtual void EndTesting( const Totals& ) { std::ostream& str = m_config.stream(); { diff --git a/include/reporters/catch_reporter_xml.hpp b/include/reporters/catch_reporter_xml.hpp index 122c81fa..69243ba3 100644 --- a/include/reporters/catch_reporter_xml.hpp +++ b/include/reporters/catch_reporter_xml.hpp @@ -122,6 +122,10 @@ namespace Catch { if( resultInfo.hasExpression() ) m_xml.endElement(); } + + virtual void Aborted() { + // !TBD + } virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) { m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess ); diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index b7a93b4d..a00e7958 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -98,29 +98,21 @@ TEST_CASE( "Sections/nested3", "nested SECTION tests" ) CHECK( runner.getLog() == "\\[tc] ./Sections/nested/a/b\n" - " \\[g] test case run\n" - " \\ [s] c\n" - " \\ [s] d (leaf)\n" - " / [s] d (leaf)\n" - " / [s] c\n" - " /[g] test case run\n" + " \\ [s] c\n" + " \\ [s] d (leaf)\n" + " / [s] d (leaf)\n" + " / [s] c\n" - " \\[g] test case run\n" - " \\ [s] c\n" - " \\ [s] e (leaf)\n" - " / [s] e (leaf)\n" - " / [s] c\n" - " /[g] test case run\n" + " \\ [s] c\n" + " \\ [s] e (leaf)\n" + " / [s] e (leaf)\n" + " / [s] c\n" - " \\[g] test case run\n" - " \\ [s] c\n" - " / [s] c\n" - " /[g] test case run\n" + " \\ [s] c\n" + " / [s] c\n" - " \\[g] test case run\n" - " \\ [s] f (leaf)\n" - " / [s] f (leaf)\n" - " /[g] test case run\n" + " \\ [s] f (leaf)\n" + " / [s] f (leaf)\n" "/[tc] ./Sections/nested/a/b\n" ); diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index eba029be..3185e16a 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -74,6 +74,7 @@ TEST_CASE( "selftest/parser", "" ) { CHECK( config.getTestSpecs().empty() ); CHECK( config.shouldDebugBreak() == false ); CHECK( config.showHelp() == false ); + CHECK( config.getCutoff() == -1 ); CHECK( dynamic_cast( config.getReporter().get() ) ); } @@ -200,4 +201,39 @@ TEST_CASE( "selftest/parser", "" ) { 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() ); + } + } + } diff --git a/projects/SelfTest/catch_self_test.hpp b/projects/SelfTest/catch_self_test.hpp index ef87f8d3..94f45623 100644 --- a/projects/SelfTest/catch_self_test.hpp +++ b/projects/SelfTest/catch_self_test.hpp @@ -77,6 +77,8 @@ namespace Catch { openLabel( recordTestCases, testInfo.getName() ); } + virtual void Aborted(){} + virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals&, const std::string&, diff --git a/single_include/catch.hpp b/single_include/catch.hpp index 624b2d63..fc8ee713 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -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 * 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 EndSection( const std::string& sectionName, const Counts& assertions ) = 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 Result( const ResultInfo& result ) = 0; }; @@ -768,9 +769,9 @@ struct ResultWas { enum OfType { struct ResultAction { enum Value { None, - Failed = 1, // Failure - but no debug break if Debug bit not set - DebugFailed = 3 // Indicates that the debugger should break, if possible - + Failed = 1, // Failure - but no debug break if Debug bit not set + 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 ) \ 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( 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_streambuf( NULL ), m_os( std::cout.rdbuf() ), - m_includeWhichResults( Include::FailedOnly ) + m_includeWhichResults( Include::FailedOnly ), + m_cutoff( -1 ) {} ~Config() { @@ -2516,6 +2519,14 @@ namespace Catch { return m_includeWhichResults == Include::SuccessfulResults; } + int getCutoff() const { + return m_cutoff; + } + + void setCutoff( int cutoff ) { + m_cutoff = cutoff; + } + private: Ptr m_reporter; std::string m_filename; @@ -2528,6 +2539,7 @@ namespace Catch { mutable std::ostream m_os; Include::WhichResults m_includeWhichResults; std::string m_name; + int m_cutoff; }; struct NewConfig { @@ -2786,7 +2798,13 @@ namespace Catch { const std::vector& allTests = getCurrentContext().getTestCaseRegistry().getAllTests(); for( std::size_t i=0; i < allTests.size(); ++i ) { 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; for( std::size_t i=0; i < allTests.size(); ++i ) { if( testSpec.matches( allTests[i].getName() ) ) { + if( aborting() ) { + m_reporter->Aborted(); + break; + } runTest( allTests[i] ); testsRun++; } @@ -2816,14 +2838,14 @@ namespace Catch { do { do { - m_reporter->StartGroup( "test case run" ); +// m_reporter->StartGroup( "test case run" ); m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() ); 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; m_runningTest = NULL; @@ -2927,17 +2949,26 @@ namespace Catch { private: + bool aborting() const { + return m_totals.assertions.failed == m_config.getCutoff(); + } + ResultAction::Value actOnCurrentResult() { testEnded( m_currentResult ); m_lastResult = m_currentResult; m_currentResult = ResultInfoBuilder(); - if( m_lastResult.ok() ) - return ResultAction::None; - else if( shouldDebugBreak() ) - return ResultAction::DebugFailed; - else - return ResultAction::Failed; + + ResultAction::Value action = ResultAction::None; + + if( !m_lastResult.ok() ) { + action = 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 ) { @@ -3565,6 +3596,19 @@ namespace Catch { throw std::domain_error( cmd.name() + " does not accept arguments" ); 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 ) { config.setError( ex.what() ); @@ -3694,7 +3738,8 @@ namespace Catch { public: BasicReporter( const IReporterConfig& config ) : m_config( config ), - m_firstSectionInTestCase( true ) + m_firstSectionInTestCase( true ), + m_aborted( false ) {} static std::string getDescription() { @@ -3703,29 +3748,29 @@ namespace Catch { 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 ) m_config.stream() << counts.failed << " of " << counts.total() << " " << label << "s failed"; 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 ) { m_config.stream() << "No tests ran"; } else if( totals.assertions.failed ) { TextColour colour( TextColour::ResultError ); - ReportCounts( "test case", totals.testCases ); + ReportCounts( "test case", totals.testCases, allPrefix ); if( totals.testCases.failed > 0 ) { m_config.stream() << " ("; - ReportCounts( "assertion", totals.assertions ); + ReportCounts( "assertion", totals.assertions, allPrefix ); m_config.stream() << ")"; } } else { TextColour colour( TextColour::ResultSuccess ); - m_config.stream() << "All tests passed (" + m_config.stream() << allPrefix << "tests passed (" << pluralise( totals.assertions.passed, "assertion" ) << " in " << pluralise( totals.testCases.passed, "test case" ) << ")"; } @@ -3741,10 +3786,20 @@ namespace Catch { m_testingSpan = SpanInfo(); } + virtual void Aborted() { + m_aborted = true; + } + virtual void EndTesting( const Totals& totals ) { // Output the overall test results even if "Started Testing" was not emitted - m_config.stream() << "\n[Testing completed. "; - ReportCounts( totals); + if( m_aborted ) { + 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; } @@ -3951,6 +4006,7 @@ namespace Catch { SpanInfo m_groupSpan; SpanInfo m_testSpan; std::vector m_sectionSpans; + bool m_aborted; }; } // end namespace Catch @@ -4268,6 +4324,10 @@ namespace Catch { m_xml.endElement(); } + virtual void Aborted() { + // !TBD + } + virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) { m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess ); m_xml.endElement(); @@ -4416,6 +4476,10 @@ namespace Catch { m_stdErr << stdErr << "\n"; } + virtual void Aborted() { + // !TBD + } + virtual void EndTesting( const Totals& ) { std::ostream& str = m_config.stream(); { @@ -4557,6 +4621,7 @@ namespace Catch { << "\t-s, --success\n" << "\t-b, --break\n" << "\t-n, --name \n\n" + << "\t-c, --cutoff [#]\n\n" << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; } inline void showHelp( std::string exeName ) {