From 42aef1d99cc22bb92f80f6e3fb13f2aab071646c Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Sun, 13 Jan 2013 21:51:44 +0000 Subject: [PATCH] Fairly major reworking of console reporter (still in progress). Changed reporter interface a bit. --- include/catch_runner.hpp | 61 +--- include/internal/catch_commandline.hpp | 2 +- include/internal/catch_common.h | 6 +- include/internal/catch_impl.hpp | 1 + include/internal/catch_interfaces_reporter.h | 13 +- include/internal/catch_line_wrap.h | 20 ++ include/internal/catch_line_wrap.hpp | 67 ++++ .../catch_notimplemented_exception.hpp | 2 +- include/internal/catch_runner_impl.hpp | 14 +- include/reporters/catch_reporter_basic.hpp | 2 +- include/reporters/catch_reporter_console.hpp | 321 ++++++++---------- projects/SelfTest/GeneratorTests.cpp | 14 + projects/SelfTest/TestMain.cpp | 10 +- projects/SelfTest/catch_self_test.cpp | 4 +- projects/SelfTest/catch_self_test.hpp | 18 +- .../CatchSelfTest.xcodeproj/project.pbxproj | 8 + .../CatchSelfTest/catch_line_wrap.cpp | 2 + 17 files changed, 306 insertions(+), 259 deletions(-) create mode 100644 include/internal/catch_line_wrap.h create mode 100644 include/internal/catch_line_wrap.hpp create mode 100644 projects/XCode4/CatchSelfTest/CatchSelfTest/catch_line_wrap.cpp diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index 71f91981..95c466b9 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -13,6 +13,7 @@ #include "internal/catch_runner_impl.hpp" #include "internal/catch_test_spec.h" #include "internal/catch_version.h" +#include "internal/catch_line_wrap.h" #include #include @@ -42,13 +43,10 @@ namespace Catch { Runner context( m_configWrapper, m_reporter ); // This Runner will be renamed Context Totals totals; - std::vector::const_iterator it = filterGroups.begin(); - std::vector::const_iterator itEnd = filterGroups.end(); - - for(; it != itEnd && !context.aborting(); ++it ) { - context.testGroupStarting( it->getName() ); - totals += runTestsForGroup( context, *it ); - context.testGroupEnded( it->getName(), totals ); + for( std::size_t i=0; i < filterGroups.size() && !context.aborting(); ++i ) { + context.testGroupStarting( filterGroups[i].getName(), i, filterGroups.size() ); + totals += runTestsForGroup( context, filterGroups[i] ); + context.testGroupEnded( filterGroups[i].getName(), totals, i, filterGroups.size() ); } return totals; } @@ -153,50 +151,6 @@ namespace Catch { os << "\nFor more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line\n" << std::endl; } - inline void addIndent( std::ostream& os, std::size_t indent ) { - while( indent-- > 0 ) - os << ' '; - } - - inline void recursivelyWrapLine( std::ostream& os, std::string paragraph, std::size_t columns, std::size_t indent ) { - std::size_t width = columns-indent; - std::size_t tab = 0; - std::size_t wrapPoint = width; - for( std::size_t pos = 0; pos < paragraph.size(); ++pos ) { - if( pos == width ) { - addIndent( os, indent ); - os << paragraph.substr( 0, wrapPoint ) << "\n"; - return recursivelyWrapLine( os, paragraph.substr( wrapPoint+1 ), columns, indent+tab ); - } - if( paragraph[pos] == '\t' ) { - tab = pos; - paragraph = paragraph.substr( 0, tab ) + paragraph.substr( tab+1 ); - pos--; - } - else if( paragraph[pos] == ' ' ) { - wrapPoint = pos; - } - } - addIndent( os, indent ); - os << paragraph << "\n"; - } - - inline std::string addLineBreaks( const std::string& str, std::size_t columns, std::size_t indent = 0 ) { - std::ostringstream oss; - std::string::size_type pos = 0; - std::string::size_type newline = str.find_first_of( '\n' ); - while( newline != std::string::npos ) { - std::string paragraph = str.substr( pos, newline-pos ); - recursivelyWrapLine( oss, paragraph, columns, indent ); - pos = newline+1; - newline = str.find_first_of( '\n', pos ); - } - if( pos != str.size() ) - recursivelyWrapLine( oss, str.substr( pos, str.size()-pos ), columns, indent ); - - return oss.str(); - } - inline void showHelp( const CommandParser& parser ) { AllOptions options; Options::HelpOptionParser helpOpt; @@ -207,13 +161,12 @@ namespace Catch { displayedSpecificOption = true; std::cout << "\n" << opt.optionNames() << " " << opt.argsSynopsis() << "\n\n" << opt.optionSummary() << "\n\n" - - << addLineBreaks( opt.optionDescription(), 80, 2 ) << "\n" << std::endl; + << wrapLongStrings( opt.optionDescription(), 80, 2 ) << "\n" << std::endl; } } if( !displayedSpecificOption ) { - std::cout << "\nCATCH v" << libraryVersion.majorVersion << "." + std::cout << "\nCATCH v" << libraryVersion.majorVersion << "." << libraryVersion.minorVersion << " build " << libraryVersion.buildNumber; if( libraryVersion.branchName != "master" ) diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index 8c88ee27..660cbffe 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -16,7 +16,7 @@ namespace Catch { class Command { public: Command(){} - + explicit Command( const std::string& name ) : m_name( name ) { } diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h index ec8cd2e9..a575b4fa 100644 --- a/include/internal/catch_common.h +++ b/include/internal/catch_common.h @@ -119,9 +119,9 @@ namespace Catch { inline std::ostream& operator << ( std::ostream& os, const SourceLineInfo& info ) { #ifndef __GNUG__ - os << info.file << "(" << info.line << "): "; + os << info.file << "(" << info.line << ")"; #else - os << info.file << ":" << info.line << ": "; + os << info.file << ":" << info.line; #endif return os; } @@ -129,7 +129,7 @@ namespace Catch { CATCH_ATTRIBUTE_NORETURN inline void throwLogicError( const std::string& message, const SourceLineInfo& locationInfo ) { std::ostringstream oss; - oss << "Internal Catch error: '" << message << "' at: " << locationInfo; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; throw std::logic_error( oss.str() ); } } diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp index b6da5488..f8f2baa4 100644 --- a/include/internal/catch_impl.hpp +++ b/include/internal/catch_impl.hpp @@ -27,6 +27,7 @@ #include "catch_test_case_info.hpp" #include "catch_tags.hpp" #include "catch_version.hpp" +#include "catch_line_wrap.hpp" #include "../reporters/catch_reporter_basic.hpp" #include "../reporters/catch_reporter_xml.hpp" diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h index 29c6a7a9..17974a22 100644 --- a/include/internal/catch_interfaces_reporter.h +++ b/include/internal/catch_interfaces_reporter.h @@ -49,8 +49,17 @@ namespace Catch std::string name; }; struct GroupInfo { - GroupInfo( std::string const& _name ) : name( _name ) {} + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; }; struct SectionInfo { @@ -174,7 +183,7 @@ namespace Catch struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); - // Implementing class must also provide the following static methid: + // Implementing class must also provide the following static method: // static std::string getDescription(); virtual ReporterPreferences getPreferences() const = 0; diff --git a/include/internal/catch_line_wrap.h b/include/internal/catch_line_wrap.h new file mode 100644 index 00000000..1197fb0b --- /dev/null +++ b/include/internal/catch_line_wrap.h @@ -0,0 +1,20 @@ +/* + * Created by Phil on 11/1/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_LINE_WRAP_H_INCLUDED +#define TWOBLUECUBES_CATCH_LINE_WRAP_H_INCLUDED + +#include + +namespace Catch { + + void wrapLongStrings( std::ostream& stream, const std::string& str, std::size_t columns, std::size_t indent = 0 ); + std::string wrapLongStrings( const std::string& str, std::size_t columns, std::size_t indent = 0 ); + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_LINE_WRAP_H_INCLUDED diff --git a/include/internal/catch_line_wrap.hpp b/include/internal/catch_line_wrap.hpp new file mode 100644 index 00000000..c6e03d20 --- /dev/null +++ b/include/internal/catch_line_wrap.hpp @@ -0,0 +1,67 @@ +/* + * Created by Phil on 11/1/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_LINE_WRAP_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_LINE_WRAP_HPP_INCLUDED + +#include "catch_line_wrap.h" + +namespace Catch { + + namespace { + inline void addIndent( std::ostream& os, std::size_t indent ) { + while( indent-- > 0 ) + os << ' '; + } + + inline void recursivelyWrapLine( std::ostream& os, std::string paragraph, std::size_t columns, std::size_t indent ) { + std::size_t width = columns-indent; + std::size_t tab = 0; + std::size_t wrapPoint = width; + for( std::size_t pos = 0; pos < paragraph.size(); ++pos ) { + if( pos == width ) { + addIndent( os, indent ); + os << paragraph.substr( 0, wrapPoint ) << "\n"; + return recursivelyWrapLine( os, paragraph.substr( wrapPoint+1 ), columns, indent+tab ); + } + if( paragraph[pos] == '\t' ) { + tab = pos; + paragraph = paragraph.substr( 0, tab ) + paragraph.substr( tab+1 ); + pos--; + } + else if( paragraph[pos] == ' ' ) { + wrapPoint = pos; + } + } + addIndent( os, indent ); + os << paragraph; + } + } + + void wrapLongStrings( std::ostream& stream, const std::string& str, std::size_t columns, std::size_t indent ) { + std::string::size_type pos = 0; + std::string::size_type newline = str.find_first_of( '\n' ); + while( newline != std::string::npos ) { + std::string paragraph = str.substr( pos, newline-pos ); + recursivelyWrapLine( stream, paragraph, columns, indent ); + stream << "\n"; + pos = newline+1; + newline = str.find_first_of( '\n', pos ); + } + if( pos != str.size() ) + recursivelyWrapLine( stream, str.substr( pos, str.size()-pos ), columns, indent ); + } + + std::string wrapLongStrings( const std::string& str, std::size_t columns, std::size_t indent ) { + std::ostringstream oss; + wrapLongStrings( oss, str, columns, indent ); + return oss.str(); + } + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_LINE_WRAP_HPP_INCLUDED diff --git a/include/internal/catch_notimplemented_exception.hpp b/include/internal/catch_notimplemented_exception.hpp index f051ed3d..36368e8c 100644 --- a/include/internal/catch_notimplemented_exception.hpp +++ b/include/internal/catch_notimplemented_exception.hpp @@ -16,7 +16,7 @@ namespace Catch { NotImplementedException::NotImplementedException( const SourceLineInfo& lineInfo ) : m_lineInfo( lineInfo ) { std::ostringstream oss; - oss << lineInfo << "function "; + oss << lineInfo << ": function "; oss << "not implemented"; m_what = oss.str(); } diff --git a/include/internal/catch_runner_impl.hpp b/include/internal/catch_runner_impl.hpp index 8c94aa22..03f1fcde 100644 --- a/include/internal/catch_runner_impl.hpp +++ b/include/internal/catch_runner_impl.hpp @@ -80,27 +80,27 @@ namespace Catch { m_context.setConfig( m_prevConfig ); } - void testGroupStarting( std::string const& testSpec ) { - m_reporter->testGroupStarting( GroupInfo( testSpec ) ); + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); } - void testGroupEnded( std::string const& testSpec, Totals const& totals ) { - m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec ), totals, aborting() ) ); + 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() ) ); } - Totals runMatching( const std::string& testSpec ) { + Totals runMatching( const std::string& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { std::vector matchingTests = getRegistryHub().getTestCaseRegistry().getMatchingTestCases( testSpec ); Totals totals; - testGroupStarting( testSpec ); + testGroupStarting( testSpec, groupIndex, groupsCount ); std::vector::const_iterator it = matchingTests.begin(); std::vector::const_iterator itEnd = matchingTests.end(); for(; it != itEnd; ++it ) totals += runTest( *it ); - testGroupEnded( testSpec, totals ); + testGroupEnded( testSpec, totals, groupIndex, groupsCount ); return totals; } diff --git a/include/reporters/catch_reporter_basic.hpp b/include/reporters/catch_reporter_basic.hpp index e8e1895a..b13f84f4 100644 --- a/include/reporters/catch_reporter_basic.hpp +++ b/include/reporters/catch_reporter_basic.hpp @@ -167,7 +167,7 @@ namespace Catch { if( !assertionResult.getSourceInfo().empty() ) { TextColour colour( TextColour::FileName ); - m_config.stream() << assertionResult.getSourceInfo(); + m_config.stream() << assertionResult.getSourceInfo() << ": "; } if( assertionResult.hasExpression() ) { diff --git a/include/reporters/catch_reporter_console.hpp b/include/reporters/catch_reporter_console.hpp index 3a74be88..999bfdfa 100644 --- a/include/reporters/catch_reporter_console.hpp +++ b/include/reporters/catch_reporter_console.hpp @@ -30,33 +30,6 @@ namespace Catch { return prefs; } - void lazyPrintRunInfo() { - printHeader( "Started testing", testRunInfo->name ); - testRunInfo.reset(); - } - void lazyPrintGroupInfo() { - if( !unusedGroupInfo->name.empty() ) - printHeader( "Group", unusedGroupInfo->name ); - unusedGroupInfo.reset(); - } - void lazyPrintTestCaseInfo() { - printHeader( "Test case", unusedTestCaseInfo->name ); - unusedTestCaseInfo.reset(); - } - void lazyPrintSectionInfo() { - std::vector sections; - for( ThreadedSectionInfo* section = unusedSectionInfo.get(); - section && !section->printed; - section = section->parent.get() ) - sections.push_back( section ); - - typedef std::vector::const_reverse_iterator It; - for( It it = sections.rbegin(), itEnd = sections.rend(); it != itEnd; ++it ) { - printHeader( "Section", (*it)->name ); - (*it)->printed = true; - } - unusedSectionInfo.reset(); - } static std::string const& getDashes() { static const std::string dashes = "----------------------------------------------------------------"; @@ -75,14 +48,15 @@ namespace Catch { } void printHeader( std::string const& _type, std::string const& _name ) { - std::size_t labelLen = _type.size() + _name.size() + 8; - std::size_t dashLen = getDashes().size(); - stream << "-- " << _type << ": '" << _name << "' " - << getDashes().substr( 0, labelLen < dashLen ? dashLen - labelLen : 0 ) - << std::endl; + stream << getDashes() << "\n" + << _type << ": '" << _name << "'\n" + << getDashes() << std::endl; } - + void lazyPrint() { + bool needsNewline = unusedTestCaseInfo || ( currentSectionInfo && !currentSectionInfo->printed ); + if( m_lazyTestCaseStats ) + lazyPrintTestCaseStats(); if( testRunInfo ) lazyPrintRunInfo(); if( unusedGroupInfo ) @@ -91,125 +65,148 @@ namespace Catch { lazyPrintTestCaseInfo(); if( currentSectionInfo && !currentSectionInfo->printed ) lazyPrintSectionInfo(); + if( needsNewline ) + stream << "\n"; + } - + void lazyPrintTestCaseStats() { + printTestCaseStats( *m_lazyTestCaseStats ); + m_lazyTestCaseStats.reset(); + } + void lazyPrintRunInfo() { + stream << "\n" << testRunInfo->name + << " is a CATCH v" << libraryVersion.majorVersion << "." + << libraryVersion.minorVersion << " b" + << libraryVersion.buildNumber; + if( libraryVersion.branchName != "master" ) + stream << " (" << libraryVersion.branchName << ")"; + stream << " host application.\n" + << "Run with -? for options\n\n"; + + testRunInfo.reset(); + } + void lazyPrintGroupInfo() { + if( !unusedGroupInfo->name.empty() && unusedGroupInfo->groupsCounts > 1 ) { + printHeader( "Group", unusedGroupInfo->name ); + unusedGroupInfo.reset(); + } + } + void lazyPrintTestCaseInfo() { + printHeader( "Test case", unusedTestCaseInfo->name ); + unusedTestCaseInfo.reset(); + } + void lazyPrintSectionInfo() { + std::vector sections; + for( ThreadedSectionInfo* section = unusedSectionInfo.get(); + section && !section->printed; + section = section->parent.get() ) + sections.push_back( section ); + + typedef std::vector::const_reverse_iterator It; + for( It it = sections.rbegin(), itEnd = sections.rend(); it != itEnd; ++it ) { + printHeader( "Section", (*it)->name ); + (*it)->printed = true; + } + unusedSectionInfo.reset(); + } + virtual void assertionStarting( AssertionInfo const& ) { } - virtual void assertionEnded( AssertionStats const& _assertionStats ) { + virtual void assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; // Drop out if result was successful and we're not printing those if( !m_config.includeSuccessfulResults() && result.isOk() ) return; - + lazyPrint(); - int inset = printLineInfo( result.getSourceInfo() ); - - if( result.hasExpression() ) { - TextColour colour( TextColour::OriginalExpression ); - stream << result.getExpression() << "\n"; - if( result.succeeded() ) { - TextColour successColour( TextColour::Success ); - stream << "succeeded"; - } - else { - TextColour errorColour( TextColour::Error ); - stream << "failed"; - if( result.isOk() ) { - TextColour okAnywayColour( TextColour::Success ); - stream << " - but was ok"; - } - } + { + TextColour colour( TextColour::FileName ); + stream << result.getSourceInfo() << ":\n"; } - - switch( result.getResultType() ) { + + if( _assertionStats.totals.assertions.total() > 0 ) { + printOriginalExpression( result ); + printResultType( result ); + printReconstructedExpression( result ); + } + printMessage( result ); + stream << std::endl; + } + + void printResultType( AssertionResult const& _result ) { + if( _result.succeeded() ) { + TextColour successColour( TextColour::Success ); + stream << "passed"; + } + else if( _result.isOk() ) { + TextColour okAnywayColour( TextColour::Success ); + stream << "failed - but was ok"; + } + else { + TextColour errorColour( TextColour::Error ); + stream << "failed"; + } + } + + void printMessage( AssertionResult const& _result ) { + std::pair message = getMessage( _result ); + if( !message.first.empty() ) + stream << " " << message.first << ":\n"; + if( !message.second.empty() ) + printWrappableString( message.second ); + } + std::pair getMessage( AssertionResult const& _result ) { + switch( _result.getResultType() ) { case ResultWas::ThrewException: - { - TextColour colour( TextColour::Error ); - if( result.hasExpression() ) - stream << " with unexpected"; - else - stream << "Unexpected"; - stream << " exception with message: '" << result.getMessage() << "'"; - } - break; + return std::make_pair( "due to unexpected exception with message", _result.getMessage() ); case ResultWas::DidntThrowException: - { - TextColour colour( TextColour::Error ); - if( result.hasExpression() ) - stream << " because no exception was thrown where one was expected"; - else - stream << "No exception thrown where one was expected"; - } - break; + return std::make_pair( "because no exception was thrown where one was expected", "" ); case ResultWas::Info: - { - TextColour colour( TextColour::ReconstructedExpression ); - streamVariableLengthText( "info", result.getMessage() ); - } - break; + return std::make_pair( "with info", _result.getMessage() ); case ResultWas::Warning: - { - TextColour colour( TextColour::ReconstructedExpression ); - streamVariableLengthText( "warning", result.getMessage() ); - } - break; + return std::make_pair( "with warning", _result.getMessage() ); case ResultWas::ExplicitFailure: - { - TextColour colour( TextColour::Error ); - stream << "failed with message: '" << result.getMessage() << "'"; - } - break; + return std::make_pair( "explicitly with message", _result.getMessage() ); + case ResultWas::Unknown: // These cases are here to prevent compiler warnings case ResultWas::Ok: case ResultWas::FailureBit: case ResultWas::ExpressionFailed: case ResultWas::Exception: - if( !result.hasExpression() ) { - if( result.succeeded() ) { - TextColour colour( TextColour::Success ); - stream << " succeeded"; - } - else { - TextColour colour( TextColour::Error ); - stream << " failed"; - if( result.isOk() ) { - TextColour okAnywayColour( TextColour::Success ); - stream << " - but was ok"; - } - } - } - if( result.hasMessage() ) { - stream << "\n"; - TextColour colour( TextColour::ReconstructedExpression ); - streamVariableLengthText( "with message", result.getMessage() ); - } - break; + if( _result.hasMessage() ) + return std::make_pair( "with message", _result.getMessage() ); + else + return std::make_pair( "", "" ); } - - if( result.hasExpandedExpression() ) { - stream << "\nfor: "; + } + void printOriginalExpression( AssertionResult const& _result ) { + if( _result.hasExpression() ) { + TextColour colour( TextColour::OriginalExpression ); + stream << " " << _result.getTestMacroName() << "( " + << _result.getExpression() + << " )\n"; + } + } + void printReconstructedExpression( AssertionResult const& _result ) { + if( _result.hasExpandedExpression() ) { + stream << " with expansion:\n"; TextColour colour( TextColour::ReconstructedExpression ); - stream << getSpaces( inset-5 ) << result.getExpandedExpression(); - } - - stream << "\n" << std::endl; - } - - void streamVariableLengthText( std::string const& prefix, std::string const& text ) { - std::string trimmed = trim( text ); - if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) { - stream << "[" << prefix << ": " << trimmed << "]"; - } - else { - stream << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed - << "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n"; + printWrappableString( _result.getExpandedExpression() ); } } - void printAssertionCounts( std::string const& label, Counts const& counts ) { + void printWrappableString( std::string const& _string ) { + stream << wrapLongStrings( _string ) << "\n"; + } + + std::string wrapLongStrings( std::string const& _string ) { + return Catch::wrapLongStrings( _string, 70, 2 ); + } + + void printCounts( std::string const& label, Counts const& counts ) { if( counts.total() == 1 ) { stream << "1 " << label << " - "; if( counts.failed ) @@ -242,10 +239,10 @@ namespace Catch { } else if( totals.assertions.failed ) { TextColour colour( TextColour::ResultError ); - printAssertionCounts( "test case", totals.testCases ); + printCounts( "test case", totals.testCases ); if( totals.testCases.failed > 0 ) { stream << " ("; - printAssertionCounts( "assertion", totals.assertions ); + printCounts( "assertion", totals.assertions ); stream << ")"; } } @@ -258,48 +255,36 @@ namespace Catch { } virtual void sectionEnded( SectionStats const& _sectionStats ) { - resetLastPrintedLine(); if( _sectionStats.missingAssertions ) { lazyPrint(); TextColour colour( TextColour::ResultError ); stream << "\nNo assertions in section, '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } - if( currentSectionInfo && currentSectionInfo->printed ) { - printSummarDivider(); - stream << "Summary for section '" << _sectionStats.sectionInfo.name << "':\n"; - Counts const& assertions = _sectionStats.assertions; - if( assertions.failed ) { - TextColour colour( TextColour::ResultError ); - printAssertionCounts( "assertion", assertions ); - } - else { - TextColour colour( TextColour::ResultSuccess ); - stream << ( assertions.passed > 1 ? "All " : "" ) - << pluralise( assertions.passed, "assertion" ) << " passed" ; - } - stream << "\n" << std::endl; - } StreamingReporterBase::sectionEnded( _sectionStats ); } + void printTestCaseStats( TestCaseStats const& _testCaseStats ) { + m_atLeastOneTestCasePrinted = true; + } + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { - resetLastPrintedLine(); + if( _testCaseStats.missingAssertions ) { lazyPrint(); TextColour colour( TextColour::ResultError ); stream << "\nNo assertions in test case, '" << _testCaseStats.testInfo.name << "'\n" << std::endl; } if( !unusedTestCaseInfo ) { - m_atLeastOneTestCasePrinted = true; - printSummarDivider(); - stream << "Summary for test case '" << _testCaseStats.testInfo.name << "':\n"; - printTotals( _testCaseStats.totals ); - stream << "\n" << std::endl; + if( m_atLeastOneTestCasePrinted ) + printTestCaseStats( _testCaseStats ); + else + m_lazyTestCaseStats = _testCaseStats; } + StreamingReporterBase::testCaseEnded( _testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { if( !unusedGroupInfo ) { - printSummarDivider(); + printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; printTotals( _testGroupStats.totals ); stream << "\n" << std::endl; @@ -309,7 +294,7 @@ namespace Catch { virtual void testRunEnded( TestRunStats const& _testRunStats ) { if( m_atLeastOneTestCasePrinted ) printTotalsDivider(); - stream << "Summary for all tests in '" << _testRunStats.runInfo.name << "':\n"; +// stream << "Summary for all tests in '" << _testRunStats.runInfo.name << "':\n"; printTotals( _testRunStats.totals ); stream << "\n" << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); @@ -317,37 +302,15 @@ namespace Catch { private: void printTotalsDivider() { - stream << "================================================================\n"; + stream << getDoubleDashes() << "\n"; } - void printSummarDivider() { - stream << "----------------------------------------------------------------\n"; - } - static int countDigits( std::size_t number ) { - int digits = 1; - for( ; number != 0; digits++, number /= 10 ); - return digits; - } - - // Returns number of characters printed - int printLineInfo( SourceLineInfo const& lineInfo ) { - if( lineInfo.empty() ) - return 0; - if( m_lastPrintedLine.empty() || - m_lastPrintedLine.file != lineInfo.file || - abs( static_cast( m_lastPrintedLine.line ) - static_cast( lineInfo.line ) ) > 20 ) { - TextColour colour( TextColour::FileName ); - stream << lineInfo << "\n"; - } - TextColour colour( TextColour::FileName ); - stream << "[" << lineInfo.line << "] "; - m_lastPrintedLine = lineInfo; - return 3 + countDigits( lineInfo.line ); - } - void resetLastPrintedLine() { - m_lastPrintedLine = SourceLineInfo(); + void printSummaryDivider() { + stream << getDashes() << "\n"; } + + private: bool m_atLeastOneTestCasePrinted; - SourceLineInfo m_lastPrintedLine; + Option m_lazyTestCaseStats; }; diff --git a/projects/SelfTest/GeneratorTests.cpp b/projects/SelfTest/GeneratorTests.cpp index 700b180b..b21e22dd 100644 --- a/projects/SelfTest/GeneratorTests.cpp +++ b/projects/SelfTest/GeneratorTests.cpp @@ -26,3 +26,17 @@ CATCH_TEST_CASE( "./succeeding/generators/1", "Generators over two ranges" ) CATCH_REQUIRE( multiply( i, 2 ) == i*2 ); CATCH_REQUIRE( multiply( j, 2 ) == j*2 ); } + +struct IntPair { int first, second; }; + +CATCH_TEST_CASE( "./succeeding/generators/2", "Generator over a range of pairs" ) +{ + using namespace Catch::Generators; + + IntPair p[] = { { 0, 1 }, { 2, 3 } }; + + IntPair* i = CATCH_GENERATE( between( p, &p[1] ) ); + + CATCH_REQUIRE( i->first == i->second-1 ); + +} diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index 8db31ae0..4085c670 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -20,12 +20,12 @@ TEST_CASE( "selftest/main", "Runs all Catch self tests and checks their results" SECTION( "selftest/expected result/failing tests", "Tests in the 'failing' branch fail" ) { - MetaTestRunner::runMatching( "./failing/*", MetaTestRunner::Expected::ToFail ); + MetaTestRunner::runMatching( "./failing/*", MetaTestRunner::Expected::ToFail, 0, 2 ); } SECTION( "selftest/expected result/succeeding tests", "Tests in the 'succeeding' branch succeed" ) { - MetaTestRunner::runMatching( "./succeeding/*", MetaTestRunner::Expected::ToSucceed ); + MetaTestRunner::runMatching( "./succeeding/*", MetaTestRunner::Expected::ToSucceed, 1, 2 ); } } @@ -36,14 +36,14 @@ TEST_CASE( "selftest/main", "Runs all Catch self tests and checks their results" SECTION( "selftest/test counts/succeeding tests", "Number of 'succeeding' tests is fixed" ) { - Totals totals = runner.runMatching( "./succeeding/*" ); + Totals totals = runner.runMatching( "./succeeding/*", 0, 2 ); CHECK( totals.assertions.passed == 291 ); CHECK( totals.assertions.failed == 0 ); } SECTION( "selftest/test counts/failing tests", "Number of 'failing' tests is fixed" ) { - Totals totals = runner.runMatching( "./failing/*" ); + Totals totals = runner.runMatching( "./failing/*", 1, 2 ); CHECK( totals.assertions.passed == 1 ); CHECK( totals.assertions.failed == 72 ); } @@ -53,7 +53,7 @@ TEST_CASE( "selftest/main", "Runs all Catch self tests and checks their results" TEST_CASE( "meta/Misc/Sections", "looped tests" ) { Catch::EmbeddedRunner runner; - Catch::Totals totals = runner.runMatching( "./mixed/Misc/Sections/nested2" ); + Catch::Totals totals = runner.runMatching( "./mixed/Misc/Sections/nested2", 0, 1 ); CHECK( totals.assertions.passed == 2 ); CHECK( totals.assertions.failed == 1 ); } diff --git a/projects/SelfTest/catch_self_test.cpp b/projects/SelfTest/catch_self_test.cpp index 81bc7e23..49592325 100644 --- a/projects/SelfTest/catch_self_test.cpp +++ b/projects/SelfTest/catch_self_test.cpp @@ -17,7 +17,7 @@ namespace Catch{ NullStreamingReporter::~NullStreamingReporter() {} - Totals EmbeddedRunner::runMatching( const std::string& rawTestSpec, const std::string& ) { + Totals EmbeddedRunner::runMatching( const std::string& rawTestSpec, std::size_t groupIndex, std::size_t groupsCount, const std::string& ) { std::ostringstream oss; Config config; config.setStreamBuf( oss.rdbuf() ); @@ -27,7 +27,7 @@ namespace Catch{ // Scoped because Runner doesn't report EndTesting until its destructor { Runner runner( config, m_reporter.get() ); - totals = runner.runMatching( rawTestSpec ); + totals = runner.runMatching( rawTestSpec, groupIndex, groupsCount ); } return totals; } diff --git a/projects/SelfTest/catch_self_test.hpp b/projects/SelfTest/catch_self_test.hpp index 03505f69..cb62187f 100644 --- a/projects/SelfTest/catch_self_test.hpp +++ b/projects/SelfTest/catch_self_test.hpp @@ -53,6 +53,8 @@ namespace Catch { EmbeddedRunner() : m_reporter( new NullStreamingReporter() ) {} Totals runMatching( const std::string& rawTestSpec, + std::size_t groupIndex, + std::size_t groupsCount, const std::string& reporter = "console" ); private: @@ -67,12 +69,18 @@ namespace Catch { ToFail }; }; - MetaTestRunner( Expected::Result expectedResult ) : m_expectedResult( expectedResult ) {} + MetaTestRunner( Expected::Result expectedResult, std::size_t groupIndex, std::size_t groupsCount ) + : m_expectedResult( expectedResult ), + m_groupIndex( groupIndex ), + m_groupsCount( groupsCount ) + {} static void runMatching( const std::string& testSpec, - Expected::Result expectedResult ) { + Expected::Result expectedResult, + std::size_t groupIndex, + std::size_t groupsCount ) { forEach( getRegistryHub().getTestCaseRegistry().getMatchingTestCases( testSpec ), - MetaTestRunner( expectedResult ) ); + MetaTestRunner( expectedResult, groupIndex, groupsCount ) ); } void operator()( const TestCase& testCase ) { @@ -81,7 +89,7 @@ namespace Catch { { EmbeddedRunner runner; name = testCase.getTestCaseInfo().name; - totals = runner.runMatching( name ); + totals = runner.runMatching( name, m_groupIndex, m_groupsCount ); } switch( m_expectedResult ) { case Expected::ToSucceed: @@ -111,6 +119,8 @@ namespace Catch { private: Expected::Result m_expectedResult; + std::size_t m_groupIndex; + std::size_t m_groupsCount; }; diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index 37a53362..a8d139bb 100644 --- a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 2694A1FD16A0000E004816E3 /* catch_line_wrap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2694A1FB16A0000E004816E3 /* catch_line_wrap.cpp */; }; 4A45DA2416161EF9004F8D6B /* catch_console_colour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A45DA2316161EF9004F8D6B /* catch_console_colour.cpp */; }; 4A45DA2716161F1F004F8D6B /* catch_ptr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A45DA2616161F1F004F8D6B /* catch_ptr.cpp */; }; 4A45DA2916161F3D004F8D6B /* catch_streambuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A45DA2816161F3D004F8D6B /* catch_streambuf.cpp */; }; @@ -52,6 +53,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 2694A1F8169FFF9B004816E3 /* catch_line_wrap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_line_wrap.h; sourceTree = ""; }; + 2694A1FA169FFFEC004816E3 /* catch_line_wrap.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_line_wrap.hpp; sourceTree = ""; }; + 2694A1FB16A0000E004816E3 /* catch_line_wrap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catch_line_wrap.cpp; sourceTree = ""; }; 4A084F1C15DACEEA0027E631 /* catch_test_case_info.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_info.hpp; sourceTree = ""; }; 4A084F1D15DAD15F0027E631 /* catch_test_spec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_test_spec.h; sourceTree = ""; }; 4A3D7DD01503869D005F9203 /* catch_matchers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_matchers.hpp; sourceTree = ""; }; @@ -270,6 +274,7 @@ 4AB3D99F1616219100C9A0F8 /* catch_interfaces_config.cpp */, 4AB3D9A1161621B500C9A0F8 /* catch_interfaces_generators.cpp */, 4ACE21CA166CA1B300FB5509 /* catch_option.cpp */, + 2694A1FB16A0000E004816E3 /* catch_line_wrap.cpp */, ); name = SurrogateCpps; sourceTree = ""; @@ -288,6 +293,7 @@ 4A90B59D15D24FE900EF71BC /* catch_assertionresult.hpp */, 4A90B59E15D2521E00EF71BC /* catch_expressionresult_builder.hpp */, 4A084F1C15DACEEA0027E631 /* catch_test_case_info.hpp */, + 2694A1FA169FFFEC004816E3 /* catch_line_wrap.hpp */, ); name = impl; sourceTree = ""; @@ -374,6 +380,7 @@ 4AB77CB51551AEA200857BF0 /* catch_ptr.hpp */, 4AEE0326161431070071E950 /* catch_streambuf.h */, 4ACE21C8166CA19700FB5509 /* catch_option.hpp */, + 2694A1F8169FFF9B004816E3 /* catch_line_wrap.h */, ); name = Infrastructure; sourceTree = ""; @@ -465,6 +472,7 @@ 4AB3D9A01616219100C9A0F8 /* catch_interfaces_config.cpp in Sources */, 4AB3D9A2161621B500C9A0F8 /* catch_interfaces_generators.cpp in Sources */, 4ACE21CC166CA1B300FB5509 /* catch_option.cpp in Sources */, + 2694A1FD16A0000E004816E3 /* catch_line_wrap.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest/catch_line_wrap.cpp b/projects/XCode4/CatchSelfTest/CatchSelfTest/catch_line_wrap.cpp new file mode 100644 index 00000000..d0445cc2 --- /dev/null +++ b/projects/XCode4/CatchSelfTest/CatchSelfTest/catch_line_wrap.cpp @@ -0,0 +1,2 @@ +// This file is only here to verify (to the extent possible) the self sufficiency of the header +#include "catch_line_wrap.h"