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
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:

View File

@ -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)

View File

@ -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.

View File

@ -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<char const**>( argv ) );
}
int run() {
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)
*/
// 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 <stdexcept>
#include <memory>
#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<typename T>
inline void convertInto( bool, T& ) {
if( isTrue( true ) )
throw std::runtime_error( "Invalid conversion" );
}
template<typename ConfigT>
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<typename C>
struct NullBinder : IArgFunction<C>{
virtual void set( C&, std::string const& ) const {}
virtual void setFlag( C& ) const {}
virtual bool takesArg() const { return true; }
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 {
convertInto( stringValue, p.*member );
}
virtual void setFlag( C& p ) const {
convertInto( true, p.*member );
}
virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* 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<M>::type value;
convertInto( true, value );
(p.*member)( value );
}
virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* 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<C>* 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<C>* 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<T>::type value;
convertInto( true, value );
function( obj, value );
}
virtual bool takesArg() const { return !IsBool<T>::value; }
virtual IArgFunction<C>* 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<std::string> argsToVector( int argc, char const* const* const argv ) {
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 {
enum Type { Positional, ShortOpt, LongOpt };
@ -558,38 +541,75 @@ namespace Clara {
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 = "--";
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<Parser::Token>& 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<Token>& 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<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>
@ -894,21 +914,21 @@ namespace Clara {
return oss.str();
}
ConfigT parse( int argc, char const* const argv[] ) const {
ConfigT parse( std::vector<std::string> const& args ) const {
ConfigT config;
parseInto( argc, argv, config );
parseInto( args, config );
return config;
}
std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const {
std::string processName = argv[0];
std::vector<Parser::Token> parseInto( std::vector<std::string> 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<Parser::Token> 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;
}

View File

@ -40,7 +40,7 @@
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
} \
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 ) \

View File

@ -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 + "," );
}
}
}

View File

@ -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<char>( ::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;

View File

@ -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__

View File

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

View File

@ -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; }
};

View File

@ -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;
}

View File

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

View File

@ -19,13 +19,31 @@
#include <iostream>
#include <algorithm>
#ifdef CATCH_CPP14_OR_GREATER
#include <random>
#endif
namespace Catch {
struct LexSort {
bool operator() (TestCase i,TestCase j) const { return (i<j);}
};
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 ) {
@ -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<std::set<TestCase>::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());
}
}
}

View File

@ -41,6 +41,10 @@ namespace TestCaseTracking {
virtual void addChild( Ptr<ITracker> 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<SectionTracker*>( childTracker );
assert( section );
assert( childTracker );
assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
}
else {
section = new SectionTracker( name, ctx, &currentTracker );
@ -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<IndexTracker*>( childTracker );
assert( tracker );
assert( childTracker );
assert( childTracker->isIndexTracker() );
tracker = static_cast<IndexTracker*>( childTracker );
}
else {
tracker = new IndexTracker( name, ctx, &currentTracker, size );

View File

@ -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<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 ) )
return false;
return true;
}
return true;
}
};

View File

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

View File

@ -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<int>( c ) << ";";
os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( 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 << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
XmlWriter( std::ostream& os )
: m_tagIsOpen( false ),
m_needsNewline( false ),
m_os( &os )
{}
{
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
~XmlWriter() {
while( !m_tags.empty() )

View File

@ -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 );

View File

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

View File

@ -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() );

View File

@ -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)

View File

@ -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

View File

@ -3920,9 +3920,9 @@ MiscTests.cpp:<line number>
MiscTests.cpp:<line number>:
PASSED:
REQUIRE( encode( "[\x01]" ) == "[&#x1]" )
REQUIRE( encode( "[\x01]" ) == "[&#x01;]" )
with expansion:
"[&#x1]" == "[&#x1]"
"[&#x01;]" == "[&#x01;]"
-------------------------------------------------------------------------------
XmlEncode
@ -3933,9 +3933,9 @@ MiscTests.cpp:<line number>
MiscTests.cpp:<line number>:
PASSED:
REQUIRE( encode( "[\x7F]" ) == "[&#x7F]" )
REQUIRE( encode( "[\x7F]" ) == "[&#x7F;]" )
with expansion:
"[&#x7F]" == "[&#x7F]"
"[&#x7F;]" == "[&#x7F;]"
-------------------------------------------------------------------------------
long long
@ -3962,6 +3962,17 @@ PASSED:
with message:
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
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

View File

@ -1,5 +1,6 @@
<?xml version="1.1" encoding="UTF-8"?>
<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 w/operator&lt;&lt;)" 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="global" name="long long" 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="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}"/>

View File

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

View File

@ -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"

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]" ) {
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<wchar_t* const>( L"wide load" );
std::string result = Catch::toString( s );
CHECK( result == "\"wide load\"" );
wchar_t * const s = const_cast<wchar_t* const>( 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<wchar_t*>( L"wide load" );
std::string result = Catch::toString( s );
CHECK( result == "\"wide load\"" );
wchar_t * s = const_cast<wchar_t*>( 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]" ) == "[&#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!" );
}
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
#include "catch_suppress_warnings.h"
#include "catch_common.h"
#include "internal/catch_suppress_warnings.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
#include "catch_suppress_warnings.h"
#include "catch_console_colour.hpp"
#include "internal/catch_suppress_warnings.h"
#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
#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
#include "catch_suppress_warnings.h"
#include "catch_interfaces_capture.h"
#include "internal/catch_suppress_warnings.h"
#include "internal/catch_interfaces_capture.h"

View File

@ -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"

View File

@ -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"

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
#include "catch_suppress_warnings.h"
#include "catch_interfaces_registry_hub.h"
#include "internal/catch_suppress_warnings.h"
#include "internal/catch_interfaces_registry_hub.h"

View File

@ -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"

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 "catch_interfaces_testcase.h"
#include "internal/catch_suppress_warnings.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
#include "catch_suppress_warnings.h"
#include "catch_message.h"
#include "internal/catch_suppress_warnings.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
#include "catch_suppress_warnings.h"
#include "catch_option.hpp"
#include "internal/catch_suppress_warnings.h"
#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
#include "catch_suppress_warnings.h"
#include "catch_ptr.hpp"
#include "internal/catch_suppress_warnings.h"
#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
#include "catch_suppress_warnings.h"
#include "catch_stream.h"
#include "internal/catch_suppress_warnings.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
#include "catch_suppress_warnings.h"
#include "catch_streambuf.h"
#include "internal/catch_suppress_warnings.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
#include "catch_suppress_warnings.h"
#include "catch_test_spec.hpp"
#include "internal/catch_suppress_warnings.h"
#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
#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"

View File

@ -25,7 +25,7 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" )
template<size_t size>
void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) {
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>

View File

@ -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<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 ) \
@ -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<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 ) )
return false;
return true;
}
return true;
}
};
@ -3450,7 +3459,7 @@ namespace Catch {
};
class DebugOutStream : public IStream {
std::auto_ptr<StreamBufBase> 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<IStream const> 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 <stdexcept>
#include <memory>
#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<typename T>
inline void convertInto( bool, T& ) {
if( isTrue( true ) )
throw std::runtime_error( "Invalid conversion" );
}
template<typename ConfigT>
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<typename C>
struct NullBinder : IArgFunction<C>{
virtual void set( C&, std::string const& ) const {}
virtual void setFlag( C& ) const {}
virtual bool takesArg() const { return true; }
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 {
convertInto( stringValue, p.*member );
}
virtual void setFlag( C& p ) const {
convertInto( true, p.*member );
}
virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* 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<M>::type value;
convertInto( true, value );
(p.*member)( value );
}
virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* 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<C>* 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<C>* 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<T>::type value;
convertInto( true, value );
function( obj, value );
}
virtual bool takesArg() const { return !IsBool<T>::value; }
virtual IArgFunction<C>* 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<std::string> argsToVector( int argc, char const* const* const argv ) {
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 {
enum Type { Positional, ShortOpt, LongOpt };
@ -4148,38 +4138,75 @@ namespace Clara {
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 = "--";
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<Parser::Token>& 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<Token>& 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<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>
@ -4482,21 +4509,21 @@ namespace Clara {
return oss.str();
}
ConfigT parse( int argc, char const* const argv[] ) const {
ConfigT parse( std::vector<std::string> const& args ) const {
ConfigT config;
parseInto( argc, argv, config );
parseInto( args, config );
return config;
}
std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const {
std::string processName = argv[0];
std::vector<Parser::Token> parseInto( std::vector<std::string> 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<Parser::Token> 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<ITracker> 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<SectionTracker*>( childTracker );
assert( section );
assert( childTracker );
assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
}
else {
section = new SectionTracker( name, ctx, &currentTracker );
@ -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<IndexTracker*>( childTracker );
assert( tracker );
assert( childTracker );
assert( childTracker->isIndexTracker() );
tracker = static_cast<IndexTracker*>( childTracker );
}
else {
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;
}
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<char const**>( argv ) );
}
int run() {
if( m_configData.showHelp )
@ -6406,13 +6454,31 @@ namespace Catch {
#include <iostream>
#include <algorithm>
#ifdef CATCH_CPP14_OR_GREATER
#include <random>
#endif
namespace Catch {
struct LexSort {
bool operator() (TestCase i,TestCase j) const { return (i<j);}
};
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 ) {
@ -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<std::set<TestCase>::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<char>( ::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<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
Ptr<IStreamingReporter> resultingReporter;
if( existingReporter ) {
MultipleReporters* multi = dynamic_cast<MultipleReporters*>( existingReporter.get() );
MultipleReporters* multi = existingReporter->tryAsMulti();
if( !multi ) {
multi = new MultipleReporters;
resultingReporter = Ptr<IStreamingReporter>( 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<int>( c );
os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( 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 << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
XmlWriter( std::ostream& os )
: m_tagIsOpen( false ),
m_needsNewline( false ),
m_os( &os )
{}
{
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\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() );