merged conflicts

This commit is contained in:
Vladimir Zelenkin 2016-11-23 12:55:08 +03:00
commit 517e31799f
48 changed files with 539 additions and 329 deletions

View File

@ -64,7 +64,7 @@ matrix:
compiler: clang compiler: clang
addons: &clang38 addons: &clang38
apt: apt:
sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test'] sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test']
packages: ['clang-3.8'] packages: ['clang-3.8']
env: COMPILER='ccache clang++-3.8' BUILD_TYPE='Release' env: COMPILER='ccache clang++-3.8' BUILD_TYPE='Release'
@ -119,23 +119,22 @@ matrix:
# 3/ OSX Clang Builds # 3/ OSX Clang Builds
- os: osx - os: osx
osx_image: xcode6.4 osx_image: xcode7
compiler: clang compiler: clang
env: COMPILER='ccache clang++' BUILD_TYPE='Debug' env: COMPILER='ccache clang++' BUILD_TYPE='Debug'
- os: osx - os: osx
osx_image: xcode6.4 osx_image: xcode7
compiler: clang compiler: clang
env: COMPILER='ccache clang++' BUILD_TYPE='Release' env: COMPILER='ccache clang++' BUILD_TYPE='Release'
- os: osx - os: osx
osx_image: xcode7 osx_image: xcode8
compiler: clang compiler: clang
env: COMPILER='ccache clang++' BUILD_TYPE='Debug' env: COMPILER='ccache clang++' BUILD_TYPE='Debug'
- os: osx - os: osx
osx_image: xcode7 osx_image: xcode8
compiler: clang compiler: clang
env: COMPILER='ccache clang++' BUILD_TYPE='Release' 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 mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
export PATH=${DEPS_DIR}/cmake/bin:${PATH} export PATH=${DEPS_DIR}/cmake/bin:${PATH}
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
brew install cmake ccache which cmake || brew install cmake
which ccache || brew install ccache
fi fi
before_script: before_script:

View File

@ -1,6 +1,6 @@
![catch logo](catch-logo-small.png) ![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) Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch)

View File

@ -1,6 +1,6 @@
# Getting Catch # 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. 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.

View File

@ -131,10 +131,10 @@ namespace Catch {
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; 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 { try {
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); 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 ) if( m_configData.showHelp )
showHelp( m_configData.processName ); showHelp( m_configData.processName );
m_config.reset(); m_config.reset();
@ -158,16 +158,13 @@ namespace Catch {
m_config.reset(); m_config.reset();
} }
int run( int argc, char const* argv[] ) { int run( int argc, char const* const* const argv ) {
int returnCode = applyCommandLine( argc, argv ); int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 ) if( returnCode == 0 )
returnCode = run(); returnCode = run();
return returnCode; return returnCode;
} }
int run( int argc, char* argv[] ) {
return run( argc, const_cast<char const**>( argv ) );
}
int run() { int run() {
if( m_configData.showHelp ) if( m_configData.showHelp )

View File

@ -6,7 +6,7 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) * 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 // Only use header guard if we are not using an outer namespace
#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
@ -343,6 +343,11 @@ namespace Tbc {
#include <stdexcept> #include <stdexcept>
#include <memory> #include <memory>
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define CLARA_PLATFORM_WINDOWS
#endif
// Use optional outer namespace // Use optional outer namespace
#ifdef STITCH_CLARA_OPEN_NAMESPACE #ifdef STITCH_CLARA_OPEN_NAMESPACE
STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
@ -366,9 +371,6 @@ namespace Clara {
const unsigned int consoleWidth = 80; const unsigned int consoleWidth = 80;
#endif #endif
// Use this to try and stop compiler from warning about unreachable code
inline bool isTrue( bool value ) { return value; }
using namespace Tbc; using namespace Tbc;
inline bool startsWith( std::string const& str, std::string const& prefix ) { inline bool startsWith( std::string const& str, std::string const& prefix ) {
@ -404,14 +406,7 @@ namespace Clara {
else else
throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
} }
inline void convertInto( bool _source, bool& _dest ) {
_dest = _source;
}
template<typename T>
inline void convertInto( bool, T& ) {
if( isTrue( true ) )
throw std::runtime_error( "Invalid conversion" );
}
template<typename ConfigT> template<typename ConfigT>
struct IArgFunction { struct IArgFunction {
@ -421,7 +416,6 @@ namespace Clara {
IArgFunction( IArgFunction const& ) = default; IArgFunction( IArgFunction const& ) = default;
#endif #endif
virtual void set( ConfigT& config, std::string const& value ) const = 0; virtual void set( ConfigT& config, std::string const& value ) const = 0;
virtual void setFlag( ConfigT& config ) const = 0;
virtual bool takesArg() const = 0; virtual bool takesArg() const = 0;
virtual IArgFunction* clone() const = 0; virtual IArgFunction* clone() const = 0;
}; };
@ -443,9 +437,6 @@ namespace Clara {
void set( ConfigT& config, std::string const& value ) const { void set( ConfigT& config, std::string const& value ) const {
functionObj->set( config, value ); functionObj->set( config, value );
} }
void setFlag( ConfigT& config ) const {
functionObj->setFlag( config );
}
bool takesArg() const { return functionObj->takesArg(); } bool takesArg() const { return functionObj->takesArg(); }
bool isSet() const { bool isSet() const {
@ -459,7 +450,6 @@ namespace Clara {
template<typename C> template<typename C>
struct NullBinder : IArgFunction<C>{ struct NullBinder : IArgFunction<C>{
virtual void set( C&, std::string const& ) const {} virtual void set( C&, std::string const& ) const {}
virtual void setFlag( C& ) const {}
virtual bool takesArg() const { return true; } virtual bool takesArg() const { return true; }
virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
}; };
@ -470,9 +460,6 @@ namespace Clara {
virtual void set( C& p, std::string const& stringValue ) const { virtual void set( C& p, std::string const& stringValue ) const {
convertInto( stringValue, p.*member ); convertInto( stringValue, p.*member );
} }
virtual void setFlag( C& p ) const {
convertInto( true, p.*member );
}
virtual bool takesArg() const { return !IsBool<M>::value; } virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
M C::* member; M C::* member;
@ -485,11 +472,6 @@ namespace Clara {
convertInto( stringValue, value ); convertInto( stringValue, value );
(p.*member)( value ); (p.*member)( value );
} }
virtual void setFlag( C& p ) const {
typename RemoveConstRef<M>::type value;
convertInto( true, value );
(p.*member)( value );
}
virtual bool takesArg() const { return !IsBool<M>::value; } virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
void (C::*member)( M ); void (C::*member)( M );
@ -503,9 +485,6 @@ namespace Clara {
if( value ) if( value )
(p.*member)(); (p.*member)();
} }
virtual void setFlag( C& p ) const {
(p.*member)();
}
virtual bool takesArg() const { return false; } virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
void (C::*member)(); void (C::*member)();
@ -520,9 +499,6 @@ namespace Clara {
if( value ) if( value )
function( obj ); function( obj );
} }
virtual void setFlag( C& p ) const {
function( p );
}
virtual bool takesArg() const { return false; } virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
void (*function)( C& ); void (*function)( C& );
@ -536,11 +512,6 @@ namespace Clara {
convertInto( stringValue, value ); convertInto( stringValue, value );
function( obj, value ); function( obj, value );
} }
virtual void setFlag( C& obj ) const {
typename RemoveConstRef<T>::type value;
convertInto( true, value );
function( obj, value );
}
virtual bool takesArg() const { return !IsBool<T>::value; } virtual bool takesArg() const { return !IsBool<T>::value; }
virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
void (*function)( C&, T ); void (*function)( C&, T );
@ -548,8 +519,20 @@ namespace Clara {
} // namespace Detail } // namespace Detail
struct Parser { inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
Parser() : separators( " \t=:" ) {} std::vector<std::string> args( static_cast<std::size_t>( argc ) );
for( std::size_t i = 0; i < static_cast<std::size_t>( 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 { struct Token {
enum Type { Positional, ShortOpt, LongOpt }; enum Type { Positional, ShortOpt, LongOpt };
@ -558,38 +541,75 @@ namespace Clara {
std::string data; std::string data;
}; };
void parseIntoTokens( int argc, char const* const argv[], std::vector<Parser::Token>& tokens ) const { Parser() : mode( None ), from( 0 ), inQuotes( false ){}
void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
const std::string doubleDash = "--"; const std::string doubleDash = "--";
for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
parseIntoTokens( argv[i] , tokens); parseIntoTokens( args[i], tokens);
} }
void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
while( !arg.empty() ) { void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
Parser::Token token( Parser::Token::Positional, arg ); for( std::size_t i = 0; i <= arg.size(); ++i ) {
arg = ""; char c = arg[i];
if( token.data[0] == '-' ) { if( c == '"' )
if( token.data.size() > 1 && token.data[1] == '-' ) { inQuotes = !inQuotes;
token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); mode = handleMode( i, c, arg, tokens );
}
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 );
} }
} }
std::string separators; Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& 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<Token>& 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<Token>& 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<typename ConfigT> template<typename ConfigT>
@ -894,21 +914,21 @@ namespace Clara {
return oss.str(); return oss.str();
} }
ConfigT parse( int argc, char const* const argv[] ) const { ConfigT parse( std::vector<std::string> const& args ) const {
ConfigT config; ConfigT config;
parseInto( argc, argv, config ); parseInto( args, config );
return config; return config;
} }
std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const { std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
std::string processName = argv[0]; std::string processName = args[0];
std::size_t lastSlash = processName.find_last_of( "/\\" ); std::size_t lastSlash = processName.find_last_of( "/\\" );
if( lastSlash != std::string::npos ) if( lastSlash != std::string::npos )
processName = processName.substr( lastSlash+1 ); processName = processName.substr( lastSlash+1 );
m_boundProcessName.set( config, processName ); m_boundProcessName.set( config, processName );
std::vector<Parser::Token> tokens; std::vector<Parser::Token> tokens;
Parser parser; Parser parser;
parser.parseIntoTokens( argc, argv, tokens ); parser.parseIntoTokens( args, tokens );
return populate( tokens, config ); return populate( tokens, config );
} }
@ -939,7 +959,7 @@ namespace Clara {
arg.boundField.set( config, tokens[++i].data ); arg.boundField.set( config, tokens[++i].data );
} }
else { else {
arg.boundField.setFlag( config ); arg.boundField.set( config, "true" );
} }
break; break;
} }

View File

@ -40,7 +40,7 @@
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
} \ } \
INTERNAL_CATCH_REACT( __catchResult ) \ INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::isTrue( false && static_cast<bool>(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 ) \ #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \

View File

@ -85,8 +85,11 @@ namespace Catch {
std::string line; std::string line;
while( std::getline( f, line ) ) { while( std::getline( f, line ) ) {
line = trim(line); line = trim(line);
if( !line.empty() && !startsWith( line, "#" ) ) if( !line.empty() && !startsWith( line, "#" ) ) {
addTestOrTags( config, "\"" + line + "\"," ); if( !startsWith( line, "\"" ) )
line = "\"" + line + "\"";
addTestOrTags( config, line + "," );
}
} }
} }

View File

@ -21,8 +21,11 @@ namespace Catch {
bool contains( std::string const& s, std::string const& infix ) { bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos; return s.find( infix ) != std::string::npos;
} }
char toLowerCh(char c) {
return static_cast<char>( ::tolower( c ) );
}
void toLowerInPlace( std::string& s ) { 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 toLower( std::string const& s ) {
std::string lc = s; std::string lc = s;

View File

@ -36,8 +36,16 @@
// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
#if defined(__cplusplus) && __cplusplus >= 201103L #ifdef __cplusplus
# define CATCH_CPP11_OR_GREATER
# if __cplusplus >= 201103L
# define CATCH_CPP11_OR_GREATER
# endif
# if __cplusplus >= 201402L
# define CATCH_CPP14_OR_GREATER
# endif
#endif #endif
#ifdef __clang__ #ifdef __clang__

View File

@ -151,7 +151,7 @@ namespace Catch {
} }
ConfigData m_data; ConfigData m_data;
std::auto_ptr<IStream const> m_stream; CATCH_AUTO_PTR( IStream const ) m_stream;
TestSpec m_testSpec; TestSpec m_testSpec;
}; };

View File

@ -219,6 +219,7 @@ namespace Catch
bool aborting; bool aborting;
}; };
class MultipleReporters;
struct IStreamingReporter : IShared { struct IStreamingReporter : IShared {
virtual ~IStreamingReporter(); virtual ~IStreamingReporter();
@ -247,6 +248,8 @@ namespace Catch
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
virtual void skipTest( TestCaseInfo const& testInfo ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
}; };

View File

@ -68,7 +68,10 @@ namespace Catch {
++it ) { ++it ) {
matchedTests++; matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); 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; return matchedTests;
} }

View File

@ -49,7 +49,7 @@ namespace Catch {
class DebugOutStream : public IStream { class DebugOutStream : public IStream {
std::auto_ptr<StreamBufBase> m_streamBuf; CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
mutable std::ostream m_os; mutable std::ostream m_os;
public: public:
DebugOutStream(); DebugOutStream();

View File

@ -19,13 +19,31 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#ifdef CATCH_CPP14_OR_GREATER
#include <random>
#endif
namespace Catch { namespace Catch {
struct LexSort {
bool operator() (TestCase i,TestCase j) const { return (i<j);}
};
struct RandomNumberGenerator { struct RandomNumberGenerator {
int operator()( int n ) const { return std::rand() % n; } typedef std::ptrdiff_t result_type;
result_type operator()( result_type n ) const { return std::rand() % n; }
#ifdef CATCH_CPP14_OR_GREATER
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return 1000000; }
result_type operator()() const { return std::rand() % max(); }
#endif
template<typename V>
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<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
@ -34,14 +52,12 @@ namespace Catch {
switch( config.runOrder() ) { switch( config.runOrder() ) {
case RunTests::InLexicographicalOrder: case RunTests::InLexicographicalOrder:
std::sort( sorted.begin(), sorted.end(), LexSort() ); std::sort( sorted.begin(), sorted.end() );
break; break;
case RunTests::InRandomOrder: case RunTests::InRandomOrder:
{ {
seedRng( config ); seedRng( config );
RandomNumberGenerator::shuffle( sorted );
RandomNumberGenerator rng;
std::random_shuffle( sorted.begin(), sorted.end(), rng );
} }
break; break;
case RunTests::InDeclarationOrder: case RunTests::InDeclarationOrder:
@ -60,13 +76,15 @@ namespace Catch {
it != itEnd; it != itEnd;
++it ) { ++it ) {
std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it ); std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
if( !prev.second ){ if( !prev.second ) {
Catch::cerr() std::ostringstream ss;
<< Colour( Colour::Red )
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" ss << Colour( Colour::Red )
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
exit(1); << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
throw std::runtime_error(ss.str());
} }
} }
} }

View File

@ -41,6 +41,10 @@ namespace TestCaseTracking {
virtual void addChild( Ptr<ITracker> const& child ) = 0; virtual void addChild( Ptr<ITracker> const& child ) = 0;
virtual ITracker* findChild( std::string const& name ) = 0; virtual ITracker* findChild( std::string const& name ) = 0;
virtual void openChild() = 0; virtual void openChild() = 0;
// Debug/ checking
virtual bool isSectionTracker() const = 0;
virtual bool isIndexTracker() const = 0;
}; };
class TrackerContext { class TrackerContext {
@ -167,6 +171,10 @@ namespace TestCaseTracking {
m_parent->openChild(); m_parent->openChild();
} }
} }
virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
void open() { void open() {
m_runState = Executing; m_runState = Executing;
moveToThis(); moveToThis();
@ -230,13 +238,16 @@ namespace TestCaseTracking {
{} {}
virtual ~SectionTracker(); virtual ~SectionTracker();
virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
SectionTracker* section = CATCH_NULL; SectionTracker* section = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker(); ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) { if( ITracker* childTracker = currentTracker.findChild( name ) ) {
section = dynamic_cast<SectionTracker*>( childTracker ); assert( childTracker );
assert( section ); assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
} }
else { else {
section = new SectionTracker( name, ctx, &currentTracker ); section = new SectionTracker( name, ctx, &currentTracker );
@ -261,13 +272,16 @@ namespace TestCaseTracking {
{} {}
virtual ~IndexTracker(); virtual ~IndexTracker();
virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
IndexTracker* tracker = CATCH_NULL; IndexTracker* tracker = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker(); ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) { if( ITracker* childTracker = currentTracker.findChild( name ) ) {
tracker = dynamic_cast<IndexTracker*>( childTracker ); assert( childTracker );
assert( tracker ); assert( childTracker->isIndexTracker() );
tracker = static_cast<IndexTracker*>( childTracker );
} }
else { else {
tracker = new IndexTracker( name, ctx, &currentTracker, size ); tracker = new IndexTracker( name, ctx, &currentTracker, size );

View File

@ -64,10 +64,11 @@ namespace Catch {
bool matches( TestCaseInfo const& testCase ) const { bool matches( TestCaseInfo const& testCase ) const {
// All patterns in a filter must match for the filter to be a match // All patterns in a filter must match for the filter to be a match
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
if( !(*it)->matches( testCase ) ) if( !(*it)->matches( testCase ) )
return false; return false;
return true; }
return true;
} }
}; };

View File

@ -37,7 +37,7 @@ namespace Catch {
return os; return os;
} }
Version libraryVersion( 1, 4, 0, "", 0 ); Version libraryVersion( 1, 5, 8, "", 0 );
} }

View File

@ -55,9 +55,10 @@ namespace Catch {
break; break;
default: 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' ) if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
os << "&#x" << std::uppercase << std::hex << static_cast<int>( c ) << ";"; os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
else else
os << c; os << c;
} }
@ -112,13 +113,20 @@ namespace Catch {
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &Catch::cout() ) 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 << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
XmlWriter( std::ostream& os ) XmlWriter( std::ostream& os )
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &os ) m_os( &os )
{} {
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
~XmlWriter() { ~XmlWriter() {
while( !m_tags.empty() ) while( !m_tags.empty() )

View File

@ -166,7 +166,7 @@ namespace Catch {
virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} 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() ); assert( !m_sectionStack.empty() );
SectionNode& sectionNode = *m_sectionStack.back(); SectionNode& sectionNode = *m_sectionStack.back();
sectionNode.assertions.push_back( assertionStats ); sectionNode.assertions.push_back( assertionStats );

View File

@ -118,13 +118,18 @@ public: // IStreamingReporter
++it ) ++it )
(*it)->skipTest( testInfo ); (*it)->skipTest( testInfo );
} }
virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
return this;
}
}; };
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) { Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
Ptr<IStreamingReporter> resultingReporter; Ptr<IStreamingReporter> resultingReporter;
if( existingReporter ) { if( existingReporter ) {
MultipleReporters* multi = dynamic_cast<MultipleReporters*>( existingReporter.get() ); MultipleReporters* multi = existingReporter->tryAsMulti();
if( !multi ) { if( !multi ) {
multi = new MultipleReporters; multi = new MultipleReporters;
resultingReporter = Ptr<IStreamingReporter>( multi ); resultingReporter = Ptr<IStreamingReporter>( multi );

View File

@ -53,7 +53,7 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting(testInfo); 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 ) if ( m_config->showDurations() == ShowDurations::Always )
m_testCaseTimer.start(); m_testCaseTimer.start();
@ -115,7 +115,7 @@ namespace Catch {
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );
break; break;
case ResultWas::FatalErrorCondition: case ResultWas::FatalErrorCondition:
m_xml.scopedElement( "Fatal Error Condition" ) m_xml.scopedElement( "FatalErrorCondition" )
.writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeAttribute( "line", assertionResult.getSourceInfo().line )
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );

View File

@ -7,31 +7,51 @@ get_filename_component(CATCH_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
get_filename_component(CATCH_DIR "${CATCH_DIR}" PATH) get_filename_component(CATCH_DIR "${CATCH_DIR}" PATH)
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest) set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
if(USE_CPP11) if(USE_CPP11)
## We can't turn this on by default, since it breaks on travis ## We can't turn this on by default, since it breaks on travis
message(STATUS "Enabling C++11") message(STATUS "Enabling C++11")
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
endif() endif()
# define the sources of the self test # define the sources of the self test
set(SOURCES set(SOURCES
${SELF_TEST_DIR}/ApproxTests.cpp ${SELF_TEST_DIR}/ApproxTests.cpp
${SELF_TEST_DIR}/BDDTests.cpp ${SELF_TEST_DIR}/BDDTests.cpp
${SELF_TEST_DIR}/ClassTests.cpp ${SELF_TEST_DIR}/ClassTests.cpp
${SELF_TEST_DIR}/ConditionTests.cpp ${SELF_TEST_DIR}/ConditionTests.cpp
${SELF_TEST_DIR}/ExceptionTests.cpp ${SELF_TEST_DIR}/ExceptionTests.cpp
${SELF_TEST_DIR}/GeneratorTests.cpp ${SELF_TEST_DIR}/GeneratorTests.cpp
${SELF_TEST_DIR}/MessageTests.cpp ${SELF_TEST_DIR}/MessageTests.cpp
${SELF_TEST_DIR}/MiscTests.cpp ${SELF_TEST_DIR}/MiscTests.cpp
${SELF_TEST_DIR}/PartTrackerTests.cpp ${SELF_TEST_DIR}/PartTrackerTests.cpp
${SELF_TEST_DIR}/TestMain.cpp ${SELF_TEST_DIR}/TestMain.cpp
${SELF_TEST_DIR}/TrickyTests.cpp ${SELF_TEST_DIR}/TrickyTests.cpp
${SELF_TEST_DIR}/VariadicMacrosTests.cpp ${SELF_TEST_DIR}/VariadicMacrosTests.cpp
${SELF_TEST_DIR}/EnumToString.cpp ${SELF_TEST_DIR}/EnumToString.cpp
${SELF_TEST_DIR}/ToStringPair.cpp ${SELF_TEST_DIR}/ToStringPair.cpp
${SELF_TEST_DIR}/ToStringVector.cpp ${SELF_TEST_DIR}/ToStringVector.cpp
${SELF_TEST_DIR}/ToStringWhich.cpp ${SELF_TEST_DIR}/ToStringWhich.cpp
${SELF_TEST_DIR}/ToStringTuple.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 # configure the executable
include_directories(${CATCH_DIR}/include) include_directories(${CATCH_DIR}/include)

View File

@ -830,6 +830,6 @@ with expansion:
"first" == "second" "first" == "second"
=============================================================================== ===============================================================================
test cases: 168 | 124 passed | 42 failed | 2 failed as expected test cases: 169 | 125 passed | 42 failed | 2 failed as expected
assertions: 920 | 824 passed | 78 failed | 18 failed as expected assertions: 921 | 825 passed | 78 failed | 18 failed as expected

View File

@ -3920,9 +3920,9 @@ MiscTests.cpp:<line number>
MiscTests.cpp:<line number>: MiscTests.cpp:<line number>:
PASSED: PASSED:
REQUIRE( encode( "[\x01]" ) == "[&#x1]" ) REQUIRE( encode( "[\x01]" ) == "[&#x01;]" )
with expansion: with expansion:
"[&#x1]" == "[&#x1]" "[&#x01;]" == "[&#x01;]"
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
XmlEncode XmlEncode
@ -3933,9 +3933,9 @@ MiscTests.cpp:<line number>
MiscTests.cpp:<line number>: MiscTests.cpp:<line number>:
PASSED: PASSED:
REQUIRE( encode( "[\x7F]" ) == "[&#x7F]" ) REQUIRE( encode( "[\x7F]" ) == "[&#x7F;]" )
with expansion: with expansion:
"[&#x7F]" == "[&#x7F]" "[&#x7F;]" == "[&#x7F;]"
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
long long long long
@ -3962,6 +3962,17 @@ PASSED:
with message: with message:
oops! oops!
-------------------------------------------------------------------------------
# A test name that starts with a #
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
yay
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Process can be configured on command line Process can be configured on command line
default - no arguments default - no arguments
@ -9104,6 +9115,6 @@ with expansion:
1 > 0 1 > 0
=============================================================================== ===============================================================================
test cases: 168 | 123 passed | 43 failed | 2 failed as expected test cases: 169 | 124 passed | 43 failed | 2 failed as expected
assertions: 922 | 824 passed | 80 failed | 18 failed as expected assertions: 923 | 825 passed | 80 failed | 18 failed as expected

View File

@ -1,5 +1,6 @@
<?xml version="1.1" encoding="UTF-8"?>
<testsuites> <testsuites>
<testsuite name="CatchSelfTest" errors="13" failures="68" tests="923" hostname="tbd" time="{duration}" timestamp="tbd"> <testsuite name="CatchSelfTest" errors="13" failures="68" tests="924" hostname="tbd" time="{duration}" timestamp="tbd">
<testcase classname="global" name="toString(enum)" time="{duration}"/> <testcase classname="global" name="toString(enum)" time="{duration}"/>
<testcase classname="global" name="toString(enum w/operator&lt;&lt;)" time="{duration}"/> <testcase classname="global" name="toString(enum w/operator&lt;&lt;)" time="{duration}"/>
<testcase classname="global" name="toString(enum class)" time="{duration}"/> <testcase classname="global" name="toString(enum class)" time="{duration}"/>
@ -500,6 +501,7 @@ MiscTests.cpp:<line number>
<testcase classname="XmlEncode" name="string with control char (x7F)" time="{duration}"/> <testcase classname="XmlEncode" name="string with control char (x7F)" time="{duration}"/>
<testcase classname="global" name="long long" time="{duration}"/> <testcase classname="global" name="long long" time="{duration}"/>
<testcase classname="global" name="This test 'should' fail but doesn't" time="{duration}"/> <testcase classname="global" name="This test 'should' fail but doesn't" time="{duration}"/>
<testcase classname="global" name="# A test name that starts with a #" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="default - no arguments" time="{duration}"/> <testcase classname="Process can be configured on command line" name="default - no arguments" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="test lists/1 test" time="{duration}"/> <testcase classname="Process can be configured on command line" name="test lists/1 test" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="test lists/Specify one test case exclusion using exclude:" time="{duration}"/> <testcase classname="Process can be configured on command line" name="test lists/Specify one test case exclusion using exclude:" time="{duration}"/>

View File

@ -1,3 +1,4 @@
<?xml version="1.1" encoding="UTF-8"?>
<Catch name="CatchSelfTest"> <Catch name="CatchSelfTest">
<Group name="CatchSelfTest"> <Group name="CatchSelfTest">
<TestCase name="toString(enum)"> <TestCase name="toString(enum)">
@ -4051,10 +4052,10 @@
<Section name="string with control char (1)"> <Section name="string with control char (1)">
<Expression success="true" type="REQUIRE" filename="projects/SelfTest/MiscTests.cpp" > <Expression success="true" type="REQUIRE" filename="projects/SelfTest/MiscTests.cpp" >
<Original> <Original>
encode( "[\x01]" ) == "[&amp;#x1]" encode( "[\x01]" ) == "[&amp;#x01;]"
</Original> </Original>
<Expanded> <Expanded>
"[&amp;#x1]" == "[&amp;#x1]" "[&amp;#x01;]" == "[&amp;#x01;]"
</Expanded> </Expanded>
</Expression> </Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/> <OverallResults successes="1" failures="0" expectedFailures="0"/>
@ -4062,10 +4063,10 @@
<Section name="string with control char (x7F)"> <Section name="string with control char (x7F)">
<Expression success="true" type="REQUIRE" filename="projects/SelfTest/MiscTests.cpp" > <Expression success="true" type="REQUIRE" filename="projects/SelfTest/MiscTests.cpp" >
<Original> <Original>
encode( "[\x7F]" ) == "[&amp;#x7F]" encode( "[\x7F]" ) == "[&amp;#x7F;]"
</Original> </Original>
<Expanded> <Expanded>
"[&amp;#x7F]" == "[&amp;#x7F]" "[&amp;#x7F;]" == "[&amp;#x7F;]"
</Expanded> </Expanded>
</Expression> </Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/> <OverallResults successes="1" failures="0" expectedFailures="0"/>
@ -4088,6 +4089,9 @@
<TestCase name="This test 'should' fail but doesn't"> <TestCase name="This test 'should' fail but doesn't">
<OverallResult success="false"/> <OverallResult success="false"/>
</TestCase> </TestCase>
<TestCase name="# A test name that starts with a #">
<OverallResult success="true"/>
</TestCase>
<TestCase name="Process can be configured on command line"> <TestCase name="Process can be configured on command line">
<Section name="default - no arguments"> <Section name="default - no arguments">
<Expression success="true" type="CHECK_NOTHROW" filename="projects/SelfTest/TestMain.cpp" > <Expression success="true" type="CHECK_NOTHROW" filename="projects/SelfTest/TestMain.cpp" >
@ -9566,7 +9570,7 @@ there"
</Section> </Section>
<OverallResult success="true"/> <OverallResult success="true"/>
</TestCase> </TestCase>
<OverallResults successes="824" failures="81" expectedFailures="18"/> <OverallResults successes="825" failures="81" expectedFailures="18"/>
</Group> </Group>
<OverallResults successes="824" failures="80" expectedFailures="18"/> <OverallResults successes="825" failures="80" expectedFailures="18"/>
</Catch> </Catch>

View File

@ -7,7 +7,7 @@
*/ */
#include "catch.hpp" #include "catch.hpp"
#include "catch_test_spec_parser.hpp" #include "internal/catch_test_spec_parser.hpp"
#ifdef __clang__ #ifdef __clang__
# pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat"

View File

@ -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]" ) { TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) {
const wchar_t * const s = L"wide load"; const wchar_t * const s = L"wide load";
std::string result = Catch::toString( s ); std::string result = Catch::toString( s );
CHECK( result == "\"wide load\"" ); CHECK( result == "\"wide load\"" );
} }
TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) { TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) {
const wchar_t * s = L"wide load"; const wchar_t * s = L"wide load";
std::string result = Catch::toString( s ); std::string result = Catch::toString( s );
CHECK( result == "\"wide load\"" ); CHECK( result == "\"wide load\"" );
} }
TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) { TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) {
wchar_t * const s = const_cast<wchar_t* const>( L"wide load" ); wchar_t * const s = const_cast<wchar_t* const>( L"wide load" );
std::string result = Catch::toString( s ); std::string result = Catch::toString( s );
CHECK( result == "\"wide load\"" ); CHECK( result == "\"wide load\"" );
} }
TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) { TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
wchar_t * s = const_cast<wchar_t*>( L"wide load" ); wchar_t * s = const_cast<wchar_t*>( L"wide load" );
std::string result = Catch::toString( s ); std::string result = Catch::toString( s );
CHECK( result == "\"wide load\"" ); CHECK( result == "\"wide load\"" );
} }
inline std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) { 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 (русский текст)" ) { SECTION( "string with utf-8 characters (русский текст)" ) {
REQUIRE( encode( "русский текст" ) == "русский текст" ); REQUIRE( encode( "русский текст" ) == "русский текст" );
REQUIRE( encode( "[\x01]" ) == "[&#x01;]" );
}
SECTION( "string with control char (x7F)" ) {
REQUIRE( encode( "[\x7F]" ) == "[&#x7F;]" );
} }
} }
@ -486,3 +490,7 @@ TEST_CASE( "This test 'should' fail but doesn't", "[.][failing][!shouldfail]" )
{ {
SUCCEED( "oops!" ); SUCCEED( "oops!" );
} }
TEST_CASE( "# A test name that starts with a #" ) {
SUCCEED( "yay" );
}

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_common.h" #include "internal/catch_common.h"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_console_colour.hpp" #include "internal/catch_console_colour.hpp"

View File

@ -1,2 +1,2 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // 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"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_interfaces_capture.h" #include "internal/catch_interfaces_capture.h"

View File

@ -1,2 +1,2 @@
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_interfaces_config.h" #include "internal/catch_interfaces_config.h"

View File

@ -1,2 +1,2 @@
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_interfaces_exception.h" #include "internal/catch_interfaces_exception.h"

View File

@ -1 +1 @@
#include "catch_interfaces_generators.h" #include "internal/catch_interfaces_generators.h"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_interfaces_registry_hub.h" #include "internal/catch_interfaces_registry_hub.h"

View File

@ -1,2 +1,2 @@
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_interfaces_reporter.h" #include "internal/catch_interfaces_reporter.h"

View File

@ -1 +1 @@
#include "catch_interfaces_runner.h" #include "internal/catch_interfaces_runner.h"

View File

@ -1,2 +1,2 @@
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_interfaces_testcase.h" #include "internal/catch_interfaces_testcase.h"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_message.h" #include "internal/catch_message.h"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_option.hpp" #include "internal/catch_option.hpp"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_ptr.hpp" #include "internal/catch_ptr.hpp"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_stream.h" #include "internal/catch_stream.h"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_streambuf.h" #include "internal/catch_streambuf.h"

View File

@ -1,3 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_test_spec.hpp" #include "internal/catch_test_spec.hpp"

View File

@ -1,4 +1,4 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#include "catch_xmlwriter.hpp" #include "internal/catch_xmlwriter.hpp"
#include "catch_reenable_warnings.h" #include "internal/catch_reenable_warnings.h"

View File

@ -25,7 +25,7 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" )
template<size_t size> template<size_t size>
void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) { void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) {
Catch::Clara::CommandLine<Catch::ConfigData> parser = Catch::makeCommandLineParser(); Catch::Clara::CommandLine<Catch::ConfigData> parser = Catch::makeCommandLineParser();
parser.parseInto( size, argv, config ); parser.parseInto( Catch::Clara::argsToVector( size, argv ), config );
} }
template<size_t size> template<size_t size>

View File

@ -1,6 +1,6 @@
/* /*
* Catch v1.4.0 * Catch v1.5.8
* Generated: 2016-03-15 07:23:12.623111 * Generated: 2016-10-26 12:07:30.938259
* ---------------------------------------------------------- * ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly * This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@ -106,8 +106,16 @@
// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
#if defined(__cplusplus) && __cplusplus >= 201103L #ifdef __cplusplus
# define CATCH_CPP11_OR_GREATER
# if __cplusplus >= 201103L
# define CATCH_CPP11_OR_GREATER
# endif
# if __cplusplus >= 201402L
# define CATCH_CPP14_OR_GREATER
# endif
#endif #endif
#ifdef __clang__ #ifdef __clang__
@ -2065,7 +2073,7 @@ namespace Catch {
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
} \ } \
INTERNAL_CATCH_REACT( __catchResult ) \ INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::isTrue( false && static_cast<bool>(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 ) \ #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
@ -3215,10 +3223,11 @@ namespace Catch {
bool matches( TestCaseInfo const& testCase ) const { bool matches( TestCaseInfo const& testCase ) const {
// All patterns in a filter must match for the filter to be a match // All patterns in a filter must match for the filter to be a match
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
if( !(*it)->matches( testCase ) ) if( !(*it)->matches( testCase ) )
return false; return false;
return true; }
return true;
} }
}; };
@ -3450,7 +3459,7 @@ namespace Catch {
}; };
class DebugOutStream : public IStream { class DebugOutStream : public IStream {
std::auto_ptr<StreamBufBase> m_streamBuf; CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
mutable std::ostream m_os; mutable std::ostream m_os;
public: public:
DebugOutStream(); DebugOutStream();
@ -3598,7 +3607,7 @@ namespace Catch {
} }
ConfigData m_data; ConfigData m_data;
std::auto_ptr<IStream const> m_stream; CATCH_AUTO_PTR( IStream const ) m_stream;
TestSpec m_testSpec; TestSpec m_testSpec;
}; };
@ -3618,7 +3627,7 @@ namespace Catch {
#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
// #included from: ../external/clara.h // #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 // Only use header guard if we are not using an outer namespace
#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
@ -3934,6 +3943,10 @@ namespace Tbc {
#include <stdexcept> #include <stdexcept>
#include <memory> #include <memory>
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define CLARA_PLATFORM_WINDOWS
#endif
// Use optional outer namespace // Use optional outer namespace
#ifdef STITCH_CLARA_OPEN_NAMESPACE #ifdef STITCH_CLARA_OPEN_NAMESPACE
STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
@ -3957,9 +3970,6 @@ namespace Clara {
const unsigned int consoleWidth = 80; const unsigned int consoleWidth = 80;
#endif #endif
// Use this to try and stop compiler from warning about unreachable code
inline bool isTrue( bool value ) { return value; }
using namespace Tbc; using namespace Tbc;
inline bool startsWith( std::string const& str, std::string const& prefix ) { inline bool startsWith( std::string const& str, std::string const& prefix ) {
@ -3995,14 +4005,6 @@ namespace Clara {
else else
throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
} }
inline void convertInto( bool _source, bool& _dest ) {
_dest = _source;
}
template<typename T>
inline void convertInto( bool, T& ) {
if( isTrue( true ) )
throw std::runtime_error( "Invalid conversion" );
}
template<typename ConfigT> template<typename ConfigT>
struct IArgFunction { struct IArgFunction {
@ -4012,7 +4014,6 @@ namespace Clara {
IArgFunction( IArgFunction const& ) = default; IArgFunction( IArgFunction const& ) = default;
#endif #endif
virtual void set( ConfigT& config, std::string const& value ) const = 0; virtual void set( ConfigT& config, std::string const& value ) const = 0;
virtual void setFlag( ConfigT& config ) const = 0;
virtual bool takesArg() const = 0; virtual bool takesArg() const = 0;
virtual IArgFunction* clone() const = 0; virtual IArgFunction* clone() const = 0;
}; };
@ -4034,9 +4035,6 @@ namespace Clara {
void set( ConfigT& config, std::string const& value ) const { void set( ConfigT& config, std::string const& value ) const {
functionObj->set( config, value ); functionObj->set( config, value );
} }
void setFlag( ConfigT& config ) const {
functionObj->setFlag( config );
}
bool takesArg() const { return functionObj->takesArg(); } bool takesArg() const { return functionObj->takesArg(); }
bool isSet() const { bool isSet() const {
@ -4049,7 +4047,6 @@ namespace Clara {
template<typename C> template<typename C>
struct NullBinder : IArgFunction<C>{ struct NullBinder : IArgFunction<C>{
virtual void set( C&, std::string const& ) const {} virtual void set( C&, std::string const& ) const {}
virtual void setFlag( C& ) const {}
virtual bool takesArg() const { return true; } virtual bool takesArg() const { return true; }
virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
}; };
@ -4060,9 +4057,6 @@ namespace Clara {
virtual void set( C& p, std::string const& stringValue ) const { virtual void set( C& p, std::string const& stringValue ) const {
convertInto( stringValue, p.*member ); convertInto( stringValue, p.*member );
} }
virtual void setFlag( C& p ) const {
convertInto( true, p.*member );
}
virtual bool takesArg() const { return !IsBool<M>::value; } virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
M C::* member; M C::* member;
@ -4075,11 +4069,6 @@ namespace Clara {
convertInto( stringValue, value ); convertInto( stringValue, value );
(p.*member)( value ); (p.*member)( value );
} }
virtual void setFlag( C& p ) const {
typename RemoveConstRef<M>::type value;
convertInto( true, value );
(p.*member)( value );
}
virtual bool takesArg() const { return !IsBool<M>::value; } virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
void (C::*member)( M ); void (C::*member)( M );
@ -4093,9 +4082,6 @@ namespace Clara {
if( value ) if( value )
(p.*member)(); (p.*member)();
} }
virtual void setFlag( C& p ) const {
(p.*member)();
}
virtual bool takesArg() const { return false; } virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
void (C::*member)(); void (C::*member)();
@ -4110,9 +4096,6 @@ namespace Clara {
if( value ) if( value )
function( obj ); function( obj );
} }
virtual void setFlag( C& p ) const {
function( p );
}
virtual bool takesArg() const { return false; } virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
void (*function)( C& ); void (*function)( C& );
@ -4126,11 +4109,6 @@ namespace Clara {
convertInto( stringValue, value ); convertInto( stringValue, value );
function( obj, value ); function( obj, value );
} }
virtual void setFlag( C& obj ) const {
typename RemoveConstRef<T>::type value;
convertInto( true, value );
function( obj, value );
}
virtual bool takesArg() const { return !IsBool<T>::value; } virtual bool takesArg() const { return !IsBool<T>::value; }
virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
void (*function)( C&, T ); void (*function)( C&, T );
@ -4138,8 +4116,20 @@ namespace Clara {
} // namespace Detail } // namespace Detail
struct Parser { inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
Parser() : separators( " \t=:" ) {} std::vector<std::string> args( static_cast<std::size_t>( argc ) );
for( std::size_t i = 0; i < static_cast<std::size_t>( 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 { struct Token {
enum Type { Positional, ShortOpt, LongOpt }; enum Type { Positional, ShortOpt, LongOpt };
@ -4148,38 +4138,75 @@ namespace Clara {
std::string data; std::string data;
}; };
void parseIntoTokens( int argc, char const* const argv[], std::vector<Parser::Token>& tokens ) const { Parser() : mode( None ), from( 0 ), inQuotes( false ){}
void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
const std::string doubleDash = "--"; const std::string doubleDash = "--";
for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
parseIntoTokens( argv[i] , tokens); parseIntoTokens( args[i], tokens);
} }
void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
while( !arg.empty() ) { void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
Parser::Token token( Parser::Token::Positional, arg ); for( std::size_t i = 0; i <= arg.size(); ++i ) {
arg = ""; char c = arg[i];
if( token.data[0] == '-' ) { if( c == '"' )
if( token.data.size() > 1 && token.data[1] == '-' ) { inQuotes = !inQuotes;
token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); mode = handleMode( i, c, arg, tokens );
}
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 );
} }
} }
std::string separators; Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& 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<Token>& 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<Token>& 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<typename ConfigT> template<typename ConfigT>
@ -4482,21 +4509,21 @@ namespace Clara {
return oss.str(); return oss.str();
} }
ConfigT parse( int argc, char const* const argv[] ) const { ConfigT parse( std::vector<std::string> const& args ) const {
ConfigT config; ConfigT config;
parseInto( argc, argv, config ); parseInto( args, config );
return config; return config;
} }
std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const { std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
std::string processName = argv[0]; std::string processName = args[0];
std::size_t lastSlash = processName.find_last_of( "/\\" ); std::size_t lastSlash = processName.find_last_of( "/\\" );
if( lastSlash != std::string::npos ) if( lastSlash != std::string::npos )
processName = processName.substr( lastSlash+1 ); processName = processName.substr( lastSlash+1 );
m_boundProcessName.set( config, processName ); m_boundProcessName.set( config, processName );
std::vector<Parser::Token> tokens; std::vector<Parser::Token> tokens;
Parser parser; Parser parser;
parser.parseIntoTokens( argc, argv, tokens ); parser.parseIntoTokens( args, tokens );
return populate( tokens, config ); return populate( tokens, config );
} }
@ -4527,7 +4554,7 @@ namespace Clara {
arg.boundField.set( config, tokens[++i].data ); arg.boundField.set( config, tokens[++i].data );
} }
else { else {
arg.boundField.setFlag( config ); arg.boundField.set( config, "true" );
} }
break; break;
} }
@ -4693,8 +4720,11 @@ namespace Catch {
std::string line; std::string line;
while( std::getline( f, line ) ) { while( std::getline( f, line ) ) {
line = trim(line); line = trim(line);
if( !line.empty() && !startsWith( line, "#" ) ) if( !line.empty() && !startsWith( line, "#" ) ) {
addTestOrTags( config, "\"" + line + "\"," ); if( !startsWith( line, "\"" ) )
line = "\"" + line + "\"";
addTestOrTags( config, line + "," );
}
} }
} }
@ -5235,6 +5265,8 @@ namespace Catch
bool aborting; bool aborting;
}; };
class MultipleReporters;
struct IStreamingReporter : IShared { struct IStreamingReporter : IShared {
virtual ~IStreamingReporter(); virtual ~IStreamingReporter();
@ -5262,6 +5294,8 @@ namespace Catch
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
virtual void skipTest( TestCaseInfo const& testInfo ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
}; };
struct IReporterFactory : IShared { struct IReporterFactory : IShared {
@ -5338,7 +5372,10 @@ namespace Catch {
++it ) { ++it ) {
matchedTests++; matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); 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; return matchedTests;
} }
@ -5479,6 +5516,10 @@ namespace TestCaseTracking {
virtual void addChild( Ptr<ITracker> const& child ) = 0; virtual void addChild( Ptr<ITracker> const& child ) = 0;
virtual ITracker* findChild( std::string const& name ) = 0; virtual ITracker* findChild( std::string const& name ) = 0;
virtual void openChild() = 0; virtual void openChild() = 0;
// Debug/ checking
virtual bool isSectionTracker() const = 0;
virtual bool isIndexTracker() const = 0;
}; };
class TrackerContext { class TrackerContext {
@ -5603,6 +5644,10 @@ namespace TestCaseTracking {
m_parent->openChild(); m_parent->openChild();
} }
} }
virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
void open() { void open() {
m_runState = Executing; m_runState = Executing;
moveToThis(); moveToThis();
@ -5666,13 +5711,16 @@ namespace TestCaseTracking {
{} {}
virtual ~SectionTracker(); virtual ~SectionTracker();
virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
SectionTracker* section = CATCH_NULL; SectionTracker* section = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker(); ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) { if( ITracker* childTracker = currentTracker.findChild( name ) ) {
section = dynamic_cast<SectionTracker*>( childTracker ); assert( childTracker );
assert( section ); assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
} }
else { else {
section = new SectionTracker( name, ctx, &currentTracker ); section = new SectionTracker( name, ctx, &currentTracker );
@ -5697,13 +5745,16 @@ namespace TestCaseTracking {
{} {}
virtual ~IndexTracker(); virtual ~IndexTracker();
virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
IndexTracker* tracker = CATCH_NULL; IndexTracker* tracker = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker(); ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) { if( ITracker* childTracker = currentTracker.findChild( name ) ) {
tracker = dynamic_cast<IndexTracker*>( childTracker ); assert( childTracker );
assert( tracker ); assert( childTracker->isIndexTracker() );
tracker = static_cast<IndexTracker*>( childTracker );
} }
else { else {
tracker = new IndexTracker( name, ctx, &currentTracker, size ); tracker = new IndexTracker( name, ctx, &currentTracker, size );
@ -6306,10 +6357,10 @@ namespace Catch {
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; 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 { try {
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); 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 ) if( m_configData.showHelp )
showHelp( m_configData.processName ); showHelp( m_configData.processName );
m_config.reset(); m_config.reset();
@ -6333,16 +6384,13 @@ namespace Catch {
m_config.reset(); m_config.reset();
} }
int run( int argc, char const* argv[] ) { int run( int argc, char const* const* const argv ) {
int returnCode = applyCommandLine( argc, argv ); int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 ) if( returnCode == 0 )
returnCode = run(); returnCode = run();
return returnCode; return returnCode;
} }
int run( int argc, char* argv[] ) {
return run( argc, const_cast<char const**>( argv ) );
}
int run() { int run() {
if( m_configData.showHelp ) if( m_configData.showHelp )
@ -6406,13 +6454,31 @@ namespace Catch {
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#ifdef CATCH_CPP14_OR_GREATER
#include <random>
#endif
namespace Catch { namespace Catch {
struct LexSort {
bool operator() (TestCase i,TestCase j) const { return (i<j);}
};
struct RandomNumberGenerator { struct RandomNumberGenerator {
int operator()( int n ) const { return std::rand() % n; } typedef std::ptrdiff_t result_type;
result_type operator()( result_type n ) const { return std::rand() % n; }
#ifdef CATCH_CPP14_OR_GREATER
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return 1000000; }
result_type operator()() const { return std::rand() % max(); }
#endif
template<typename V>
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<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
@ -6421,14 +6487,12 @@ namespace Catch {
switch( config.runOrder() ) { switch( config.runOrder() ) {
case RunTests::InLexicographicalOrder: case RunTests::InLexicographicalOrder:
std::sort( sorted.begin(), sorted.end(), LexSort() ); std::sort( sorted.begin(), sorted.end() );
break; break;
case RunTests::InRandomOrder: case RunTests::InRandomOrder:
{ {
seedRng( config ); seedRng( config );
RandomNumberGenerator::shuffle( sorted );
RandomNumberGenerator rng;
std::random_shuffle( sorted.begin(), sorted.end(), rng );
} }
break; break;
case RunTests::InDeclarationOrder: case RunTests::InDeclarationOrder:
@ -6447,13 +6511,15 @@ namespace Catch {
it != itEnd; it != itEnd;
++it ) { ++it ) {
std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it ); std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
if( !prev.second ){ if( !prev.second ) {
Catch::cerr() std::ostringstream ss;
<< Colour( Colour::Red )
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" ss << Colour( Colour::Red )
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
exit(1); << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
throw std::runtime_error(ss.str());
} }
} }
} }
@ -7512,7 +7578,7 @@ namespace Catch {
return os; 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 ) { bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos; return s.find( infix ) != std::string::npos;
} }
char toLowerCh(char c) {
return static_cast<char>( ::tolower( c ) );
}
void toLowerInPlace( std::string& s ) { 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 toLower( std::string const& s ) {
std::string lc = s; std::string lc = s;
@ -8491,13 +8560,18 @@ public: // IStreamingReporter
++it ) ++it )
(*it)->skipTest( testInfo ); (*it)->skipTest( testInfo );
} }
virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
return this;
}
}; };
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) { Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
Ptr<IStreamingReporter> resultingReporter; Ptr<IStreamingReporter> resultingReporter;
if( existingReporter ) { if( existingReporter ) {
MultipleReporters* multi = dynamic_cast<MultipleReporters*>( existingReporter.get() ); MultipleReporters* multi = existingReporter->tryAsMulti();
if( !multi ) { if( !multi ) {
multi = new MultipleReporters; multi = new MultipleReporters;
resultingReporter = Ptr<IStreamingReporter>( multi ); resultingReporter = Ptr<IStreamingReporter>( multi );
@ -8677,7 +8751,7 @@ namespace Catch {
virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} 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() ); assert( !m_sectionStack.empty() );
SectionNode& sectionNode = *m_sectionStack.back(); SectionNode& sectionNode = *m_sectionStack.back();
sectionNode.assertions.push_back( assertionStats ); sectionNode.assertions.push_back( assertionStats );
@ -8887,9 +8961,10 @@ namespace Catch {
break; break;
default: 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' ) if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
os << "&#x" << std::uppercase << std::hex << static_cast<int>( c ); os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
else else
os << c; os << c;
} }
@ -8944,13 +9019,20 @@ namespace Catch {
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &Catch::cout() ) 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 << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
XmlWriter( std::ostream& os ) XmlWriter( std::ostream& os )
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &os ) m_os( &os )
{} {
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
~XmlWriter() { ~XmlWriter() {
while( !m_tags.empty() ) while( !m_tags.empty() )
@ -9117,7 +9199,7 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting(testInfo); 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 ) if ( m_config->showDurations() == ShowDurations::Always )
m_testCaseTimer.start(); m_testCaseTimer.start();
@ -9179,7 +9261,7 @@ namespace Catch {
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );
break; break;
case ResultWas::FatalErrorCondition: case ResultWas::FatalErrorCondition:
m_xml.scopedElement( "Fatal Error Condition" ) m_xml.scopedElement( "FatalErrorCondition" )
.writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeAttribute( "line", assertionResult.getSourceInfo().line )
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );