From 1ad971ea2b77a2df0bb560ce61f7eca4cb353eb1 Mon Sep 17 00:00:00 2001 From: Martin Moene Date: Sun, 22 Jul 2012 08:59:48 +0200 Subject: [PATCH 1/4] Fixed issue #101, missing space in end of section message --- include/reporters/catch_reporter_basic.hpp | 666 ++++++++++----------- 1 file changed, 333 insertions(+), 333 deletions(-) diff --git a/include/reporters/catch_reporter_basic.hpp b/include/reporters/catch_reporter_basic.hpp index f5fc6ee1..b620544e 100644 --- a/include/reporters/catch_reporter_basic.hpp +++ b/include/reporters/catch_reporter_basic.hpp @@ -1,333 +1,333 @@ -/* - * Created by Phil on 28/10/2010. - * Copyright 2010 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_REPORTER_BASIC_HPP_INCLUDED -#define TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED - -#include "../internal/catch_capture.hpp" -#include "../internal/catch_interfaces_reporter.h" -#include "../internal/catch_reporter_registrars.hpp" -#include "../internal/catch_console_colour.hpp" - -namespace Catch { - - struct pluralise { - pluralise( std::size_t count, const std::string& label ) - : m_count( count ), - m_label( label ) - {} - - friend std::ostream& operator << ( std::ostream& os, const pluralise& pluraliser ) { - os << pluraliser.m_count << " " << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << "s"; - return os; - } - - std::size_t m_count; - std::string m_label; - }; - - class BasicReporter : public SharedImpl { - - struct SpanInfo { - - SpanInfo() - : emitted( false ) - {} - - SpanInfo( const std::string& spanName ) - : name( spanName ), - emitted( false ) - {} - - SpanInfo( const SpanInfo& other ) - : name( other.name ), - emitted( other.emitted ) - {} - - std::string name; - bool emitted; - }; - - public: - BasicReporter( const IReporterConfig& config ) - : m_config( config ), - m_firstSectionInTestCase( true ), - m_aborted( false ) - {} - - static std::string getDescription() { - return "Reports test results as lines of text"; - } - - private: - - 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 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed"; - } - - 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, allPrefix ); - if( totals.testCases.failed > 0 ) { - m_config.stream() << " ("; - ReportCounts( "assertion", totals.assertions, allPrefix ); - m_config.stream() << ")"; - } - } - else { - TextColour colour( TextColour::ResultSuccess ); - m_config.stream() << allPrefix << "tests passed (" - << pluralise( totals.assertions.passed, "assertion" ) << " in " - << pluralise( totals.testCases.passed, "test case" ) << ")"; - } - } - - private: // IReporter - - virtual bool shouldRedirectStdout() const { - return false; - } - - virtual void StartTesting() { - 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 - 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; - } - - virtual void StartGroup( const std::string& groupName ) { - m_groupSpan = groupName; - } - - virtual void EndGroup( const std::string& groupName, const Totals& totals ) { - if( m_groupSpan.emitted && !groupName.empty() ) { - m_config.stream() << "[End of group: '" << groupName << "'. "; - ReportCounts( totals ); - m_config.stream() << "]\n" << std::endl; - m_groupSpan = SpanInfo(); - } - } - - virtual void StartTestCase( const TestCaseInfo& testInfo ) { - m_testSpan = testInfo.getName(); - } - - virtual void StartSection( const std::string& sectionName, const std::string& ) { - m_sectionSpans.push_back( SpanInfo( sectionName ) ); - } - - virtual void EndSection( const std::string& sectionName, const Counts& assertions ) { - SpanInfo& sectionSpan = m_sectionSpans.back(); - if( sectionSpan.emitted && !sectionSpan.name.empty() ) { - m_config.stream() << "[End of section: '" << sectionName << "' "; - - if( assertions.failed ) { - TextColour colour( TextColour::ResultError ); - ReportCounts( "assertion", assertions); - } - else { - TextColour colour( TextColour::ResultSuccess ); - m_config.stream() << ( assertions.passed > 1 ? "All " : "" ) - << pluralise( assertions.passed, "assertion" ) << "passed" ; - } - m_config.stream() << "]\n" << std::endl; - } - m_sectionSpans.pop_back(); - } - - virtual void Result( const ResultInfo& resultInfo ) { - if( !m_config.includeSuccessfulResults() && resultInfo.getResultType() == ResultWas::Ok ) - return; - - StartSpansLazily(); - - if( !resultInfo.getFilename().empty() ) { - TextColour colour( TextColour::FileName ); - m_config.stream() << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() ); - } - - if( resultInfo.hasExpression() ) { - TextColour colour( TextColour::OriginalExpression ); - m_config.stream() << resultInfo.getExpression(); - if( resultInfo.ok() ) { - TextColour successColour( TextColour::Success ); - m_config.stream() << " succeeded"; - } - else { - TextColour errorColour( TextColour::Error ); - m_config.stream() << " failed"; - } - } - switch( resultInfo.getResultType() ) { - case ResultWas::ThrewException: - { - TextColour colour( TextColour::Error ); - if( resultInfo.hasExpression() ) - m_config.stream() << " with unexpected"; - else - m_config.stream() << "Unexpected"; - m_config.stream() << " exception with message: '" << resultInfo.getMessage() << "'"; - } - break; - case ResultWas::DidntThrowException: - { - TextColour colour( TextColour::Error ); - if( resultInfo.hasExpression() ) - m_config.stream() << " because no exception was thrown where one was expected"; - else - m_config.stream() << "No exception thrown where one was expected"; - } - break; - case ResultWas::Info: - streamVariableLengthText( "info", resultInfo.getMessage() ); - break; - case ResultWas::Warning: - m_config.stream() << "warning:\n'" << resultInfo.getMessage() << "'"; - break; - case ResultWas::ExplicitFailure: - { - TextColour colour( TextColour::Error ); - m_config.stream() << "failed with message: '" << resultInfo.getMessage() << "'"; - } - break; - case ResultWas::Unknown: // These cases are here to prevent compiler warnings - case ResultWas::Ok: - case ResultWas::FailureBit: - case ResultWas::ExpressionFailed: - case ResultWas::Exception: - default: - if( !resultInfo.hasExpression() ) { - if( resultInfo.ok() ) { - TextColour colour( TextColour::Success ); - m_config.stream() << " succeeded"; - } - else { - TextColour colour( TextColour::Error ); - m_config.stream() << " failed"; - } - } - break; - } - - if( resultInfo.hasExpandedExpression() ) { - m_config.stream() << " for: "; - TextColour colour( TextColour::ReconstructedExpression ); - m_config.stream() << resultInfo.getExpandedExpression(); - } - m_config.stream() << std::endl; - } - - virtual void EndTestCase( const TestCaseInfo& testInfo, - const Totals& totals, - const std::string& stdOut, - const std::string& stdErr ) { - if( !stdOut.empty() ) { - StartSpansLazily(); - streamVariableLengthText( "stdout", stdOut ); - } - - if( !stdErr.empty() ) { - StartSpansLazily(); - streamVariableLengthText( "stderr", stdErr ); - } - - if( m_testSpan.emitted ) { - m_config.stream() << "[Finished: '" << testInfo.getName() << "' "; - ReportCounts( totals ); - m_config.stream() << "]" << std::endl; - } - } - - private: // helpers - - void StartSpansLazily() { - if( !m_testingSpan.emitted ) { - if( m_config.getName().empty() ) - m_config.stream() << "[Started testing]" << std::endl; - else - m_config.stream() << "[Started testing: " << m_config.getName() << "]" << std::endl; - m_testingSpan.emitted = true; - } - - if( !m_groupSpan.emitted && !m_groupSpan.name.empty() ) { - m_config.stream() << "[Started group: '" << m_groupSpan.name << "']" << std::endl; - m_groupSpan.emitted = true; - } - - if( !m_testSpan.emitted ) { - m_config.stream() << std::endl << "[Running: " << m_testSpan.name << "]" << std::endl; - m_testSpan.emitted = true; - } - - if( !m_sectionSpans.empty() ) { - SpanInfo& sectionSpan = m_sectionSpans.back(); - if( !sectionSpan.emitted && !sectionSpan.name.empty() ) { - if( m_firstSectionInTestCase ) { - m_config.stream() << "\n"; - m_firstSectionInTestCase = false; - } - std::vector::iterator it = m_sectionSpans.begin(); - std::vector::iterator itEnd = m_sectionSpans.end(); - for(; it != itEnd; ++it ) { - SpanInfo& prevSpan = *it; - if( !prevSpan.emitted && !prevSpan.name.empty() ) { - m_config.stream() << "[Started section: '" << prevSpan.name << "']" << std::endl; - prevSpan.emitted = true; - } - } - } - } - } - - void streamVariableLengthText( const std::string& prefix, const std::string& text ) { - std::string trimmed = trim( text ); - if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) { - m_config.stream() << "[" << prefix << ": " << trimmed << "]\n"; - } - else { - m_config.stream() << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed - << "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n"; - } - } - - private: - const IReporterConfig& m_config; - bool m_firstSectionInTestCase; - - SpanInfo m_testingSpan; - SpanInfo m_groupSpan; - SpanInfo m_testSpan; - std::vector m_sectionSpans; - bool m_aborted; - }; - -} // end namespace Catch - -#endif // TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED +/* + * Created by Phil on 28/10/2010. + * Copyright 2010 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_REPORTER_BASIC_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED + +#include "../internal/catch_capture.hpp" +#include "../internal/catch_interfaces_reporter.h" +#include "../internal/catch_reporter_registrars.hpp" +#include "../internal/catch_console_colour.hpp" + +namespace Catch { + + struct pluralise { + pluralise( std::size_t count, const std::string& label ) + : m_count( count ), + m_label( label ) + {} + + friend std::ostream& operator << ( std::ostream& os, const pluralise& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + std::size_t m_count; + std::string m_label; + }; + + class BasicReporter : public SharedImpl { + + struct SpanInfo { + + SpanInfo() + : emitted( false ) + {} + + SpanInfo( const std::string& spanName ) + : name( spanName ), + emitted( false ) + {} + + SpanInfo( const SpanInfo& other ) + : name( other.name ), + emitted( other.emitted ) + {} + + std::string name; + bool emitted; + }; + + public: + BasicReporter( const IReporterConfig& config ) + : m_config( config ), + m_firstSectionInTestCase( true ), + m_aborted( false ) + {} + + static std::string getDescription() { + return "Reports test results as lines of text"; + } + + private: + + 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 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed"; + } + + 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, allPrefix ); + if( totals.testCases.failed > 0 ) { + m_config.stream() << " ("; + ReportCounts( "assertion", totals.assertions, allPrefix ); + m_config.stream() << ")"; + } + } + else { + TextColour colour( TextColour::ResultSuccess ); + m_config.stream() << allPrefix << "tests passed (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")"; + } + } + + private: // IReporter + + virtual bool shouldRedirectStdout() const { + return false; + } + + virtual void StartTesting() { + 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 + 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; + } + + virtual void StartGroup( const std::string& groupName ) { + m_groupSpan = groupName; + } + + virtual void EndGroup( const std::string& groupName, const Totals& totals ) { + if( m_groupSpan.emitted && !groupName.empty() ) { + m_config.stream() << "[End of group: '" << groupName << "'. "; + ReportCounts( totals ); + m_config.stream() << "]\n" << std::endl; + m_groupSpan = SpanInfo(); + } + } + + virtual void StartTestCase( const TestCaseInfo& testInfo ) { + m_testSpan = testInfo.getName(); + } + + virtual void StartSection( const std::string& sectionName, const std::string& ) { + m_sectionSpans.push_back( SpanInfo( sectionName ) ); + } + + virtual void EndSection( const std::string& sectionName, const Counts& assertions ) { + SpanInfo& sectionSpan = m_sectionSpans.back(); + if( sectionSpan.emitted && !sectionSpan.name.empty() ) { + m_config.stream() << "[End of section: '" << sectionName << "' "; + + if( assertions.failed ) { + TextColour colour( TextColour::ResultError ); + ReportCounts( "assertion", assertions); + } + else { + TextColour colour( TextColour::ResultSuccess ); + m_config.stream() << ( assertions.passed > 1 ? "All " : "" ) + << pluralise( assertions.passed, "assertion" ) << " passed" ; + } + m_config.stream() << "]\n" << std::endl; + } + m_sectionSpans.pop_back(); + } + + virtual void Result( const ResultInfo& resultInfo ) { + if( !m_config.includeSuccessfulResults() && resultInfo.getResultType() == ResultWas::Ok ) + return; + + StartSpansLazily(); + + if( !resultInfo.getFilename().empty() ) { + TextColour colour( TextColour::FileName ); + m_config.stream() << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() ); + } + + if( resultInfo.hasExpression() ) { + TextColour colour( TextColour::OriginalExpression ); + m_config.stream() << resultInfo.getExpression(); + if( resultInfo.ok() ) { + TextColour successColour( TextColour::Success ); + m_config.stream() << " succeeded"; + } + else { + TextColour errorColour( TextColour::Error ); + m_config.stream() << " failed"; + } + } + switch( resultInfo.getResultType() ) { + case ResultWas::ThrewException: + { + TextColour colour( TextColour::Error ); + if( resultInfo.hasExpression() ) + m_config.stream() << " with unexpected"; + else + m_config.stream() << "Unexpected"; + m_config.stream() << " exception with message: '" << resultInfo.getMessage() << "'"; + } + break; + case ResultWas::DidntThrowException: + { + TextColour colour( TextColour::Error ); + if( resultInfo.hasExpression() ) + m_config.stream() << " because no exception was thrown where one was expected"; + else + m_config.stream() << "No exception thrown where one was expected"; + } + break; + case ResultWas::Info: + streamVariableLengthText( "info", resultInfo.getMessage() ); + break; + case ResultWas::Warning: + m_config.stream() << "warning:\n'" << resultInfo.getMessage() << "'"; + break; + case ResultWas::ExplicitFailure: + { + TextColour colour( TextColour::Error ); + m_config.stream() << "failed with message: '" << resultInfo.getMessage() << "'"; + } + break; + case ResultWas::Unknown: // These cases are here to prevent compiler warnings + case ResultWas::Ok: + case ResultWas::FailureBit: + case ResultWas::ExpressionFailed: + case ResultWas::Exception: + default: + if( !resultInfo.hasExpression() ) { + if( resultInfo.ok() ) { + TextColour colour( TextColour::Success ); + m_config.stream() << " succeeded"; + } + else { + TextColour colour( TextColour::Error ); + m_config.stream() << " failed"; + } + } + break; + } + + if( resultInfo.hasExpandedExpression() ) { + m_config.stream() << " for: "; + TextColour colour( TextColour::ReconstructedExpression ); + m_config.stream() << resultInfo.getExpandedExpression(); + } + m_config.stream() << std::endl; + } + + virtual void EndTestCase( const TestCaseInfo& testInfo, + const Totals& totals, + const std::string& stdOut, + const std::string& stdErr ) { + if( !stdOut.empty() ) { + StartSpansLazily(); + streamVariableLengthText( "stdout", stdOut ); + } + + if( !stdErr.empty() ) { + StartSpansLazily(); + streamVariableLengthText( "stderr", stdErr ); + } + + if( m_testSpan.emitted ) { + m_config.stream() << "[Finished: '" << testInfo.getName() << "' "; + ReportCounts( totals ); + m_config.stream() << "]" << std::endl; + } + } + + private: // helpers + + void StartSpansLazily() { + if( !m_testingSpan.emitted ) { + if( m_config.getName().empty() ) + m_config.stream() << "[Started testing]" << std::endl; + else + m_config.stream() << "[Started testing: " << m_config.getName() << "]" << std::endl; + m_testingSpan.emitted = true; + } + + if( !m_groupSpan.emitted && !m_groupSpan.name.empty() ) { + m_config.stream() << "[Started group: '" << m_groupSpan.name << "']" << std::endl; + m_groupSpan.emitted = true; + } + + if( !m_testSpan.emitted ) { + m_config.stream() << std::endl << "[Running: " << m_testSpan.name << "]" << std::endl; + m_testSpan.emitted = true; + } + + if( !m_sectionSpans.empty() ) { + SpanInfo& sectionSpan = m_sectionSpans.back(); + if( !sectionSpan.emitted && !sectionSpan.name.empty() ) { + if( m_firstSectionInTestCase ) { + m_config.stream() << "\n"; + m_firstSectionInTestCase = false; + } + std::vector::iterator it = m_sectionSpans.begin(); + std::vector::iterator itEnd = m_sectionSpans.end(); + for(; it != itEnd; ++it ) { + SpanInfo& prevSpan = *it; + if( !prevSpan.emitted && !prevSpan.name.empty() ) { + m_config.stream() << "[Started section: '" << prevSpan.name << "']" << std::endl; + prevSpan.emitted = true; + } + } + } + } + } + + void streamVariableLengthText( const std::string& prefix, const std::string& text ) { + std::string trimmed = trim( text ); + if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) { + m_config.stream() << "[" << prefix << ": " << trimmed << "]\n"; + } + else { + m_config.stream() << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed + << "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n"; + } + } + + private: + const IReporterConfig& m_config; + bool m_firstSectionInTestCase; + + SpanInfo m_testingSpan; + SpanInfo m_groupSpan; + SpanInfo m_testSpan; + std::vector m_sectionSpans; + bool m_aborted; + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED From 79a6ae297742f4f9ad08ec0c3de588cff76b7ad7 Mon Sep 17 00:00:00 2001 From: Martin Moene Date: Sun, 22 Jul 2012 09:03:37 +0200 Subject: [PATCH 2/4] Removed stray '+' --- include/catch_runner.hpp | 298 +++++++++++++++++++-------------------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index 0e087206..cedf7aae 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -1,149 +1,149 @@ -/* - * Created by Phil on 31/10/2010. - * Copyright 2010 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_RUNNER_HPP_INCLUDED -#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED - -#include "internal/catch_context_impl.hpp" - -#include "internal/catch_commandline.hpp" -#include "internal/catch_list.hpp" -#include "reporters/catch_reporter_basic.hpp" -#include "reporters/catch_reporter_xml.hpp" -#include "reporters/catch_reporter_junit.hpp" - -#include -#include -#include - -namespace Catch { - - INTERNAL_CATCH_REGISTER_REPORTER( "basic", BasicReporter ) - INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) - INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) - - inline int Main( Config& config ) { - - // Handle list request - if( config.listWhat() != List::None ) - return List( config ); - - // Open output file, if specified - std::ofstream ofs; - if( !config.getFilename().empty() ) { - ofs.open( config.getFilename().c_str() ); - if( ofs.fail() ) { - std::cerr << "Unable to open file: '" << config.getFilename() << "'" << std::endl; - return (std::numeric_limits::max)(); - } - config.setStreamBuf( ofs.rdbuf() ); - } - - int result = 0; - - // Scope here for the Runner so it can use the context before it is cleaned-up - { - Runner runner( config ); - - // Run test specs specified on the command line - or default to all - if( !config.testsSpecified() ) { - config.getReporter()->StartGroup( "" ); - runner.runAll(); - config.getReporter()->EndGroup( "", runner.getTotals() ); - } - else { - // !TBD We should get all the testcases upfront, report any missing, - // then just run them - std::vector::const_iterator it = config.getTestSpecs().begin(); - std::vector::const_iterator itEnd = config.getTestSpecs().end(); - for(; it != itEnd; ++it ) { - Totals prevTotals = runner.getTotals(); - config.getReporter()->StartGroup( *it ); - if( runner.runMatching( *it ) == 0 ) { - // Use reporter? - // std::cerr << "\n[Unable to match any test cases with: " << *it << "]" << std::endl; - } - config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals ); - } - } - result = static_cast( runner.getTotals().assertions.failed ); - } - Catch::Context::cleanUp(); - return result; - } - - inline void showUsage( std::ostream& os ) { - os << "\t-?, -h, --help\n" - << "\t-l, --list [xml]\n" - << "\t-t, --test [...]\n" - << "\t-r, --reporter \n" - << "\t-o, --out |<%stream name>\n" - << "\t-s, --success\n" - << "\t-b, --break\n" - << "\t-n, --name \n" - << "\t-a, --abort [#]\n\n" - << "\t-nt, --nothrow\n\n" - << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; - } - inline void showHelp( std::string exeName ) { - std::string::size_type pos = exeName.find_last_of( "/\\" ); - if( pos != std::string::npos ) { - exeName = exeName.substr( pos+1 ); - } - - std::cout << exeName << " is a CATCH host application. Options are as follows:\n\n"; - showUsage( std::cout ); - } - - inline int Main( int argc, char* const argv[], Config& config ) { - - try { - CommandParser parser( argc, argv ); - - if( Command cmd = parser.find( "-h", "-?", "--help" ) ) { - if( cmd.argsCount() != 0 ) - cmd.raiseError( "Does not accept arguments" ); - - showHelp( argv[0] ); - Catch::Context::cleanUp(); - return 0; - } - - parseIntoConfig( parser, config.data() ); - - // !TBD: wire up (do this lazily?) - if( !config.data().reporter.empty() ) - config.setReporter( config.data().reporter ); - - if( !config.data().stream.empty() ) { - if( config.data().stream[0] == '%' ) - config.useStream( config.data().stream.substr( 1 ) ); - else - config.setFilename( config.data().stream ); - } - } - catch( std::exception& ex ) { - std::cerr << ex.what() << + "\n\nUsage: ...\n\n"; - showUsage( std::cerr ); - Catch::Context::cleanUp(); - return (std::numeric_limits::max)(); - } - - return Main( config ); - } - - inline int Main( int argc, char* const argv[] ) { - Config config; -// !TBD: This doesn't always work, for some reason -// if( isDebuggerActive() ) -// config.useStream( "debug" ); - return Main( argc, argv, config ); - } - -} // end namespace Catch - -#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED +/* + * Created by Phil on 31/10/2010. + * Copyright 2010 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_RUNNER_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +#include "internal/catch_context_impl.hpp" + +#include "internal/catch_commandline.hpp" +#include "internal/catch_list.hpp" +#include "reporters/catch_reporter_basic.hpp" +#include "reporters/catch_reporter_xml.hpp" +#include "reporters/catch_reporter_junit.hpp" + +#include +#include +#include + +namespace Catch { + + INTERNAL_CATCH_REGISTER_REPORTER( "basic", BasicReporter ) + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + + inline int Main( Config& config ) { + + // Handle list request + if( config.listWhat() != List::None ) + return List( config ); + + // Open output file, if specified + std::ofstream ofs; + if( !config.getFilename().empty() ) { + ofs.open( config.getFilename().c_str() ); + if( ofs.fail() ) { + std::cerr << "Unable to open file: '" << config.getFilename() << "'" << std::endl; + return (std::numeric_limits::max)(); + } + config.setStreamBuf( ofs.rdbuf() ); + } + + int result = 0; + + // Scope here for the Runner so it can use the context before it is cleaned-up + { + Runner runner( config ); + + // Run test specs specified on the command line - or default to all + if( !config.testsSpecified() ) { + config.getReporter()->StartGroup( "" ); + runner.runAll(); + config.getReporter()->EndGroup( "", runner.getTotals() ); + } + else { + // !TBD We should get all the testcases upfront, report any missing, + // then just run them + std::vector::const_iterator it = config.getTestSpecs().begin(); + std::vector::const_iterator itEnd = config.getTestSpecs().end(); + for(; it != itEnd; ++it ) { + Totals prevTotals = runner.getTotals(); + config.getReporter()->StartGroup( *it ); + if( runner.runMatching( *it ) == 0 ) { + // Use reporter? + // std::cerr << "\n[Unable to match any test cases with: " << *it << "]" << std::endl; + } + config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals ); + } + } + result = static_cast( runner.getTotals().assertions.failed ); + } + Catch::Context::cleanUp(); + return result; + } + + inline void showUsage( std::ostream& os ) { + os << "\t-?, -h, --help\n" + << "\t-l, --list [xml]\n" + << "\t-t, --test [...]\n" + << "\t-r, --reporter \n" + << "\t-o, --out |<%stream name>\n" + << "\t-s, --success\n" + << "\t-b, --break\n" + << "\t-n, --name \n" + << "\t-a, --abort [#]\n\n" + << "\t-nt, --nothrow\n\n" + << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; + } + inline void showHelp( std::string exeName ) { + std::string::size_type pos = exeName.find_last_of( "/\\" ); + if( pos != std::string::npos ) { + exeName = exeName.substr( pos+1 ); + } + + std::cout << exeName << " is a CATCH host application. Options are as follows:\n\n"; + showUsage( std::cout ); + } + + inline int Main( int argc, char* const argv[], Config& config ) { + + try { + CommandParser parser( argc, argv ); + + if( Command cmd = parser.find( "-h", "-?", "--help" ) ) { + if( cmd.argsCount() != 0 ) + cmd.raiseError( "Does not accept arguments" ); + + showHelp( argv[0] ); + Catch::Context::cleanUp(); + return 0; + } + + parseIntoConfig( parser, config.data() ); + + // !TBD: wire up (do this lazily?) + if( !config.data().reporter.empty() ) + config.setReporter( config.data().reporter ); + + if( !config.data().stream.empty() ) { + if( config.data().stream[0] == '%' ) + config.useStream( config.data().stream.substr( 1 ) ); + else + config.setFilename( config.data().stream ); + } + } + catch( std::exception& ex ) { + std::cerr << ex.what() << "\n\nUsage: ...\n\n"; + showUsage( std::cerr ); + Catch::Context::cleanUp(); + return (std::numeric_limits::max)(); + } + + return Main( config ); + } + + inline int Main( int argc, char* const argv[] ) { + Config config; +// !TBD: This doesn't always work, for some reason +// if( isDebuggerActive() ) +// config.useStream( "debug" ); + return Main( argc, argv, config ); + } + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED From 14f1c094f4877fe2a4bf98fead66d637189c8edd Mon Sep 17 00:00:00 2001 From: Martin Moene Date: Sun, 22 Jul 2012 09:13:19 +0200 Subject: [PATCH 3/4] Revert "Removed stray '+'" This reverts commit 79a6ae297742f4f9ad08ec0c3de588cff76b7ad7. --- include/catch_runner.hpp | 298 +++++++++++++++++++-------------------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index cedf7aae..0e087206 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -1,149 +1,149 @@ -/* - * Created by Phil on 31/10/2010. - * Copyright 2010 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_RUNNER_HPP_INCLUDED -#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED - -#include "internal/catch_context_impl.hpp" - -#include "internal/catch_commandline.hpp" -#include "internal/catch_list.hpp" -#include "reporters/catch_reporter_basic.hpp" -#include "reporters/catch_reporter_xml.hpp" -#include "reporters/catch_reporter_junit.hpp" - -#include -#include -#include - -namespace Catch { - - INTERNAL_CATCH_REGISTER_REPORTER( "basic", BasicReporter ) - INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) - INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) - - inline int Main( Config& config ) { - - // Handle list request - if( config.listWhat() != List::None ) - return List( config ); - - // Open output file, if specified - std::ofstream ofs; - if( !config.getFilename().empty() ) { - ofs.open( config.getFilename().c_str() ); - if( ofs.fail() ) { - std::cerr << "Unable to open file: '" << config.getFilename() << "'" << std::endl; - return (std::numeric_limits::max)(); - } - config.setStreamBuf( ofs.rdbuf() ); - } - - int result = 0; - - // Scope here for the Runner so it can use the context before it is cleaned-up - { - Runner runner( config ); - - // Run test specs specified on the command line - or default to all - if( !config.testsSpecified() ) { - config.getReporter()->StartGroup( "" ); - runner.runAll(); - config.getReporter()->EndGroup( "", runner.getTotals() ); - } - else { - // !TBD We should get all the testcases upfront, report any missing, - // then just run them - std::vector::const_iterator it = config.getTestSpecs().begin(); - std::vector::const_iterator itEnd = config.getTestSpecs().end(); - for(; it != itEnd; ++it ) { - Totals prevTotals = runner.getTotals(); - config.getReporter()->StartGroup( *it ); - if( runner.runMatching( *it ) == 0 ) { - // Use reporter? - // std::cerr << "\n[Unable to match any test cases with: " << *it << "]" << std::endl; - } - config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals ); - } - } - result = static_cast( runner.getTotals().assertions.failed ); - } - Catch::Context::cleanUp(); - return result; - } - - inline void showUsage( std::ostream& os ) { - os << "\t-?, -h, --help\n" - << "\t-l, --list [xml]\n" - << "\t-t, --test [...]\n" - << "\t-r, --reporter \n" - << "\t-o, --out |<%stream name>\n" - << "\t-s, --success\n" - << "\t-b, --break\n" - << "\t-n, --name \n" - << "\t-a, --abort [#]\n\n" - << "\t-nt, --nothrow\n\n" - << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; - } - inline void showHelp( std::string exeName ) { - std::string::size_type pos = exeName.find_last_of( "/\\" ); - if( pos != std::string::npos ) { - exeName = exeName.substr( pos+1 ); - } - - std::cout << exeName << " is a CATCH host application. Options are as follows:\n\n"; - showUsage( std::cout ); - } - - inline int Main( int argc, char* const argv[], Config& config ) { - - try { - CommandParser parser( argc, argv ); - - if( Command cmd = parser.find( "-h", "-?", "--help" ) ) { - if( cmd.argsCount() != 0 ) - cmd.raiseError( "Does not accept arguments" ); - - showHelp( argv[0] ); - Catch::Context::cleanUp(); - return 0; - } - - parseIntoConfig( parser, config.data() ); - - // !TBD: wire up (do this lazily?) - if( !config.data().reporter.empty() ) - config.setReporter( config.data().reporter ); - - if( !config.data().stream.empty() ) { - if( config.data().stream[0] == '%' ) - config.useStream( config.data().stream.substr( 1 ) ); - else - config.setFilename( config.data().stream ); - } - } - catch( std::exception& ex ) { - std::cerr << ex.what() << "\n\nUsage: ...\n\n"; - showUsage( std::cerr ); - Catch::Context::cleanUp(); - return (std::numeric_limits::max)(); - } - - return Main( config ); - } - - inline int Main( int argc, char* const argv[] ) { - Config config; -// !TBD: This doesn't always work, for some reason -// if( isDebuggerActive() ) -// config.useStream( "debug" ); - return Main( argc, argv, config ); - } - -} // end namespace Catch - -#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED +/* + * Created by Phil on 31/10/2010. + * Copyright 2010 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_RUNNER_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +#include "internal/catch_context_impl.hpp" + +#include "internal/catch_commandline.hpp" +#include "internal/catch_list.hpp" +#include "reporters/catch_reporter_basic.hpp" +#include "reporters/catch_reporter_xml.hpp" +#include "reporters/catch_reporter_junit.hpp" + +#include +#include +#include + +namespace Catch { + + INTERNAL_CATCH_REGISTER_REPORTER( "basic", BasicReporter ) + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + + inline int Main( Config& config ) { + + // Handle list request + if( config.listWhat() != List::None ) + return List( config ); + + // Open output file, if specified + std::ofstream ofs; + if( !config.getFilename().empty() ) { + ofs.open( config.getFilename().c_str() ); + if( ofs.fail() ) { + std::cerr << "Unable to open file: '" << config.getFilename() << "'" << std::endl; + return (std::numeric_limits::max)(); + } + config.setStreamBuf( ofs.rdbuf() ); + } + + int result = 0; + + // Scope here for the Runner so it can use the context before it is cleaned-up + { + Runner runner( config ); + + // Run test specs specified on the command line - or default to all + if( !config.testsSpecified() ) { + config.getReporter()->StartGroup( "" ); + runner.runAll(); + config.getReporter()->EndGroup( "", runner.getTotals() ); + } + else { + // !TBD We should get all the testcases upfront, report any missing, + // then just run them + std::vector::const_iterator it = config.getTestSpecs().begin(); + std::vector::const_iterator itEnd = config.getTestSpecs().end(); + for(; it != itEnd; ++it ) { + Totals prevTotals = runner.getTotals(); + config.getReporter()->StartGroup( *it ); + if( runner.runMatching( *it ) == 0 ) { + // Use reporter? + // std::cerr << "\n[Unable to match any test cases with: " << *it << "]" << std::endl; + } + config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals ); + } + } + result = static_cast( runner.getTotals().assertions.failed ); + } + Catch::Context::cleanUp(); + return result; + } + + inline void showUsage( std::ostream& os ) { + os << "\t-?, -h, --help\n" + << "\t-l, --list [xml]\n" + << "\t-t, --test [...]\n" + << "\t-r, --reporter \n" + << "\t-o, --out |<%stream name>\n" + << "\t-s, --success\n" + << "\t-b, --break\n" + << "\t-n, --name \n" + << "\t-a, --abort [#]\n\n" + << "\t-nt, --nothrow\n\n" + << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; + } + inline void showHelp( std::string exeName ) { + std::string::size_type pos = exeName.find_last_of( "/\\" ); + if( pos != std::string::npos ) { + exeName = exeName.substr( pos+1 ); + } + + std::cout << exeName << " is a CATCH host application. Options are as follows:\n\n"; + showUsage( std::cout ); + } + + inline int Main( int argc, char* const argv[], Config& config ) { + + try { + CommandParser parser( argc, argv ); + + if( Command cmd = parser.find( "-h", "-?", "--help" ) ) { + if( cmd.argsCount() != 0 ) + cmd.raiseError( "Does not accept arguments" ); + + showHelp( argv[0] ); + Catch::Context::cleanUp(); + return 0; + } + + parseIntoConfig( parser, config.data() ); + + // !TBD: wire up (do this lazily?) + if( !config.data().reporter.empty() ) + config.setReporter( config.data().reporter ); + + if( !config.data().stream.empty() ) { + if( config.data().stream[0] == '%' ) + config.useStream( config.data().stream.substr( 1 ) ); + else + config.setFilename( config.data().stream ); + } + } + catch( std::exception& ex ) { + std::cerr << ex.what() << + "\n\nUsage: ...\n\n"; + showUsage( std::cerr ); + Catch::Context::cleanUp(); + return (std::numeric_limits::max)(); + } + + return Main( config ); + } + + inline int Main( int argc, char* const argv[] ) { + Config config; +// !TBD: This doesn't always work, for some reason +// if( isDebuggerActive() ) +// config.useStream( "debug" ); + return Main( argc, argv, config ); + } + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED From a0c496fefc493566d3cf73aa4763845f8061d653 Mon Sep 17 00:00:00 2001 From: Martin Moene Date: Sun, 22 Jul 2012 09:14:19 +0200 Subject: [PATCH 4/4] Revert "Fixed issue #101, missing space in end of section message" This reverts commit 1ad971ea2b77a2df0bb560ce61f7eca4cb353eb1. --- include/reporters/catch_reporter_basic.hpp | 666 ++++++++++----------- 1 file changed, 333 insertions(+), 333 deletions(-) diff --git a/include/reporters/catch_reporter_basic.hpp b/include/reporters/catch_reporter_basic.hpp index b620544e..f5fc6ee1 100644 --- a/include/reporters/catch_reporter_basic.hpp +++ b/include/reporters/catch_reporter_basic.hpp @@ -1,333 +1,333 @@ -/* - * Created by Phil on 28/10/2010. - * Copyright 2010 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_REPORTER_BASIC_HPP_INCLUDED -#define TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED - -#include "../internal/catch_capture.hpp" -#include "../internal/catch_interfaces_reporter.h" -#include "../internal/catch_reporter_registrars.hpp" -#include "../internal/catch_console_colour.hpp" - -namespace Catch { - - struct pluralise { - pluralise( std::size_t count, const std::string& label ) - : m_count( count ), - m_label( label ) - {} - - friend std::ostream& operator << ( std::ostream& os, const pluralise& pluraliser ) { - os << pluraliser.m_count << " " << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << "s"; - return os; - } - - std::size_t m_count; - std::string m_label; - }; - - class BasicReporter : public SharedImpl { - - struct SpanInfo { - - SpanInfo() - : emitted( false ) - {} - - SpanInfo( const std::string& spanName ) - : name( spanName ), - emitted( false ) - {} - - SpanInfo( const SpanInfo& other ) - : name( other.name ), - emitted( other.emitted ) - {} - - std::string name; - bool emitted; - }; - - public: - BasicReporter( const IReporterConfig& config ) - : m_config( config ), - m_firstSectionInTestCase( true ), - m_aborted( false ) - {} - - static std::string getDescription() { - return "Reports test results as lines of text"; - } - - private: - - 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 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed"; - } - - 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, allPrefix ); - if( totals.testCases.failed > 0 ) { - m_config.stream() << " ("; - ReportCounts( "assertion", totals.assertions, allPrefix ); - m_config.stream() << ")"; - } - } - else { - TextColour colour( TextColour::ResultSuccess ); - m_config.stream() << allPrefix << "tests passed (" - << pluralise( totals.assertions.passed, "assertion" ) << " in " - << pluralise( totals.testCases.passed, "test case" ) << ")"; - } - } - - private: // IReporter - - virtual bool shouldRedirectStdout() const { - return false; - } - - virtual void StartTesting() { - 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 - 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; - } - - virtual void StartGroup( const std::string& groupName ) { - m_groupSpan = groupName; - } - - virtual void EndGroup( const std::string& groupName, const Totals& totals ) { - if( m_groupSpan.emitted && !groupName.empty() ) { - m_config.stream() << "[End of group: '" << groupName << "'. "; - ReportCounts( totals ); - m_config.stream() << "]\n" << std::endl; - m_groupSpan = SpanInfo(); - } - } - - virtual void StartTestCase( const TestCaseInfo& testInfo ) { - m_testSpan = testInfo.getName(); - } - - virtual void StartSection( const std::string& sectionName, const std::string& ) { - m_sectionSpans.push_back( SpanInfo( sectionName ) ); - } - - virtual void EndSection( const std::string& sectionName, const Counts& assertions ) { - SpanInfo& sectionSpan = m_sectionSpans.back(); - if( sectionSpan.emitted && !sectionSpan.name.empty() ) { - m_config.stream() << "[End of section: '" << sectionName << "' "; - - if( assertions.failed ) { - TextColour colour( TextColour::ResultError ); - ReportCounts( "assertion", assertions); - } - else { - TextColour colour( TextColour::ResultSuccess ); - m_config.stream() << ( assertions.passed > 1 ? "All " : "" ) - << pluralise( assertions.passed, "assertion" ) << " passed" ; - } - m_config.stream() << "]\n" << std::endl; - } - m_sectionSpans.pop_back(); - } - - virtual void Result( const ResultInfo& resultInfo ) { - if( !m_config.includeSuccessfulResults() && resultInfo.getResultType() == ResultWas::Ok ) - return; - - StartSpansLazily(); - - if( !resultInfo.getFilename().empty() ) { - TextColour colour( TextColour::FileName ); - m_config.stream() << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() ); - } - - if( resultInfo.hasExpression() ) { - TextColour colour( TextColour::OriginalExpression ); - m_config.stream() << resultInfo.getExpression(); - if( resultInfo.ok() ) { - TextColour successColour( TextColour::Success ); - m_config.stream() << " succeeded"; - } - else { - TextColour errorColour( TextColour::Error ); - m_config.stream() << " failed"; - } - } - switch( resultInfo.getResultType() ) { - case ResultWas::ThrewException: - { - TextColour colour( TextColour::Error ); - if( resultInfo.hasExpression() ) - m_config.stream() << " with unexpected"; - else - m_config.stream() << "Unexpected"; - m_config.stream() << " exception with message: '" << resultInfo.getMessage() << "'"; - } - break; - case ResultWas::DidntThrowException: - { - TextColour colour( TextColour::Error ); - if( resultInfo.hasExpression() ) - m_config.stream() << " because no exception was thrown where one was expected"; - else - m_config.stream() << "No exception thrown where one was expected"; - } - break; - case ResultWas::Info: - streamVariableLengthText( "info", resultInfo.getMessage() ); - break; - case ResultWas::Warning: - m_config.stream() << "warning:\n'" << resultInfo.getMessage() << "'"; - break; - case ResultWas::ExplicitFailure: - { - TextColour colour( TextColour::Error ); - m_config.stream() << "failed with message: '" << resultInfo.getMessage() << "'"; - } - break; - case ResultWas::Unknown: // These cases are here to prevent compiler warnings - case ResultWas::Ok: - case ResultWas::FailureBit: - case ResultWas::ExpressionFailed: - case ResultWas::Exception: - default: - if( !resultInfo.hasExpression() ) { - if( resultInfo.ok() ) { - TextColour colour( TextColour::Success ); - m_config.stream() << " succeeded"; - } - else { - TextColour colour( TextColour::Error ); - m_config.stream() << " failed"; - } - } - break; - } - - if( resultInfo.hasExpandedExpression() ) { - m_config.stream() << " for: "; - TextColour colour( TextColour::ReconstructedExpression ); - m_config.stream() << resultInfo.getExpandedExpression(); - } - m_config.stream() << std::endl; - } - - virtual void EndTestCase( const TestCaseInfo& testInfo, - const Totals& totals, - const std::string& stdOut, - const std::string& stdErr ) { - if( !stdOut.empty() ) { - StartSpansLazily(); - streamVariableLengthText( "stdout", stdOut ); - } - - if( !stdErr.empty() ) { - StartSpansLazily(); - streamVariableLengthText( "stderr", stdErr ); - } - - if( m_testSpan.emitted ) { - m_config.stream() << "[Finished: '" << testInfo.getName() << "' "; - ReportCounts( totals ); - m_config.stream() << "]" << std::endl; - } - } - - private: // helpers - - void StartSpansLazily() { - if( !m_testingSpan.emitted ) { - if( m_config.getName().empty() ) - m_config.stream() << "[Started testing]" << std::endl; - else - m_config.stream() << "[Started testing: " << m_config.getName() << "]" << std::endl; - m_testingSpan.emitted = true; - } - - if( !m_groupSpan.emitted && !m_groupSpan.name.empty() ) { - m_config.stream() << "[Started group: '" << m_groupSpan.name << "']" << std::endl; - m_groupSpan.emitted = true; - } - - if( !m_testSpan.emitted ) { - m_config.stream() << std::endl << "[Running: " << m_testSpan.name << "]" << std::endl; - m_testSpan.emitted = true; - } - - if( !m_sectionSpans.empty() ) { - SpanInfo& sectionSpan = m_sectionSpans.back(); - if( !sectionSpan.emitted && !sectionSpan.name.empty() ) { - if( m_firstSectionInTestCase ) { - m_config.stream() << "\n"; - m_firstSectionInTestCase = false; - } - std::vector::iterator it = m_sectionSpans.begin(); - std::vector::iterator itEnd = m_sectionSpans.end(); - for(; it != itEnd; ++it ) { - SpanInfo& prevSpan = *it; - if( !prevSpan.emitted && !prevSpan.name.empty() ) { - m_config.stream() << "[Started section: '" << prevSpan.name << "']" << std::endl; - prevSpan.emitted = true; - } - } - } - } - } - - void streamVariableLengthText( const std::string& prefix, const std::string& text ) { - std::string trimmed = trim( text ); - if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) { - m_config.stream() << "[" << prefix << ": " << trimmed << "]\n"; - } - else { - m_config.stream() << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed - << "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n"; - } - } - - private: - const IReporterConfig& m_config; - bool m_firstSectionInTestCase; - - SpanInfo m_testingSpan; - SpanInfo m_groupSpan; - SpanInfo m_testSpan; - std::vector m_sectionSpans; - bool m_aborted; - }; - -} // end namespace Catch - -#endif // TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED +/* + * Created by Phil on 28/10/2010. + * Copyright 2010 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_REPORTER_BASIC_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED + +#include "../internal/catch_capture.hpp" +#include "../internal/catch_interfaces_reporter.h" +#include "../internal/catch_reporter_registrars.hpp" +#include "../internal/catch_console_colour.hpp" + +namespace Catch { + + struct pluralise { + pluralise( std::size_t count, const std::string& label ) + : m_count( count ), + m_label( label ) + {} + + friend std::ostream& operator << ( std::ostream& os, const pluralise& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + std::size_t m_count; + std::string m_label; + }; + + class BasicReporter : public SharedImpl { + + struct SpanInfo { + + SpanInfo() + : emitted( false ) + {} + + SpanInfo( const std::string& spanName ) + : name( spanName ), + emitted( false ) + {} + + SpanInfo( const SpanInfo& other ) + : name( other.name ), + emitted( other.emitted ) + {} + + std::string name; + bool emitted; + }; + + public: + BasicReporter( const IReporterConfig& config ) + : m_config( config ), + m_firstSectionInTestCase( true ), + m_aborted( false ) + {} + + static std::string getDescription() { + return "Reports test results as lines of text"; + } + + private: + + 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 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed"; + } + + 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, allPrefix ); + if( totals.testCases.failed > 0 ) { + m_config.stream() << " ("; + ReportCounts( "assertion", totals.assertions, allPrefix ); + m_config.stream() << ")"; + } + } + else { + TextColour colour( TextColour::ResultSuccess ); + m_config.stream() << allPrefix << "tests passed (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")"; + } + } + + private: // IReporter + + virtual bool shouldRedirectStdout() const { + return false; + } + + virtual void StartTesting() { + 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 + 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; + } + + virtual void StartGroup( const std::string& groupName ) { + m_groupSpan = groupName; + } + + virtual void EndGroup( const std::string& groupName, const Totals& totals ) { + if( m_groupSpan.emitted && !groupName.empty() ) { + m_config.stream() << "[End of group: '" << groupName << "'. "; + ReportCounts( totals ); + m_config.stream() << "]\n" << std::endl; + m_groupSpan = SpanInfo(); + } + } + + virtual void StartTestCase( const TestCaseInfo& testInfo ) { + m_testSpan = testInfo.getName(); + } + + virtual void StartSection( const std::string& sectionName, const std::string& ) { + m_sectionSpans.push_back( SpanInfo( sectionName ) ); + } + + virtual void EndSection( const std::string& sectionName, const Counts& assertions ) { + SpanInfo& sectionSpan = m_sectionSpans.back(); + if( sectionSpan.emitted && !sectionSpan.name.empty() ) { + m_config.stream() << "[End of section: '" << sectionName << "' "; + + if( assertions.failed ) { + TextColour colour( TextColour::ResultError ); + ReportCounts( "assertion", assertions); + } + else { + TextColour colour( TextColour::ResultSuccess ); + m_config.stream() << ( assertions.passed > 1 ? "All " : "" ) + << pluralise( assertions.passed, "assertion" ) << "passed" ; + } + m_config.stream() << "]\n" << std::endl; + } + m_sectionSpans.pop_back(); + } + + virtual void Result( const ResultInfo& resultInfo ) { + if( !m_config.includeSuccessfulResults() && resultInfo.getResultType() == ResultWas::Ok ) + return; + + StartSpansLazily(); + + if( !resultInfo.getFilename().empty() ) { + TextColour colour( TextColour::FileName ); + m_config.stream() << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() ); + } + + if( resultInfo.hasExpression() ) { + TextColour colour( TextColour::OriginalExpression ); + m_config.stream() << resultInfo.getExpression(); + if( resultInfo.ok() ) { + TextColour successColour( TextColour::Success ); + m_config.stream() << " succeeded"; + } + else { + TextColour errorColour( TextColour::Error ); + m_config.stream() << " failed"; + } + } + switch( resultInfo.getResultType() ) { + case ResultWas::ThrewException: + { + TextColour colour( TextColour::Error ); + if( resultInfo.hasExpression() ) + m_config.stream() << " with unexpected"; + else + m_config.stream() << "Unexpected"; + m_config.stream() << " exception with message: '" << resultInfo.getMessage() << "'"; + } + break; + case ResultWas::DidntThrowException: + { + TextColour colour( TextColour::Error ); + if( resultInfo.hasExpression() ) + m_config.stream() << " because no exception was thrown where one was expected"; + else + m_config.stream() << "No exception thrown where one was expected"; + } + break; + case ResultWas::Info: + streamVariableLengthText( "info", resultInfo.getMessage() ); + break; + case ResultWas::Warning: + m_config.stream() << "warning:\n'" << resultInfo.getMessage() << "'"; + break; + case ResultWas::ExplicitFailure: + { + TextColour colour( TextColour::Error ); + m_config.stream() << "failed with message: '" << resultInfo.getMessage() << "'"; + } + break; + case ResultWas::Unknown: // These cases are here to prevent compiler warnings + case ResultWas::Ok: + case ResultWas::FailureBit: + case ResultWas::ExpressionFailed: + case ResultWas::Exception: + default: + if( !resultInfo.hasExpression() ) { + if( resultInfo.ok() ) { + TextColour colour( TextColour::Success ); + m_config.stream() << " succeeded"; + } + else { + TextColour colour( TextColour::Error ); + m_config.stream() << " failed"; + } + } + break; + } + + if( resultInfo.hasExpandedExpression() ) { + m_config.stream() << " for: "; + TextColour colour( TextColour::ReconstructedExpression ); + m_config.stream() << resultInfo.getExpandedExpression(); + } + m_config.stream() << std::endl; + } + + virtual void EndTestCase( const TestCaseInfo& testInfo, + const Totals& totals, + const std::string& stdOut, + const std::string& stdErr ) { + if( !stdOut.empty() ) { + StartSpansLazily(); + streamVariableLengthText( "stdout", stdOut ); + } + + if( !stdErr.empty() ) { + StartSpansLazily(); + streamVariableLengthText( "stderr", stdErr ); + } + + if( m_testSpan.emitted ) { + m_config.stream() << "[Finished: '" << testInfo.getName() << "' "; + ReportCounts( totals ); + m_config.stream() << "]" << std::endl; + } + } + + private: // helpers + + void StartSpansLazily() { + if( !m_testingSpan.emitted ) { + if( m_config.getName().empty() ) + m_config.stream() << "[Started testing]" << std::endl; + else + m_config.stream() << "[Started testing: " << m_config.getName() << "]" << std::endl; + m_testingSpan.emitted = true; + } + + if( !m_groupSpan.emitted && !m_groupSpan.name.empty() ) { + m_config.stream() << "[Started group: '" << m_groupSpan.name << "']" << std::endl; + m_groupSpan.emitted = true; + } + + if( !m_testSpan.emitted ) { + m_config.stream() << std::endl << "[Running: " << m_testSpan.name << "]" << std::endl; + m_testSpan.emitted = true; + } + + if( !m_sectionSpans.empty() ) { + SpanInfo& sectionSpan = m_sectionSpans.back(); + if( !sectionSpan.emitted && !sectionSpan.name.empty() ) { + if( m_firstSectionInTestCase ) { + m_config.stream() << "\n"; + m_firstSectionInTestCase = false; + } + std::vector::iterator it = m_sectionSpans.begin(); + std::vector::iterator itEnd = m_sectionSpans.end(); + for(; it != itEnd; ++it ) { + SpanInfo& prevSpan = *it; + if( !prevSpan.emitted && !prevSpan.name.empty() ) { + m_config.stream() << "[Started section: '" << prevSpan.name << "']" << std::endl; + prevSpan.emitted = true; + } + } + } + } + } + + void streamVariableLengthText( const std::string& prefix, const std::string& text ) { + std::string trimmed = trim( text ); + if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) { + m_config.stream() << "[" << prefix << ": " << trimmed << "]\n"; + } + else { + m_config.stream() << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed + << "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n"; + } + } + + private: + const IReporterConfig& m_config; + bool m_firstSectionInTestCase; + + SpanInfo m_testingSpan; + SpanInfo m_groupSpan; + SpanInfo m_testSpan; + std::vector m_sectionSpans; + bool m_aborted; + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED