diff --git a/.travis.yml b/.travis.yml index e63a76a3..8b519069 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,7 +64,7 @@ matrix: compiler: clang addons: &clang38 apt: - sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test'] + sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test'] packages: ['clang-3.8'] env: COMPILER='ccache clang++-3.8' BUILD_TYPE='Release' @@ -119,23 +119,22 @@ matrix: # 3/ OSX Clang Builds - os: osx - osx_image: xcode6.4 + osx_image: xcode7 compiler: clang env: COMPILER='ccache clang++' BUILD_TYPE='Debug' - os: osx - osx_image: xcode6.4 + osx_image: xcode7 compiler: clang env: COMPILER='ccache clang++' BUILD_TYPE='Release' - - os: osx - osx_image: xcode7 + osx_image: xcode8 compiler: clang env: COMPILER='ccache clang++' BUILD_TYPE='Debug' - os: osx - osx_image: xcode7 + osx_image: xcode8 compiler: clang env: COMPILER='ccache clang++' BUILD_TYPE='Release' @@ -149,7 +148,8 @@ install: mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake export PATH=${DEPS_DIR}/cmake/bin:${PATH} elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - brew install cmake ccache + which cmake || brew install cmake + which ccache || brew install ccache fi before_script: diff --git a/README.md b/README.md index b530bb87..88ed122f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![catch logo](catch-logo-small.png) -*v1.4.0* +*v1.5.8* Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch) diff --git a/docs/tutorial.md b/docs/tutorial.md index 0fdaff9b..1aa2a659 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -1,6 +1,6 @@ # Getting Catch -The simplest way to get Catch is to download the single header version from [http://builds.catch-lib.net](http://builds.catch-lib.net). Don't be put off by the word "builds" there. The single header is generated by merging a set of individual headers but it is still just normal source code in a header file. +The simplest way to get Catch is to download the latest [single header version](https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file. The full source for Catch, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there. diff --git a/include/catch_session.hpp b/include/catch_session.hpp index 3884b957..a9c33664 100644 --- a/include/catch_session.hpp +++ b/include/catch_session.hpp @@ -131,10 +131,10 @@ namespace Catch { Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } - int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); - m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); if( m_configData.showHelp ) showHelp( m_configData.processName ); m_config.reset(); @@ -158,16 +158,13 @@ namespace Catch { m_config.reset(); } - int run( int argc, char const* argv[] ) { + int run( int argc, char const* const* const argv ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) returnCode = run(); return returnCode; } - int run( int argc, char* argv[] ) { - return run( argc, const_cast( argv ) ); - } int run() { if( m_configData.showHelp ) diff --git a/include/external/clara.h b/include/external/clara.h index f2ea14b2..369c1b76 100644 --- a/include/external/clara.h +++ b/include/external/clara.h @@ -6,7 +6,7 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ -// Version 0.0.1.1 +// Version 0.0.2.4 // Only use header guard if we are not using an outer namespace #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) @@ -343,6 +343,11 @@ namespace Tbc { #include #include +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CLARA_PLATFORM_WINDOWS +#endif + + // Use optional outer namespace #ifdef STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE @@ -366,9 +371,6 @@ namespace Clara { const unsigned int consoleWidth = 80; #endif - // Use this to try and stop compiler from warning about unreachable code - inline bool isTrue( bool value ) { return value; } - using namespace Tbc; inline bool startsWith( std::string const& str, std::string const& prefix ) { @@ -404,14 +406,7 @@ namespace Clara { else throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); } - inline void convertInto( bool _source, bool& _dest ) { - _dest = _source; - } - template - inline void convertInto( bool, T& ) { - if( isTrue( true ) ) - throw std::runtime_error( "Invalid conversion" ); - } + template struct IArgFunction { @@ -421,7 +416,6 @@ namespace Clara { IArgFunction( IArgFunction const& ) = default; #endif virtual void set( ConfigT& config, std::string const& value ) const = 0; - virtual void setFlag( ConfigT& config ) const = 0; virtual bool takesArg() const = 0; virtual IArgFunction* clone() const = 0; }; @@ -443,9 +437,6 @@ namespace Clara { void set( ConfigT& config, std::string const& value ) const { functionObj->set( config, value ); } - void setFlag( ConfigT& config ) const { - functionObj->setFlag( config ); - } bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { @@ -459,7 +450,6 @@ namespace Clara { template struct NullBinder : IArgFunction{ virtual void set( C&, std::string const& ) const {} - virtual void setFlag( C& ) const {} virtual bool takesArg() const { return true; } virtual IArgFunction* clone() const { return new NullBinder( *this ); } }; @@ -470,9 +460,6 @@ namespace Clara { virtual void set( C& p, std::string const& stringValue ) const { convertInto( stringValue, p.*member ); } - virtual void setFlag( C& p ) const { - convertInto( true, p.*member ); - } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } M C::* member; @@ -485,11 +472,6 @@ namespace Clara { convertInto( stringValue, value ); (p.*member)( value ); } - virtual void setFlag( C& p ) const { - typename RemoveConstRef::type value; - convertInto( true, value ); - (p.*member)( value ); - } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } void (C::*member)( M ); @@ -503,9 +485,6 @@ namespace Clara { if( value ) (p.*member)(); } - virtual void setFlag( C& p ) const { - (p.*member)(); - } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } void (C::*member)(); @@ -520,9 +499,6 @@ namespace Clara { if( value ) function( obj ); } - virtual void setFlag( C& p ) const { - function( p ); - } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } void (*function)( C& ); @@ -536,11 +512,6 @@ namespace Clara { convertInto( stringValue, value ); function( obj, value ); } - virtual void setFlag( C& obj ) const { - typename RemoveConstRef::type value; - convertInto( true, value ); - function( obj, value ); - } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } void (*function)( C&, T ); @@ -548,8 +519,20 @@ namespace Clara { } // namespace Detail - struct Parser { - Parser() : separators( " \t=:" ) {} + inline std::vector argsToVector( int argc, char const* const* const argv ) { + std::vector args( static_cast( argc ) ); + for( std::size_t i = 0; i < static_cast( argc ); ++i ) + args[i] = argv[i]; + + return args; + } + + class Parser { + enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; + Mode mode; + std::size_t from; + bool inQuotes; + public: struct Token { enum Type { Positional, ShortOpt, LongOpt }; @@ -558,38 +541,75 @@ namespace Clara { std::string data; }; - void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + Parser() : mode( None ), from( 0 ), inQuotes( false ){} + + void parseIntoTokens( std::vector const& args, std::vector& tokens ) { const std::string doubleDash = "--"; - for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) - parseIntoTokens( argv[i] , tokens); + for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) + parseIntoTokens( args[i], tokens); } - void parseIntoTokens( std::string arg, std::vector& tokens ) const { - while( !arg.empty() ) { - Parser::Token token( Parser::Token::Positional, arg ); - arg = ""; - if( token.data[0] == '-' ) { - if( token.data.size() > 1 && token.data[1] == '-' ) { - token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); - } - else { - token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); - if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { - arg = "-" + token.data.substr( 1 ); - token.data = token.data.substr( 0, 1 ); - } - } - } - if( token.type != Parser::Token::Positional ) { - std::size_t pos = token.data.find_first_of( separators ); - if( pos != std::string::npos ) { - arg = token.data.substr( pos+1 ); - token.data = token.data.substr( 0, pos ); - } - } - tokens.push_back( token ); + + void parseIntoTokens( std::string const& arg, std::vector& tokens ) { + for( std::size_t i = 0; i <= arg.size(); ++i ) { + char c = arg[i]; + if( c == '"' ) + inQuotes = !inQuotes; + mode = handleMode( i, c, arg, tokens ); } } - std::string separators; + Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + switch( mode ) { + case None: return handleNone( i, c ); + case MaybeShortOpt: return handleMaybeShortOpt( i, c ); + case ShortOpt: + case LongOpt: + case SlashOpt: return handleOpt( i, c, arg, tokens ); + case Positional: return handlePositional( i, c, arg, tokens ); + default: throw std::logic_error( "Unknown mode" ); + } + } + + Mode handleNone( std::size_t i, char c ) { + if( inQuotes ) { + from = i; + return Positional; + } + switch( c ) { + case '-': return MaybeShortOpt; +#ifdef CLARA_PLATFORM_WINDOWS + case '/': from = i+1; return SlashOpt; +#endif + default: from = i; return Positional; + } + } + Mode handleMaybeShortOpt( std::size_t i, char c ) { + switch( c ) { + case '-': from = i+1; return LongOpt; + default: from = i; return ShortOpt; + } + } + Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) + return mode; + + std::string optName = arg.substr( from, i-from ); + if( mode == ShortOpt ) + for( std::size_t j = 0; j < optName.size(); ++j ) + tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); + else if( mode == SlashOpt && optName.size() == 1 ) + tokens.push_back( Token( Token::ShortOpt, optName ) ); + else + tokens.push_back( Token( Token::LongOpt, optName ) ); + return None; + } + Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) + return mode; + + std::string data = arg.substr( from, i-from ); + tokens.push_back( Token( Token::Positional, data ) ); + return None; + } }; template @@ -894,21 +914,21 @@ namespace Clara { return oss.str(); } - ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT parse( std::vector const& args ) const { ConfigT config; - parseInto( argc, argv, config ); + parseInto( args, config ); return config; } - std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { - std::string processName = argv[0]; + std::vector parseInto( std::vector const& args, ConfigT& config ) const { + std::string processName = args[0]; std::size_t lastSlash = processName.find_last_of( "/\\" ); if( lastSlash != std::string::npos ) processName = processName.substr( lastSlash+1 ); m_boundProcessName.set( config, processName ); std::vector tokens; Parser parser; - parser.parseIntoTokens( argc, argv, tokens ); + parser.parseIntoTokens( args, tokens ); return populate( tokens, config ); } @@ -939,7 +959,7 @@ namespace Clara { arg.boundField.set( config, tokens[++i].data ); } else { - arg.boundField.setFlag( config ); + arg.boundField.set( config, "true" ); } break; } diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 1496fe3a..fa5835b8 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -40,7 +40,7 @@ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + } while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index 6926559a..89eced34 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -85,8 +85,11 @@ namespace Catch { std::string line; while( std::getline( f, line ) ) { line = trim(line); - if( !line.empty() && !startsWith( line, "#" ) ) - addTestOrTags( config, "\"" + line + "\"," ); + if( !line.empty() && !startsWith( line, "#" ) ) { + if( !startsWith( line, "\"" ) ) + line = "\"" + line + "\""; + addTestOrTags( config, line + "," ); + } } } diff --git a/include/internal/catch_common.hpp b/include/internal/catch_common.hpp index 2342ae61..7ad5b1ca 100644 --- a/include/internal/catch_common.hpp +++ b/include/internal/catch_common.hpp @@ -21,8 +21,11 @@ namespace Catch { bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } + char toLowerCh(char c) { + return static_cast( ::tolower( c ) ); + } void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } std::string toLower( std::string const& s ) { std::string lc = s; diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h index ed4aa52b..5af1e76a 100644 --- a/include/internal/catch_compiler_capabilities.h +++ b/include/internal/catch_compiler_capabilities.h @@ -36,8 +36,16 @@ // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 -#if defined(__cplusplus) && __cplusplus >= 201103L -# define CATCH_CPP11_OR_GREATER +#ifdef __cplusplus + +# if __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +# endif + +# if __cplusplus >= 201402L +# define CATCH_CPP14_OR_GREATER +# endif + #endif #ifdef __clang__ diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp index 2665f474..72b0f6c7 100644 --- a/include/internal/catch_config.hpp +++ b/include/internal/catch_config.hpp @@ -151,7 +151,7 @@ namespace Catch { } ConfigData m_data; - std::auto_ptr m_stream; + CATCH_AUTO_PTR( IStream const ) m_stream; TestSpec m_testSpec; }; diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h index d1c6e704..98e2cd6a 100644 --- a/include/internal/catch_interfaces_reporter.h +++ b/include/internal/catch_interfaces_reporter.h @@ -219,6 +219,7 @@ namespace Catch bool aborting; }; + class MultipleReporters; struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); @@ -247,6 +248,8 @@ namespace Catch virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } }; diff --git a/include/internal/catch_list.hpp b/include/internal/catch_list.hpp index 4c87ccf4..f83827ee 100644 --- a/include/internal/catch_list.hpp +++ b/include/internal/catch_list.hpp @@ -68,7 +68,10 @@ namespace Catch { ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Catch::cout() << testCaseInfo.name << std::endl; + if( startsWith( testCaseInfo.name, "#" ) ) + Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl; + else + Catch::cout() << testCaseInfo.name << std::endl; } return matchedTests; } diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h index 5f22ad67..1bf5ee18 100644 --- a/include/internal/catch_stream.h +++ b/include/internal/catch_stream.h @@ -49,7 +49,7 @@ namespace Catch { class DebugOutStream : public IStream { - std::auto_ptr m_streamBuf; + CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; mutable std::ostream m_os; public: DebugOutStream(); diff --git a/include/internal/catch_test_case_registry_impl.hpp b/include/internal/catch_test_case_registry_impl.hpp index a2b041a3..a70b019b 100644 --- a/include/internal/catch_test_case_registry_impl.hpp +++ b/include/internal/catch_test_case_registry_impl.hpp @@ -19,13 +19,31 @@ #include #include +#ifdef CATCH_CPP14_OR_GREATER +#include +#endif + namespace Catch { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i + static void shuffle( V& vector ) { + RandomNumberGenerator rng; +#ifdef CATCH_CPP14_OR_GREATER + std::shuffle( vector.begin(), vector.end(), rng ); +#else + std::random_shuffle( vector.begin(), vector.end(), rng ); +#endif + } }; inline std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { @@ -34,14 +52,12 @@ namespace Catch { switch( config.runOrder() ) { case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end(), LexSort() ); + std::sort( sorted.begin(), sorted.end() ); break; case RunTests::InRandomOrder: { seedRng( config ); - - RandomNumberGenerator rng; - std::random_shuffle( sorted.begin(), sorted.end(), rng ); + RandomNumberGenerator::shuffle( sorted ); } break; case RunTests::InDeclarationOrder: @@ -60,13 +76,15 @@ namespace Catch { it != itEnd; ++it ) { std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); - if( !prev.second ){ - Catch::cerr() - << Colour( Colour::Red ) - << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; - exit(1); + if( !prev.second ) { + std::ostringstream ss; + + ss << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + + throw std::runtime_error(ss.str()); } } } diff --git a/include/internal/catch_test_case_tracker.hpp b/include/internal/catch_test_case_tracker.hpp index 505c3ab8..3973e7b9 100644 --- a/include/internal/catch_test_case_tracker.hpp +++ b/include/internal/catch_test_case_tracker.hpp @@ -41,6 +41,10 @@ namespace TestCaseTracking { virtual void addChild( Ptr const& child ) = 0; virtual ITracker* findChild( std::string const& name ) = 0; virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isIndexTracker() const = 0; }; class TrackerContext { @@ -167,6 +171,10 @@ namespace TestCaseTracking { m_parent->openChild(); } } + + virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } + virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } + void open() { m_runState = Executing; moveToThis(); @@ -230,13 +238,16 @@ namespace TestCaseTracking { {} virtual ~SectionTracker(); + virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { SectionTracker* section = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( name ) ) { - section = dynamic_cast( childTracker ); - assert( section ); + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = static_cast( childTracker ); } else { section = new SectionTracker( name, ctx, ¤tTracker ); @@ -261,13 +272,16 @@ namespace TestCaseTracking { {} virtual ~IndexTracker(); + virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { IndexTracker* tracker = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( name ) ) { - tracker = dynamic_cast( childTracker ); - assert( tracker ); + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = static_cast( childTracker ); } else { tracker = new IndexTracker( name, ctx, ¤tTracker, size ); diff --git a/include/internal/catch_test_spec.hpp b/include/internal/catch_test_spec.hpp index 7e4ea9d1..3ec59b55 100644 --- a/include/internal/catch_test_spec.hpp +++ b/include/internal/catch_test_spec.hpp @@ -64,10 +64,11 @@ namespace Catch { bool matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match - for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { if( !(*it)->matches( testCase ) ) return false; - return true; + } + return true; } }; diff --git a/include/internal/catch_version.hpp b/include/internal/catch_version.hpp index 8409e0bd..cca4c6e0 100644 --- a/include/internal/catch_version.hpp +++ b/include/internal/catch_version.hpp @@ -37,7 +37,7 @@ namespace Catch { return os; } - Version libraryVersion( 1, 4, 0, "", 0 ); + Version libraryVersion( 1, 5, 8, "", 0 ); } diff --git a/include/internal/catch_xmlwriter.hpp b/include/internal/catch_xmlwriter.hpp index cdff5a2e..6d182269 100644 --- a/include/internal/catch_xmlwriter.hpp +++ b/include/internal/catch_xmlwriter.hpp @@ -55,9 +55,10 @@ namespace Catch { break; default: - // Escape control chars - based on contribution by @espenalb in PR #465 + // Escape control chars - based on contribution by @espenalb in PR #465 and + // by @mrpi PR #588 if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) - os << "&#x" << std::uppercase << std::hex << static_cast( c ) << ";"; + os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast( c ) << ';'; else os << c; } @@ -112,13 +113,20 @@ namespace Catch { : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &Catch::cout() ) - {} + { + // We encode control characters, which requires + // XML 1.1 + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + *m_os << "\n"; + } XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &os ) - {} + { + *m_os << "\n"; + } ~XmlWriter() { while( !m_tags.empty() ) diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp index 4fdeb195..cfc28f29 100644 --- a/include/reporters/catch_reporter_bases.hpp +++ b/include/reporters/catch_reporter_bases.hpp @@ -166,7 +166,7 @@ namespace Catch { virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back( assertionStats ); diff --git a/include/reporters/catch_reporter_multi.hpp b/include/reporters/catch_reporter_multi.hpp index d3282666..7fc08f69 100644 --- a/include/reporters/catch_reporter_multi.hpp +++ b/include/reporters/catch_reporter_multi.hpp @@ -118,13 +118,18 @@ public: // IStreamingReporter ++it ) (*it)->skipTest( testInfo ); } + + virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { + return this; + } + }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { Ptr resultingReporter; if( existingReporter ) { - MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + MultipleReporters* multi = existingReporter->tryAsMulti(); if( !multi ) { multi = new MultipleReporters; resultingReporter = Ptr( multi ); diff --git a/include/reporters/catch_reporter_xml.hpp b/include/reporters/catch_reporter_xml.hpp index bbe8780b..153f0e7a 100644 --- a/include/reporters/catch_reporter_xml.hpp +++ b/include/reporters/catch_reporter_xml.hpp @@ -53,7 +53,7 @@ namespace Catch { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); @@ -115,7 +115,7 @@ namespace Catch { .writeText( assertionResult.getMessage() ); break; case ResultWas::FatalErrorCondition: - m_xml.scopedElement( "Fatal Error Condition" ) + m_xml.scopedElement( "FatalErrorCondition" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt index 960d9fb1..f4fb704f 100644 --- a/projects/CMake/CMakeLists.txt +++ b/projects/CMake/CMakeLists.txt @@ -7,31 +7,51 @@ get_filename_component(CATCH_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CATCH_DIR "${CATCH_DIR}" PATH) set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest) if(USE_CPP11) - ## We can't turn this on by default, since it breaks on travis - message(STATUS "Enabling C++11") - set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") + ## We can't turn this on by default, since it breaks on travis + message(STATUS "Enabling C++11") + set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") endif() # define the sources of the self test set(SOURCES - ${SELF_TEST_DIR}/ApproxTests.cpp - ${SELF_TEST_DIR}/BDDTests.cpp - ${SELF_TEST_DIR}/ClassTests.cpp - ${SELF_TEST_DIR}/ConditionTests.cpp - ${SELF_TEST_DIR}/ExceptionTests.cpp - ${SELF_TEST_DIR}/GeneratorTests.cpp - ${SELF_TEST_DIR}/MessageTests.cpp - ${SELF_TEST_DIR}/MiscTests.cpp - ${SELF_TEST_DIR}/PartTrackerTests.cpp - ${SELF_TEST_DIR}/TestMain.cpp - ${SELF_TEST_DIR}/TrickyTests.cpp - ${SELF_TEST_DIR}/VariadicMacrosTests.cpp - ${SELF_TEST_DIR}/EnumToString.cpp - ${SELF_TEST_DIR}/ToStringPair.cpp - ${SELF_TEST_DIR}/ToStringVector.cpp - ${SELF_TEST_DIR}/ToStringWhich.cpp - ${SELF_TEST_DIR}/ToStringTuple.cpp -) + ${SELF_TEST_DIR}/ApproxTests.cpp + ${SELF_TEST_DIR}/BDDTests.cpp + ${SELF_TEST_DIR}/ClassTests.cpp + ${SELF_TEST_DIR}/ConditionTests.cpp + ${SELF_TEST_DIR}/ExceptionTests.cpp + ${SELF_TEST_DIR}/GeneratorTests.cpp + ${SELF_TEST_DIR}/MessageTests.cpp + ${SELF_TEST_DIR}/MiscTests.cpp + ${SELF_TEST_DIR}/PartTrackerTests.cpp + ${SELF_TEST_DIR}/TestMain.cpp + ${SELF_TEST_DIR}/TrickyTests.cpp + ${SELF_TEST_DIR}/VariadicMacrosTests.cpp + ${SELF_TEST_DIR}/EnumToString.cpp + ${SELF_TEST_DIR}/ToStringPair.cpp + ${SELF_TEST_DIR}/ToStringVector.cpp + ${SELF_TEST_DIR}/ToStringWhich.cpp + ${SELF_TEST_DIR}/ToStringTuple.cpp + ${SELF_TEST_DIR}/CmdLineTests.cpp + ${SELF_TEST_DIR}/TagAliasTests.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_common.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_console_colour.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_debugger.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_capture.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_config.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_exception.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_generators.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_registry_hub.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_reporter.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_runner.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_testcase.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_message.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_option.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_ptr.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_stream.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_streambuf.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_test_spec.cpp + ${SELF_TEST_DIR}/SurrogateCpps/catch_xmlwriter.cpp + ) # configure the executable include_directories(${CATCH_DIR}/include) diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index ae45f32d..ee8d8072 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -830,6 +830,6 @@ with expansion: "first" == "second" =============================================================================== -test cases: 168 | 124 passed | 42 failed | 2 failed as expected -assertions: 920 | 824 passed | 78 failed | 18 failed as expected +test cases: 169 | 125 passed | 42 failed | 2 failed as expected +assertions: 921 | 825 passed | 78 failed | 18 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index e0a49030..3359a0fa 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -3920,9 +3920,9 @@ MiscTests.cpp: MiscTests.cpp:: PASSED: - REQUIRE( encode( "[\x01]" ) == "[]" ) + REQUIRE( encode( "[\x01]" ) == "[]" ) with expansion: - "[]" == "[]" + "[]" == "[]" ------------------------------------------------------------------------------- XmlEncode @@ -3933,9 +3933,9 @@ MiscTests.cpp: MiscTests.cpp:: PASSED: - REQUIRE( encode( "[\x7F]" ) == "[]" ) + REQUIRE( encode( "[\x7F]" ) == "[]" ) with expansion: - "[]" == "[]" + "[]" == "[]" ------------------------------------------------------------------------------- long long @@ -3962,6 +3962,17 @@ PASSED: with message: oops! +------------------------------------------------------------------------------- +# A test name that starts with a # +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: +with message: + yay + ------------------------------------------------------------------------------- Process can be configured on command line default - no arguments @@ -9104,6 +9115,6 @@ with expansion: 1 > 0 =============================================================================== -test cases: 168 | 123 passed | 43 failed | 2 failed as expected -assertions: 922 | 824 passed | 80 failed | 18 failed as expected +test cases: 169 | 124 passed | 43 failed | 2 failed as expected +assertions: 923 | 825 passed | 80 failed | 18 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index e3268bc6..3fd998f0 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,5 +1,6 @@ + - + @@ -500,6 +501,7 @@ MiscTests.cpp: + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index be30de52..ed730bbd 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -1,3 +1,4 @@ + @@ -4051,10 +4052,10 @@
- encode( "[\x01]" ) == "[&#x1]" + encode( "[\x01]" ) == "[&#x01;]" - "[&#x1]" == "[&#x1]" + "[&#x01;]" == "[&#x01;]" @@ -4062,10 +4063,10 @@
- encode( "[\x7F]" ) == "[&#x7F]" + encode( "[\x7F]" ) == "[&#x7F;]" - "[&#x7F]" == "[&#x7F]" + "[&#x7F;]" == "[&#x7F;]" @@ -4088,6 +4089,9 @@ + + +
@@ -9566,7 +9570,7 @@ there"
- + - + diff --git a/projects/SelfTest/CmdLineTests.cpp b/projects/SelfTest/CmdLineTests.cpp index 719c89b8..83b79fde 100644 --- a/projects/SelfTest/CmdLineTests.cpp +++ b/projects/SelfTest/CmdLineTests.cpp @@ -7,7 +7,7 @@ */ #include "catch.hpp" -#include "catch_test_spec_parser.hpp" +#include "internal/catch_test_spec_parser.hpp" #ifdef __clang__ # pragma clang diagnostic ignored "-Wc++98-compat" diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index 083e52eb..680826b7 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -406,27 +406,27 @@ TEST_CASE( "Tabs and newlines show in output", "[.][whitespace][failing]" ) { TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) { - const wchar_t * const s = L"wide load"; - std::string result = Catch::toString( s ); - CHECK( result == "\"wide load\"" ); + const wchar_t * const s = L"wide load"; + std::string result = Catch::toString( s ); + CHECK( result == "\"wide load\"" ); } TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) { - const wchar_t * s = L"wide load"; - std::string result = Catch::toString( s ); - CHECK( result == "\"wide load\"" ); + const wchar_t * s = L"wide load"; + std::string result = Catch::toString( s ); + CHECK( result == "\"wide load\"" ); } TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) { - wchar_t * const s = const_cast( L"wide load" ); - std::string result = Catch::toString( s ); - CHECK( result == "\"wide load\"" ); + wchar_t * const s = const_cast( L"wide load" ); + std::string result = Catch::toString( s ); + CHECK( result == "\"wide load\"" ); } TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) { - wchar_t * s = const_cast( L"wide load" ); - std::string result = Catch::toString( s ); - CHECK( result == "\"wide load\"" ); + wchar_t * s = const_cast( L"wide load" ); + std::string result = Catch::toString( s ); + CHECK( result == "\"wide load\"" ); } inline std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) { @@ -465,6 +465,10 @@ TEST_CASE( "XmlEncode" ) { } SECTION( "string with utf-8 characters (русский текст)" ) { REQUIRE( encode( "русский текст" ) == "русский текст" ); + REQUIRE( encode( "[\x01]" ) == "[]" ); + } + SECTION( "string with control char (x7F)" ) { + REQUIRE( encode( "[\x7F]" ) == "[]" ); } } @@ -486,3 +490,7 @@ TEST_CASE( "This test 'should' fail but doesn't", "[.][failing][!shouldfail]" ) { SUCCEED( "oops!" ); } + +TEST_CASE( "# A test name that starts with a #" ) { + SUCCEED( "yay" ); +} diff --git a/projects/SelfTest/SurrogateCpps/catch_common.cpp b/projects/SelfTest/SurrogateCpps/catch_common.cpp index 72f90bd6..65377f30 100644 --- a/projects/SelfTest/SurrogateCpps/catch_common.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_common.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_common.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_common.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_console_colour.cpp b/projects/SelfTest/SurrogateCpps/catch_console_colour.cpp index e7378c04..c28aa011 100644 --- a/projects/SelfTest/SurrogateCpps/catch_console_colour.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_console_colour.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_console_colour.hpp" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_console_colour.hpp" diff --git a/projects/SelfTest/SurrogateCpps/catch_debugger.cpp b/projects/SelfTest/SurrogateCpps/catch_debugger.cpp index 33f76ae6..04f4e071 100644 --- a/projects/SelfTest/SurrogateCpps/catch_debugger.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_debugger.cpp @@ -1,2 +1,2 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_debugger.h" +#include "internal/catch_debugger.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_capture.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_capture.cpp index 2d1c8f35..f46dae48 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_capture.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_capture.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_interfaces_capture.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_interfaces_capture.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_config.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_config.cpp index de0f18d3..46f80e86 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_config.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_config.cpp @@ -1,2 +1,2 @@ -#include "catch_suppress_warnings.h" -#include "catch_interfaces_config.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_interfaces_config.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_exception.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_exception.cpp index 183d87d9..f5ad4870 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_exception.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_exception.cpp @@ -1,2 +1,2 @@ -#include "catch_suppress_warnings.h" -#include "catch_interfaces_exception.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_interfaces_exception.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_generators.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_generators.cpp index 271b1bcc..2eda9812 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_generators.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_generators.cpp @@ -1 +1 @@ -#include "catch_interfaces_generators.h" +#include "internal/catch_interfaces_generators.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_registry_hub.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_registry_hub.cpp index ffece3b4..b399d862 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_registry_hub.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_registry_hub.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_interfaces_registry_hub.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_interfaces_registry_hub.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_reporter.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_reporter.cpp index 544f9d0f..f3c71585 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_reporter.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_reporter.cpp @@ -1,2 +1,2 @@ -#include "catch_suppress_warnings.h" -#include "catch_interfaces_reporter.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_interfaces_reporter.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_runner.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_runner.cpp index 401de262..800f32ab 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_runner.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_runner.cpp @@ -1 +1 @@ -#include "catch_interfaces_runner.h" +#include "internal/catch_interfaces_runner.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_testcase.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_testcase.cpp index 733dcb4e..0d6903cc 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_testcase.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_testcase.cpp @@ -1,2 +1,2 @@ -#include "catch_suppress_warnings.h" -#include "catch_interfaces_testcase.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_interfaces_testcase.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_message.cpp b/projects/SelfTest/SurrogateCpps/catch_message.cpp index ad2f5e77..40f4403c 100644 --- a/projects/SelfTest/SurrogateCpps/catch_message.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_message.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_message.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_message.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_option.cpp b/projects/SelfTest/SurrogateCpps/catch_option.cpp index 35e32829..a4ca37c2 100644 --- a/projects/SelfTest/SurrogateCpps/catch_option.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_option.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_option.hpp" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_option.hpp" diff --git a/projects/SelfTest/SurrogateCpps/catch_ptr.cpp b/projects/SelfTest/SurrogateCpps/catch_ptr.cpp index a25ad66d..90796ca1 100644 --- a/projects/SelfTest/SurrogateCpps/catch_ptr.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_ptr.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_ptr.hpp" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_ptr.hpp" diff --git a/projects/SelfTest/SurrogateCpps/catch_stream.cpp b/projects/SelfTest/SurrogateCpps/catch_stream.cpp index 7aaffa1e..a76d8413 100644 --- a/projects/SelfTest/SurrogateCpps/catch_stream.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_stream.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_stream.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_stream.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_streambuf.cpp b/projects/SelfTest/SurrogateCpps/catch_streambuf.cpp index 5c0043c2..a9222e4b 100644 --- a/projects/SelfTest/SurrogateCpps/catch_streambuf.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_streambuf.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_streambuf.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_streambuf.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_test_spec.cpp b/projects/SelfTest/SurrogateCpps/catch_test_spec.cpp index 46bf89f6..9993b80a 100644 --- a/projects/SelfTest/SurrogateCpps/catch_test_spec.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_test_spec.cpp @@ -1,3 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_test_spec.hpp" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_test_spec.hpp" diff --git a/projects/SelfTest/SurrogateCpps/catch_xmlwriter.cpp b/projects/SelfTest/SurrogateCpps/catch_xmlwriter.cpp index 15328efe..169d2d70 100644 --- a/projects/SelfTest/SurrogateCpps/catch_xmlwriter.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_xmlwriter.cpp @@ -1,4 +1,4 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header -#include "catch_suppress_warnings.h" -#include "catch_xmlwriter.hpp" -#include "catch_reenable_warnings.h" +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_xmlwriter.hpp" +#include "internal/catch_reenable_warnings.h" diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index c63f469f..16af2f67 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -25,7 +25,7 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" ) template void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) { Catch::Clara::CommandLine parser = Catch::makeCommandLineParser(); - parser.parseInto( size, argv, config ); + parser.parseInto( Catch::Clara::argsToVector( size, argv ), config ); } template diff --git a/single_include/catch.hpp b/single_include/catch.hpp index 2a7146a7..2e6fe8d3 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v1.4.0 - * Generated: 2016-03-15 07:23:12.623111 + * Catch v1.5.8 + * Generated: 2016-10-26 12:07:30.938259 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -106,8 +106,16 @@ // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 -#if defined(__cplusplus) && __cplusplus >= 201103L -# define CATCH_CPP11_OR_GREATER +#ifdef __cplusplus + +# if __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +# endif + +# if __cplusplus >= 201402L +# define CATCH_CPP14_OR_GREATER +# endif + #endif #ifdef __clang__ @@ -2065,7 +2073,7 @@ namespace Catch { __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + } while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ @@ -3215,10 +3223,11 @@ namespace Catch { bool matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match - for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { if( !(*it)->matches( testCase ) ) return false; - return true; + } + return true; } }; @@ -3450,7 +3459,7 @@ namespace Catch { }; class DebugOutStream : public IStream { - std::auto_ptr m_streamBuf; + CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; mutable std::ostream m_os; public: DebugOutStream(); @@ -3598,7 +3607,7 @@ namespace Catch { } ConfigData m_data; - std::auto_ptr m_stream; + CATCH_AUTO_PTR( IStream const ) m_stream; TestSpec m_testSpec; }; @@ -3618,7 +3627,7 @@ namespace Catch { #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { // #included from: ../external/clara.h -// Version 0.0.1.1 +// Version 0.0.2.4 // Only use header guard if we are not using an outer namespace #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) @@ -3934,6 +3943,10 @@ namespace Tbc { #include #include +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CLARA_PLATFORM_WINDOWS +#endif + // Use optional outer namespace #ifdef STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE @@ -3957,9 +3970,6 @@ namespace Clara { const unsigned int consoleWidth = 80; #endif - // Use this to try and stop compiler from warning about unreachable code - inline bool isTrue( bool value ) { return value; } - using namespace Tbc; inline bool startsWith( std::string const& str, std::string const& prefix ) { @@ -3995,14 +4005,6 @@ namespace Clara { else throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); } - inline void convertInto( bool _source, bool& _dest ) { - _dest = _source; - } - template - inline void convertInto( bool, T& ) { - if( isTrue( true ) ) - throw std::runtime_error( "Invalid conversion" ); - } template struct IArgFunction { @@ -4012,7 +4014,6 @@ namespace Clara { IArgFunction( IArgFunction const& ) = default; #endif virtual void set( ConfigT& config, std::string const& value ) const = 0; - virtual void setFlag( ConfigT& config ) const = 0; virtual bool takesArg() const = 0; virtual IArgFunction* clone() const = 0; }; @@ -4034,9 +4035,6 @@ namespace Clara { void set( ConfigT& config, std::string const& value ) const { functionObj->set( config, value ); } - void setFlag( ConfigT& config ) const { - functionObj->setFlag( config ); - } bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { @@ -4049,7 +4047,6 @@ namespace Clara { template struct NullBinder : IArgFunction{ virtual void set( C&, std::string const& ) const {} - virtual void setFlag( C& ) const {} virtual bool takesArg() const { return true; } virtual IArgFunction* clone() const { return new NullBinder( *this ); } }; @@ -4060,9 +4057,6 @@ namespace Clara { virtual void set( C& p, std::string const& stringValue ) const { convertInto( stringValue, p.*member ); } - virtual void setFlag( C& p ) const { - convertInto( true, p.*member ); - } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } M C::* member; @@ -4075,11 +4069,6 @@ namespace Clara { convertInto( stringValue, value ); (p.*member)( value ); } - virtual void setFlag( C& p ) const { - typename RemoveConstRef::type value; - convertInto( true, value ); - (p.*member)( value ); - } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } void (C::*member)( M ); @@ -4093,9 +4082,6 @@ namespace Clara { if( value ) (p.*member)(); } - virtual void setFlag( C& p ) const { - (p.*member)(); - } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } void (C::*member)(); @@ -4110,9 +4096,6 @@ namespace Clara { if( value ) function( obj ); } - virtual void setFlag( C& p ) const { - function( p ); - } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } void (*function)( C& ); @@ -4126,11 +4109,6 @@ namespace Clara { convertInto( stringValue, value ); function( obj, value ); } - virtual void setFlag( C& obj ) const { - typename RemoveConstRef::type value; - convertInto( true, value ); - function( obj, value ); - } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } void (*function)( C&, T ); @@ -4138,8 +4116,20 @@ namespace Clara { } // namespace Detail - struct Parser { - Parser() : separators( " \t=:" ) {} + inline std::vector argsToVector( int argc, char const* const* const argv ) { + std::vector args( static_cast( argc ) ); + for( std::size_t i = 0; i < static_cast( argc ); ++i ) + args[i] = argv[i]; + + return args; + } + + class Parser { + enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; + Mode mode; + std::size_t from; + bool inQuotes; + public: struct Token { enum Type { Positional, ShortOpt, LongOpt }; @@ -4148,38 +4138,75 @@ namespace Clara { std::string data; }; - void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + Parser() : mode( None ), from( 0 ), inQuotes( false ){} + + void parseIntoTokens( std::vector const& args, std::vector& tokens ) { const std::string doubleDash = "--"; - for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) - parseIntoTokens( argv[i] , tokens); + for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) + parseIntoTokens( args[i], tokens); } - void parseIntoTokens( std::string arg, std::vector& tokens ) const { - while( !arg.empty() ) { - Parser::Token token( Parser::Token::Positional, arg ); - arg = ""; - if( token.data[0] == '-' ) { - if( token.data.size() > 1 && token.data[1] == '-' ) { - token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); - } - else { - token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); - if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { - arg = "-" + token.data.substr( 1 ); - token.data = token.data.substr( 0, 1 ); - } - } - } - if( token.type != Parser::Token::Positional ) { - std::size_t pos = token.data.find_first_of( separators ); - if( pos != std::string::npos ) { - arg = token.data.substr( pos+1 ); - token.data = token.data.substr( 0, pos ); - } - } - tokens.push_back( token ); + + void parseIntoTokens( std::string const& arg, std::vector& tokens ) { + for( std::size_t i = 0; i <= arg.size(); ++i ) { + char c = arg[i]; + if( c == '"' ) + inQuotes = !inQuotes; + mode = handleMode( i, c, arg, tokens ); } } - std::string separators; + Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + switch( mode ) { + case None: return handleNone( i, c ); + case MaybeShortOpt: return handleMaybeShortOpt( i, c ); + case ShortOpt: + case LongOpt: + case SlashOpt: return handleOpt( i, c, arg, tokens ); + case Positional: return handlePositional( i, c, arg, tokens ); + default: throw std::logic_error( "Unknown mode" ); + } + } + + Mode handleNone( std::size_t i, char c ) { + if( inQuotes ) { + from = i; + return Positional; + } + switch( c ) { + case '-': return MaybeShortOpt; +#ifdef CLARA_PLATFORM_WINDOWS + case '/': from = i+1; return SlashOpt; +#endif + default: from = i; return Positional; + } + } + Mode handleMaybeShortOpt( std::size_t i, char c ) { + switch( c ) { + case '-': from = i+1; return LongOpt; + default: from = i; return ShortOpt; + } + } + Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) + return mode; + + std::string optName = arg.substr( from, i-from ); + if( mode == ShortOpt ) + for( std::size_t j = 0; j < optName.size(); ++j ) + tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); + else if( mode == SlashOpt && optName.size() == 1 ) + tokens.push_back( Token( Token::ShortOpt, optName ) ); + else + tokens.push_back( Token( Token::LongOpt, optName ) ); + return None; + } + Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) + return mode; + + std::string data = arg.substr( from, i-from ); + tokens.push_back( Token( Token::Positional, data ) ); + return None; + } }; template @@ -4482,21 +4509,21 @@ namespace Clara { return oss.str(); } - ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT parse( std::vector const& args ) const { ConfigT config; - parseInto( argc, argv, config ); + parseInto( args, config ); return config; } - std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { - std::string processName = argv[0]; + std::vector parseInto( std::vector const& args, ConfigT& config ) const { + std::string processName = args[0]; std::size_t lastSlash = processName.find_last_of( "/\\" ); if( lastSlash != std::string::npos ) processName = processName.substr( lastSlash+1 ); m_boundProcessName.set( config, processName ); std::vector tokens; Parser parser; - parser.parseIntoTokens( argc, argv, tokens ); + parser.parseIntoTokens( args, tokens ); return populate( tokens, config ); } @@ -4527,7 +4554,7 @@ namespace Clara { arg.boundField.set( config, tokens[++i].data ); } else { - arg.boundField.setFlag( config ); + arg.boundField.set( config, "true" ); } break; } @@ -4693,8 +4720,11 @@ namespace Catch { std::string line; while( std::getline( f, line ) ) { line = trim(line); - if( !line.empty() && !startsWith( line, "#" ) ) - addTestOrTags( config, "\"" + line + "\"," ); + if( !line.empty() && !startsWith( line, "#" ) ) { + if( !startsWith( line, "\"" ) ) + line = "\"" + line + "\""; + addTestOrTags( config, line + "," ); + } } } @@ -5235,6 +5265,8 @@ namespace Catch bool aborting; }; + class MultipleReporters; + struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); @@ -5262,6 +5294,8 @@ namespace Catch virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } }; struct IReporterFactory : IShared { @@ -5338,7 +5372,10 @@ namespace Catch { ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Catch::cout() << testCaseInfo.name << std::endl; + if( startsWith( testCaseInfo.name, "#" ) ) + Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl; + else + Catch::cout() << testCaseInfo.name << std::endl; } return matchedTests; } @@ -5479,6 +5516,10 @@ namespace TestCaseTracking { virtual void addChild( Ptr const& child ) = 0; virtual ITracker* findChild( std::string const& name ) = 0; virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isIndexTracker() const = 0; }; class TrackerContext { @@ -5603,6 +5644,10 @@ namespace TestCaseTracking { m_parent->openChild(); } } + + virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } + virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } + void open() { m_runState = Executing; moveToThis(); @@ -5666,13 +5711,16 @@ namespace TestCaseTracking { {} virtual ~SectionTracker(); + virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { SectionTracker* section = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( name ) ) { - section = dynamic_cast( childTracker ); - assert( section ); + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = static_cast( childTracker ); } else { section = new SectionTracker( name, ctx, ¤tTracker ); @@ -5697,13 +5745,16 @@ namespace TestCaseTracking { {} virtual ~IndexTracker(); + virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { IndexTracker* tracker = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( name ) ) { - tracker = dynamic_cast( childTracker ); - assert( tracker ); + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = static_cast( childTracker ); } else { tracker = new IndexTracker( name, ctx, ¤tTracker, size ); @@ -6306,10 +6357,10 @@ namespace Catch { Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } - int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); - m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); if( m_configData.showHelp ) showHelp( m_configData.processName ); m_config.reset(); @@ -6333,16 +6384,13 @@ namespace Catch { m_config.reset(); } - int run( int argc, char const* argv[] ) { + int run( int argc, char const* const* const argv ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) returnCode = run(); return returnCode; } - int run( int argc, char* argv[] ) { - return run( argc, const_cast( argv ) ); - } int run() { if( m_configData.showHelp ) @@ -6406,13 +6454,31 @@ namespace Catch { #include #include +#ifdef CATCH_CPP14_OR_GREATER +#include +#endif + namespace Catch { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i + static void shuffle( V& vector ) { + RandomNumberGenerator rng; +#ifdef CATCH_CPP14_OR_GREATER + std::shuffle( vector.begin(), vector.end(), rng ); +#else + std::random_shuffle( vector.begin(), vector.end(), rng ); +#endif + } }; inline std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { @@ -6421,14 +6487,12 @@ namespace Catch { switch( config.runOrder() ) { case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end(), LexSort() ); + std::sort( sorted.begin(), sorted.end() ); break; case RunTests::InRandomOrder: { seedRng( config ); - - RandomNumberGenerator rng; - std::random_shuffle( sorted.begin(), sorted.end(), rng ); + RandomNumberGenerator::shuffle( sorted ); } break; case RunTests::InDeclarationOrder: @@ -6447,13 +6511,15 @@ namespace Catch { it != itEnd; ++it ) { std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); - if( !prev.second ){ - Catch::cerr() - << Colour( Colour::Red ) - << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; - exit(1); + if( !prev.second ) { + std::ostringstream ss; + + ss << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + + throw std::runtime_error(ss.str()); } } } @@ -7512,7 +7578,7 @@ namespace Catch { return os; } - Version libraryVersion( 1, 4, 0, "", 0 ); + Version libraryVersion( 1, 5, 8, "", 0 ); } @@ -7743,8 +7809,11 @@ namespace Catch { bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } + char toLowerCh(char c) { + return static_cast( ::tolower( c ) ); + } void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } std::string toLower( std::string const& s ) { std::string lc = s; @@ -8491,13 +8560,18 @@ public: // IStreamingReporter ++it ) (*it)->skipTest( testInfo ); } + + virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { + return this; + } + }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { Ptr resultingReporter; if( existingReporter ) { - MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + MultipleReporters* multi = existingReporter->tryAsMulti(); if( !multi ) { multi = new MultipleReporters; resultingReporter = Ptr( multi ); @@ -8677,7 +8751,7 @@ namespace Catch { virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back( assertionStats ); @@ -8887,9 +8961,10 @@ namespace Catch { break; default: - // Escape control chars - based on contribution by @espenalb in PR #465 + // Escape control chars - based on contribution by @espenalb in PR #465 and + // by @mrpi PR #588 if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) - os << "&#x" << std::uppercase << std::hex << static_cast( c ); + os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast( c ) << ';'; else os << c; } @@ -8944,13 +9019,20 @@ namespace Catch { : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &Catch::cout() ) - {} + { + // We encode control characters, which requires + // XML 1.1 + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + *m_os << "\n"; + } XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &os ) - {} + { + *m_os << "\n"; + } ~XmlWriter() { while( !m_tags.empty() ) @@ -9117,7 +9199,7 @@ namespace Catch { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); @@ -9179,7 +9261,7 @@ namespace Catch { .writeText( assertionResult.getMessage() ); break; case ResultWas::FatalErrorCondition: - m_xml.scopedElement( "Fatal Error Condition" ) + m_xml.scopedElement( "FatalErrorCondition" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() );