catch2/single_include/catch.hpp
Vadim Zeitlin b7f7054828 Fix harmless but annoying MSVC warnings.
Suppress

catch.hpp(1760) : warning C4512: 'Catch::TagExtracter' : assignment operator could not be generated
catch.hpp(1864) : warning C4512: 'Catch::TagExpressionParser' : assignment operator could not be generated

warnings given by MSVC 9 (and probably other version too) compiler with /W4 switch.

The warnings are given because the compiler can't synthesize the assignment
operators for the classes with members of reference type, so simply explicitly
declare (without defining) these operators ourselves to suppress them.
2012-10-31 19:17:31 +01:00

6327 lines
210 KiB
C++

/*
* Generated: 2012-10-31 19:15:51.281013
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
#ifdef __clang__
#pragma clang diagnostic ignored "-Wno-global-constructors"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpadded"
#endif
// #included from: internal/catch_notimplemented_exception.h
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
// #included from: catch_common.h
#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
#ifdef __GNUC__
#define CATCH_ATTRIBUTE_NORETURN __attribute__ ((noreturn))
#else
#define CATCH_ATTRIBUTE_NORETURN
#endif
#include <sstream>
#include <stdexcept>
#include <algorithm>
namespace Catch {
class NonCopyable {
NonCopyable( const NonCopyable& );
void operator = ( const NonCopyable& );
protected:
NonCopyable() {}
virtual ~NonCopyable();
};
class SafeBool {
public:
typedef void (SafeBool::*type)() const;
static type makeSafe( bool value ) {
return value ? &SafeBool::trueValue : 0;
}
private:
void trueValue() const {}
};
template<typename ContainerT>
inline void deleteAll( ContainerT& container ) {
typename ContainerT::const_iterator it = container.begin();
typename ContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )
{
delete *it;
}
}
template<typename AssociativeContainerT>
inline void deleteAllValues( AssociativeContainerT& container ) {
typename AssociativeContainerT::const_iterator it = container.begin();
typename AssociativeContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )
{
delete it->second;
}
}
template<typename ContainerT, typename Function>
inline void forEach( ContainerT& container, Function function ) {
std::for_each( container.begin(), container.end(), function );
}
template<typename ContainerT, typename Function>
inline void forEach( const ContainerT& container, Function function ) {
std::for_each( container.begin(), container.end(), function );
}
inline bool startsWith( const std::string& s, const std::string& prefix ) {
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
}
inline bool endsWith( const std::string& s, const std::string& suffix ) {
return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
}
inline bool contains( const std::string& s, const std::string& infix ) {
return s.find( infix ) != std::string::npos;
}
struct pluralise {
pluralise( std::size_t count, const std::string& label )
: m_count( count ),
m_label( label )
{}
friend std::ostream& operator << ( std::ostream& os, const pluralise& pluraliser ) {
os << pluraliser.m_count << " " << pluraliser.m_label;
if( pluraliser.m_count != 1 )
os << "s";
return os;
}
std::size_t m_count;
std::string m_label;
};
struct SourceLineInfo {
SourceLineInfo() : line( 0 ){}
SourceLineInfo( const std::string& _file, std::size_t _line )
: file( _file ),
line( _line )
{}
SourceLineInfo( const std::string& _function, const std::string& _file, std::size_t _line )
: function( _function ),
file( _file ),
line( _line )
{}
SourceLineInfo( const SourceLineInfo& other )
: file( other.file ),
line( other.line )
{}
void swap( SourceLineInfo& other ){
file.swap( other.file );
std::swap( line, other.line );
}
std::string function;
std::string file;
std::size_t line;
};
inline std::ostream& operator << ( std::ostream& os, const SourceLineInfo& info ) {
#ifndef __GNUG__
os << info.file << "(" << info.line << "): ";
#else
os << info.file << ":" << info.line << ": ";
#endif
return os;
}
CATCH_ATTRIBUTE_NORETURN
inline void throwLogicError( const std::string& message, const SourceLineInfo& locationInfo ) {
std::ostringstream oss;
oss << "Internal Catch error: '" << message << "' at: " << locationInfo;
throw std::logic_error( oss.str() );
}
}
#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
#include <ostream>
namespace Catch {
class NotImplementedException : public std::exception
{
public:
NotImplementedException( const SourceLineInfo& lineInfo );
virtual ~NotImplementedException() throw() {}
virtual const char* what() const throw();
private:
std::string m_what;
SourceLineInfo m_lineInfo;
};
} // end namespace Catch
///////////////////////////////////////////////////////////////////////////////
#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
// #included from: internal/catch_context.h
#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
// #included from: catch_interfaces_generators.h
#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
#include <string>
namespace Catch {
struct IGeneratorInfo {
virtual ~IGeneratorInfo();
virtual bool moveNext() = 0;
virtual std::size_t getCurrentIndex() const = 0;
};
struct IGeneratorsForTest {
virtual ~IGeneratorsForTest();
virtual IGeneratorInfo& getGeneratorInfo( const std::string& fileInfo, std::size_t size ) = 0;
virtual bool moveNext() = 0;
};
IGeneratorsForTest* createGeneratorsForTest();
} // end namespace Catch
#include <memory>
#include <vector>
#include <stdlib.h>
namespace Catch {
class TestCaseInfo;
class Stream;
struct IResultCapture;
struct IRunner;
struct IGeneratorsForTest;
struct IConfig;
struct IContext
{
virtual ~IContext();
virtual IResultCapture& getResultCapture() = 0;
virtual IRunner& getRunner() = 0;
virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) = 0;
virtual bool advanceGeneratorsForCurrentTest() = 0;
virtual const IConfig* getConfig() const = 0;
};
struct IMutableContext : IContext
{
virtual ~IMutableContext();
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
virtual void setRunner( IRunner* runner ) = 0;
virtual void setConfig( const IConfig* config ) = 0;
};
IContext& getCurrentContext();
IMutableContext& getCurrentMutableContext();
void cleanUpContext();
Stream createStream( const std::string& streamName );
}
// #included from: internal/catch_test_registry.hpp
#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
// #included from: catch_interfaces_testcase.h
#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
// #included from: catch_ptr.hpp
#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
namespace Catch {
// An intrusive reference counting smart pointer.
// T must implement addRef() and release() methods
// typically implementing the IShared interface
template<typename T>
class Ptr {
public:
Ptr() : m_p( NULL ){}
Ptr( T* p ) : m_p( p ){
if( m_p )
m_p->addRef();
}
Ptr( const Ptr& other ) : m_p( other.m_p ){
if( m_p )
m_p->addRef();
}
~Ptr(){
if( m_p )
m_p->release();
}
Ptr& operator = ( T* p ){
Ptr temp( p );
swap( temp );
return *this;
}
Ptr& operator = ( const Ptr& other ){
Ptr temp( other );
swap( temp );
return *this;
}
void swap( Ptr& other ){
std::swap( m_p, other.m_p );
}
T* get(){
return m_p;
}
const T* get() const{
return m_p;
}
T& operator*() const {
return *m_p;
}
T* operator->() const {
return m_p;
}
bool operator !() const {
return m_p == NULL;
}
private:
T* m_p;
};
struct IShared : NonCopyable {
virtual ~IShared();
virtual void addRef() = 0;
virtual void release() = 0;
};
template<typename T>
struct SharedImpl : T {
SharedImpl() : m_rc( 0 ){}
virtual void addRef(){
++m_rc;
}
virtual void release(){
if( --m_rc == 0 )
delete this;
}
int m_rc;
};
} // end namespace Catch
#include <vector>
namespace Catch {
class TestCaseFilters;
struct ITestCase : IShared {
virtual void invoke () const = 0;
protected:
virtual ~ITestCase();
};
class TestCaseInfo;
struct ITestCaseRegistry {
virtual ~ITestCaseRegistry();
virtual const std::vector<TestCaseInfo>& getAllTests() const = 0;
virtual std::vector<TestCaseInfo> getMatchingTestCases( const std::string& rawTestSpec ) const = 0;
};
}
namespace Catch {
template<typename C>
class MethodTestCase : public SharedImpl<ITestCase> {
public:
MethodTestCase( void (C::*method)() ) : m_method( method ) {}
virtual void invoke() const {
C obj;
(obj.*m_method)();
}
private:
virtual ~MethodTestCase() {}
void (C::*m_method)();
};
typedef void(*TestFunction)();
struct AutoReg {
AutoReg( TestFunction function,
const char* name,
const char* description,
const SourceLineInfo& lineInfo );
template<typename C>
AutoReg( void (C::*method)(),
const char* name,
const char* description,
const SourceLineInfo& lineInfo ) {
registerTestCase( new MethodTestCase<C>( method ), name, description, lineInfo );
}
void registerTestCase( ITestCase* testCase,
const char* name,
const char* description,
const SourceLineInfo& lineInfo );
~AutoReg();
private:
AutoReg( const AutoReg& );
void operator= ( const AutoReg& );
};
} // end namespace Catch
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )(); \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ ), Name, Desc, CATCH_INTERNAL_LINEINFO ); }\
static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )()
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE_NORETURN( Name, Desc ) \
static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )() CATCH_ATTRIBUTE_NORETURN; \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ ), Name, Desc, CATCH_INTERNAL_LINEINFO ); }\
static void INTERNAL_CATCH_UNIQUE_NAME( TestCaseFunction_catch_internal_ )()
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, Name, Desc, CATCH_INTERNAL_LINEINFO ); }
///////////////////////////////////////////////////////////////////////////////
#define TEST_CASE_METHOD( ClassName, TestName, Desc )\
namespace{ \
struct INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ ) : ClassName{ \
void test(); \
}; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ )::test, TestName, Desc, CATCH_INTERNAL_LINEINFO ); \
} \
void INTERNAL_CATCH_UNIQUE_NAME( TestCaseMethod_catch_internal_ )::test()
// #included from: internal/catch_capture.hpp
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
// #included from: catch_expression_builder.hpp
#define TWOBLUECUBES_CATCH_EXPRESSION_BUILDER_HPP_INCLUDED
// #included from: catch_expression.hpp
#define TWOBLUECUBES_CATCH_EXPRESSION_HPP_INCLUDED
// #included from: catch_resultinfo_builder.h
#define TWOBLUECUBES_CATCH_RESULTINFO_BUILDER_H_INCLUDED
// #included from: catch_tostring.hpp
#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
#include <sstream>
#ifdef __OBJC__
// #included from: catch_objc_arc.hpp
#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
#import <Foundation/Foundation.h>
#ifdef __has_feature
#define CATCH_ARC_ENABLED __has_feature(objc_arc)
#else
#define CATCH_ARC_ENABLED 0
#endif
void arcSafeRelease( NSObject* obj );
id performOptionalSelector( id obj, SEL sel );
#if !CATCH_ARC_ENABLED
inline void arcSafeRelease( NSObject* obj ) {
[obj release];
}
inline id performOptionalSelector( id obj, SEL sel ) {
if( [obj respondsToSelector: sel] )
return [obj performSelector: sel];
return nil;
}
#define CATCH_UNSAFE_UNRETAINED
#define CATCH_ARC_STRONG
#else
inline void arcSafeRelease( NSObject* ){}
inline id performOptionalSelector( id obj, SEL sel ) {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
#endif
if( [obj respondsToSelector: sel] )
return [obj performSelector: sel];
#ifdef __clang__
#pragma clang diagnostic pop
#endif
return nil;
}
#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
#define CATCH_ARC_STRONG __strong
#endif
#endif
namespace Catch {
namespace Detail {
struct NonStreamable {
template<typename T> NonStreamable( const T& ){}
};
// If the type does not have its own << overload for ostream then
// this one will be used instead
inline std::ostream& operator << ( std::ostream& ss, NonStreamable ){
return ss << "{?}";
}
template<typename T>
inline std::string makeString( const T& value ) {
std::ostringstream oss;
oss << value;
return oss.str();
}
template<typename T>
inline std::string makeString( T* p ) {
if( !p )
return INTERNAL_CATCH_STRINGIFY( NULL );
std::ostringstream oss;
oss << p;
return oss.str();
}
template<typename T>
inline std::string makeString( const T* p ) {
if( !p )
return INTERNAL_CATCH_STRINGIFY( NULL );
std::ostringstream oss;
oss << p;
return oss.str();
}
} // end namespace Detail
/// \brief converts any type to a string
///
/// The default template forwards on to ostringstream - except when an
/// ostringstream overload does not exist - in which case it attempts to detect
/// that and writes {?}.
/// Overload (not specialise) this template for custom typs that you don't want
/// to provide an ostream overload for.
template<typename T>
std::string toString( const T& value ) {
return Detail::makeString( value );
}
// Built in overloads
inline std::string toString( const std::string& value ) {
return "\"" + value + "\"";
}
inline std::string toString( const std::wstring& value ) {
std::ostringstream oss;
oss << "\"";
for(size_t i = 0; i < value.size(); ++i )
oss << static_cast<char>( value[i] <= 0xff ? value[i] : '?');
oss << "\"";
return oss.str();
}
inline std::string toString( const char* const value ) {
return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
}
inline std::string toString( char* const value ) {
return Catch::toString( static_cast<const char*>( value ) );
}
inline std::string toString( int value ) {
std::ostringstream oss;
oss << value;
return oss.str();
}
inline std::string toString( unsigned long value ) {
std::ostringstream oss;
if( value > 8192 )
oss << "0x" << std::hex << value;
else
oss << value;
return oss.str();
}
inline std::string toString( unsigned int value ) {
return toString( static_cast<unsigned long>( value ) );
}
inline std::string toString( const double value ) {
std::ostringstream oss;
oss << value;
return oss.str();
}
inline std::string toString( bool value ) {
return value ? "true" : "false";
}
inline std::string toString( char value ) {
return value < ' '
? toString( (unsigned int)value )
: Detail::makeString( value );
}
inline std::string toString( signed char value ) {
return toString( static_cast<char>( value ) );
}
#ifdef CATCH_CONFIG_CPP11_NULLPTR
inline std::string toString( std::nullptr_t ) {
return "nullptr";
}
#endif
#ifdef __OBJC__
inline std::string toString( NSString const * const& nsstring ) {
return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
}
inline std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
}
inline std::string toString( NSObject* const& nsObject ) {
return toString( [nsObject description] );
}
#endif
} // end namespace Catch
// #included from: catch_resultinfo.h
#define TWOBLUECUBES_CATCH_RESULTINFO_H_INCLUDED
#include <string>
// #included from: catch_result_type.h
#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
namespace Catch {
struct ResultWas { enum OfType {
Unknown = -1,
Ok = 0,
Info = 1,
Warning = 2,
FailureBit = 0x10,
ExpressionFailed = FailureBit | 1,
ExplicitFailure = FailureBit | 2,
Exception = 0x100 | FailureBit,
ThrewException = Exception | 1,
DidntThrowException = Exception | 2
}; };
inline bool isOk( ResultWas::OfType resultType ) {
return ( resultType & ResultWas::FailureBit ) == 0;
}
struct ResultAction { enum Value {
None,
Failed = 1, // Failure - but no debug break if Debug bit not set
Debug = 2, // If this bit is set, invoke the debugger
Abort = 4 // Test run should abort
}; };
}
namespace Catch {
struct ResultData
{
ResultData() : resultType( ResultWas::Unknown ) {}
std::string macroName;
SourceLineInfo lineInfo;
std::string capturedExpression;
std::string reconstructedExpression;
std::string message;
ResultWas::OfType resultType;
};
class ResultInfo {
public:
ResultInfo();
ResultInfo( const ResultData& data );
~ResultInfo();
bool ok() const;
ResultWas::OfType getResultType() const;
bool hasExpression() const;
bool hasMessage() const;
std::string getExpression() const;
bool hasExpandedExpression() const;
std::string getExpandedExpression() const;
std::string getMessage() const;
std::string getFilename() const;
std::size_t getLine() const;
std::string getTestMacroName() const;
protected:
ResultData m_data;
};
} // end namespace Catch
// #included from: catch_evaluate.hpp
#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
namespace Catch {
namespace Internal {
enum Operator {
IsEqualTo,
IsNotEqualTo,
IsLessThan,
IsGreaterThan,
IsLessThanOrEqualTo,
IsGreaterThanOrEqualTo
};
template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
// So the compare overloads can be operator agnostic we convey the operator as a template
// enum, which is used to specialise an Evaluator for doing the comparison.
template<typename T1, typename T2, Operator Op>
class Evaluator{};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsEqualTo> {
static bool evaluate( const T1& lhs, const T2& rhs) {
return const_cast<T1&>( lhs ) == const_cast<T2&>( rhs );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsNotEqualTo> {
static bool evaluate( const T1& lhs, const T2& rhs ) {
return const_cast<T1&>( lhs ) != const_cast<T2&>( rhs );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsLessThan> {
static bool evaluate( const T1& lhs, const T2& rhs ) {
return const_cast<T1&>( lhs ) < const_cast<T2&>( rhs );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsGreaterThan> {
static bool evaluate( const T1& lhs, const T2& rhs ) {
return const_cast<T1&>( lhs ) > const_cast<T2&>( rhs );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
static bool evaluate( const T1& lhs, const T2& rhs ) {
return const_cast<T1&>( lhs ) >= const_cast<T2&>( rhs );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
static bool evaluate( const T1& lhs, const T2& rhs ) {
return const_cast<T1&>( lhs ) <= const_cast<T2&>( rhs );
}
};
template<Operator Op, typename T1, typename T2>
bool applyEvaluator( const T1& lhs, const T2& rhs ) {
return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
}
// "base" overload
template<Operator Op, typename T1, typename T2>
bool compare( const T1& lhs, const T2& rhs ) {
return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
}
// unsigned X to int
template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
}
template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
}
template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
}
// unsigned X to long
template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
}
template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
}
template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
}
// int to unsigned X
template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
}
template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
}
template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
}
// long to unsigned X
template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
}
template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
}
template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
}
// pointer to long (when comparing against NULL)
template<Operator Op, typename T>
bool compare( long lhs, const T* rhs ) {
return Evaluator<const T*, const T*, Op>::evaluate( reinterpret_cast<const T*>( lhs ), rhs );
}
template<Operator Op, typename T>
bool compare( long lhs, T* rhs ) {
return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
}
template<Operator Op, typename T>
bool compare( const T* lhs, long rhs ) {
return Evaluator<const T*, const T*, Op>::evaluate( lhs, reinterpret_cast<const T*>( rhs ) );
}
template<Operator Op, typename T>
bool compare( T* lhs, long rhs ) {
return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
}
// pointer to int (when comparing against NULL)
template<Operator Op, typename T>
bool compare( int lhs, const T* rhs ) {
return Evaluator<const T*, const T*, Op>::evaluate( reinterpret_cast<const T*>( lhs ), rhs );
}
template<Operator Op, typename T>
bool compare( int lhs, T* rhs ) {
return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
}
template<Operator Op, typename T>
bool compare( const T* lhs, int rhs ) {
return Evaluator<const T*, const T*, Op>::evaluate( lhs, reinterpret_cast<const T*>( rhs ) );
}
template<Operator Op, typename T>
bool compare( T* lhs, int rhs ) {
return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
}
} // end of namespace Internal
} // end of namespace Catch
namespace Catch {
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
class ResultInfoBuilder {
public:
ResultInfoBuilder();
ResultInfoBuilder& setResultType( ResultWas::OfType result );
ResultInfoBuilder& setCapturedExpression( const std::string& capturedExpression );
ResultInfoBuilder& setIsFalse( bool isFalse );
ResultInfoBuilder& setMessage( const std::string& message );
ResultInfoBuilder& setLineInfo( const SourceLineInfo& lineInfo );
ResultInfoBuilder& setLhs( const std::string& lhs );
ResultInfoBuilder& setRhs( const std::string& rhs );
ResultInfoBuilder& setOp( const std::string& op );
ResultInfoBuilder& setMacroName( const std::string& macroName );
std::string reconstructExpression() const;
ResultInfo build() const;
// Disable attempts to use || and && in expressions (without parantheses)
template<typename RhsT>
STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( const RhsT& );
template<typename RhsT>
STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( const RhsT& );
bool getIsFalse() const {
return m_isFalse;
}
private:
ResultData m_data;
std::string m_lhs, m_rhs, m_op;
bool m_isFalse;
};
} // end namespace Catch
namespace Catch {
template<typename T>
class Expression {
void operator = ( const Expression& );
public:
Expression( ResultInfoBuilder& result, T lhs )
: m_result( result.setLhs( Catch::toString( lhs ) ) ),
m_lhs( lhs )
{}
template<typename RhsT>
ResultInfoBuilder& operator == ( const RhsT& rhs ) {
return captureExpression<Internal::IsEqualTo>( rhs );
}
template<typename RhsT>
ResultInfoBuilder& operator != ( const RhsT& rhs ) {
return captureExpression<Internal::IsNotEqualTo>( rhs );
}
template<typename RhsT>
ResultInfoBuilder& operator < ( const RhsT& rhs ) {
return captureExpression<Internal::IsLessThan>( rhs );
}
template<typename RhsT>
ResultInfoBuilder& operator > ( const RhsT& rhs ) {
return captureExpression<Internal::IsGreaterThan>( rhs );
}
template<typename RhsT>
ResultInfoBuilder& operator <= ( const RhsT& rhs ) {
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
}
template<typename RhsT>
ResultInfoBuilder& operator >= ( const RhsT& rhs ) {
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
}
ResultInfoBuilder& operator == ( bool rhs ) {
return captureExpression<Internal::IsEqualTo>( rhs );
}
ResultInfoBuilder& operator != ( bool rhs ) {
return captureExpression<Internal::IsNotEqualTo>( rhs );
}
operator ResultInfoBuilder& () {
return m_result.setResultType( m_lhs ? ResultWas::Ok : ResultWas::ExpressionFailed );
}
template<typename RhsT>
STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( const RhsT& );
template<typename RhsT>
STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( const RhsT& );
private:
template<Internal::Operator Op, typename RhsT>
ResultInfoBuilder& captureExpression( const RhsT& rhs ) {
return m_result
.setResultType( Internal::compare<Op>( m_lhs, rhs ) ? ResultWas::Ok : ResultWas::ExpressionFailed )
.setRhs( Catch::toString( rhs ) )
.setOp( Internal::OperatorTraits<Op>::getName() );
}
private:
ResultInfoBuilder& m_result;
T m_lhs;
};
} // end namespace Catch
#include <sstream>
namespace Catch {
class ExpressionBuilder {
public:
ExpressionBuilder( const SourceLineInfo& lineInfo,
const char* macroName,
const char* expr = "",
bool isFalse = false )
: m_messageStream()
{
m_result
.setCapturedExpression( expr )
.setIsFalse( isFalse )
.setLineInfo( lineInfo )
.setMacroName( macroName );
}
template<typename T>
Expression<const T&> operator->* ( const T & operand ) {
Expression<const T&> expr( m_result, operand );
return expr;
}
Expression<bool> operator->* ( bool value ) {
Expression<bool> expr( m_result, value );
return expr;
}
template<typename T>
ExpressionBuilder& operator << ( const T & value ) {
m_messageStream << Catch::toString( value );
return *this;
}
template<typename MatcherT, typename ArgT>
ExpressionBuilder& acceptMatcher( const MatcherT& matcher,
const ArgT& arg,
const std::string& matcherCallAsString ) {
std::string matcherAsString = matcher.toString();
if( matcherAsString == "{?}" )
matcherAsString = matcherCallAsString;
m_result
.setLhs( Catch::toString( arg ) )
.setRhs( matcherAsString )
.setOp( "matches" )
.setResultType( matcher.match( arg ) ? ResultWas::Ok : ResultWas::ExpressionFailed );
return *this;
}
template<typename MatcherT, typename ArgT>
ExpressionBuilder& acceptMatcher( const MatcherT& matcher,
ArgT* arg,
const std::string& matcherCallAsString ) {
std::string matcherAsString = matcher.toString();
if( matcherAsString == "{?}" )
matcherAsString = matcherCallAsString;
m_result
.setLhs( Catch::toString( arg ) )
.setRhs( matcherAsString )
.setOp( "matches" )
.setResultType( matcher.match( arg ) ? ResultWas::Ok : ResultWas::ExpressionFailed );
return *this;
}
ExpressionBuilder& setResultType( ResultWas::OfType resultType ) {
m_result.setResultType( resultType );
return *this;
}
operator ResultInfoBuilder&() {
m_result.setMessage( m_messageStream.str() );
return m_result;
}
private:
ResultInfoBuilder m_result;
std::ostringstream m_messageStream;
};
} // end namespace Catch
// #included from: catch_interfaces_capture.h
#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
#include <string>
// #included from: catch_totals.hpp
#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
#include <cstddef>
namespace Catch {
struct Counts {
Counts() : passed( 0 ), failed( 0 ) {}
Counts operator - ( const Counts& other ) const {
Counts diff;
diff.passed = passed - other.passed;
diff.failed = failed - other.failed;
return diff;
}
Counts& operator += ( const Counts& other ) {
passed += other.passed;
failed += other.failed;
return *this;
}
std::size_t total() const {
return passed + failed;
}
std::size_t passed;
std::size_t failed;
};
struct Totals {
Totals operator - ( const Totals& other ) const {
Totals diff;
diff.assertions = assertions - other.assertions;
diff.testCases = testCases - other.testCases;
return diff;
}
Totals delta( const Totals& prevTotals ) const {
Totals diff = *this - prevTotals;
if( diff.assertions.failed > 0 )
++diff.testCases.failed;
else
++diff.testCases.passed;
return diff;
}
Totals& operator += ( const Totals& other ) {
assertions += other.assertions;
testCases += other.testCases;
return *this;
}
Counts assertions;
Counts testCases;
};
}
namespace Catch {
class TestCaseInfo;
class ScopedInfo;
class ResultInfoBuilder;
class ResultInfo;
struct IResultCapture {
virtual ~IResultCapture();
virtual void testEnded( const ResultInfo& result ) = 0;
virtual bool sectionStarted( const std::string& name,
const std::string& description,
const SourceLineInfo& lineInfo,
Counts& assertions ) = 0;
virtual void sectionEnded( const std::string& name, const Counts& assertions ) = 0;
virtual void pushScopedInfo( ScopedInfo* scopedInfo ) = 0;
virtual void popScopedInfo( ScopedInfo* scopedInfo ) = 0;
virtual bool shouldDebugBreak() const = 0;
virtual ResultAction::Value acceptResult( bool result ) = 0;
virtual ResultAction::Value acceptResult( ResultWas::OfType result ) = 0;
virtual ResultAction::Value acceptExpression( const ResultInfoBuilder& resultInfo ) = 0;
virtual void acceptMessage( const std::string& msg ) = 0;
virtual std::string getCurrentTestName() const = 0;
virtual const ResultInfo* getLastResult() const = 0;
};
}
// #included from: catch_debugger.hpp
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
#include <iostream>
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
#define CATCH_PLATFORM_MAC
#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#define CATCH_PLATFORM_IPHONE
#elif defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define CATCH_PLATFORM_WINDOWS
#endif
#ifdef CATCH_PLATFORM_MAC
#include <assert.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>
namespace Catch{
// The following function is taken directly from the following technical note:
// http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
inline bool isDebuggerActive(){
int junk;
int mib[4];
struct kinfo_proc info;
size_t size;
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
// Call sysctl.
size = sizeof(info);
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
assert(junk == 0);
// We're being debugged if the P_TRACED flag is set.
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}
}
// The following code snippet taken from:
// http://cocoawithlove.com/2008/03/break-into-debugger.html
#ifdef DEBUG
#if defined(__ppc64__) || defined(__ppc__)
#define BreakIntoDebugger() \
if( Catch::isDebuggerActive() ) { \
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
: : : "memory","r0","r3","r4" ); \
}
#else
#define BreakIntoDebugger() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
#endif
#else
inline void BreakIntoDebugger(){}
#endif
#elif defined(_MSC_VER)
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
#define BreakIntoDebugger() if (IsDebuggerPresent() ) { __debugbreak(); }
inline bool isDebuggerActive() {
return IsDebuggerPresent() != 0;
}
#elif defined(__MINGW32__)
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
extern "C" __declspec(dllimport) void __stdcall DebugBreak();
#define BreakIntoDebugger() if (IsDebuggerPresent() ) { DebugBreak(); }
inline bool isDebuggerActive() {
return IsDebuggerPresent() != 0;
}
#else
inline void BreakIntoDebugger(){}
inline bool isDebuggerActive() { return false; }
#endif
#ifdef CATCH_PLATFORM_WINDOWS
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
inline void writeToDebugConsole( const std::string& text ) {
::OutputDebugStringA( text.c_str() );
}
#else
inline void writeToDebugConsole( const std::string& text ) {
// !TBD: Need a version for Mac/ XCode and other IDEs
std::cout << text;
}
#endif // CATCH_PLATFORM_WINDOWS
#include <ostream>
namespace Catch {
struct TestFailureException{};
class ScopedInfo {
public:
ScopedInfo() : m_oss() {
getCurrentContext().getResultCapture().pushScopedInfo( this );
}
~ScopedInfo() {
getCurrentContext().getResultCapture().popScopedInfo( this );
}
template<typename T>
ScopedInfo& operator << ( const T& value ) {
m_oss << value;
return *this;
}
ResultInfo getInfo () const {
return ResultInfoBuilder()
.setResultType( ResultWas::Info )
.setMessage( m_oss.str() )
.setMacroName( "SCOPED_INFO" )
.build();
}
private:
std::ostringstream m_oss;
};
// This is just here to avoid compiler warnings with macro constants
inline bool isTrue( bool value ){ return value; }
} // end namespace Catch
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \
if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) { \
if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \
if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \
if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \
if( Catch::isTrue( false ) ){ bool this_is_here_to_invoke_warnings = ( originalExpr ); Catch::isTrue( this_is_here_to_invoke_warnings ); } \
}
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( expr, isFalse, stopOnFailure, macroName ) \
do { try { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr, isFalse )->*expr ), stopOnFailure, expr ); \
} catch( Catch::TestFailureException& ) { \
throw; \
} catch( ... ) { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getRegistryHub().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, expr ); \
throw; \
} } while( Catch::isTrue( false ) )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( expr, isFalse, stopOnFailure, macroName ) \
INTERNAL_CATCH_TEST( expr, isFalse, stopOnFailure, macroName ); \
if( Catch::getCurrentContext().getResultCapture().getLastResult()->ok() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ELSE( expr, isFalse, stopOnFailure, macroName ) \
INTERNAL_CATCH_TEST( expr, isFalse, stopOnFailure, macroName ); \
if( !Catch::getCurrentContext().getResultCapture().getLastResult()->ok() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( expr, stopOnFailure, macroName ) \
try { \
expr; \
INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::Ok ), stopOnFailure, false ); \
} \
catch( ... ) { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getRegistryHub().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \
}
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \
try { \
if( Catch::getCurrentContext().getConfig()->allowThrows() ) { \
expr; \
INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::DidntThrowException ), stopOnFailure, false ); \
} \
} \
catch( Catch::TestFailureException& ) { \
throw; \
} \
catch( exceptionType ) { \
INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ).setResultType( Catch::ResultWas::Ok ), stopOnFailure, false ); \
}
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, stopOnFailure, macroName ) \
INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \
catch( ... ) { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getRegistryHub().getExceptionTranslatorRegistry() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \
}
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \
Catch::getCurrentContext().getResultCapture().acceptExpression( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName ) << reason ).setResultType( resultType ) );
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_SCOPED_INFO( log ) \
Catch::ScopedInfo INTERNAL_CATCH_UNIQUE_NAME( info ); \
INTERNAL_CATCH_UNIQUE_NAME( info ) << log
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CHECK_THAT( arg, matcher, stopOnFailure, macroName ) \
do { try { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher, false ).acceptMatcher( ::Catch::Matchers::matcher, arg, #matcher ) ), stopOnFailure, false ); \
} catch( Catch::TestFailureException& ) { \
throw; \
} catch( ... ) { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher ) << Catch::getRegistryHub().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, false ); \
throw; \
}}while( Catch::isTrue( false ) )
// #included from: internal/catch_section.hpp
#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
#include <string>
namespace Catch {
class Section {
public:
Section( const std::string& name,
const std::string& description,
const SourceLineInfo& lineInfo )
: m_name( name ),
m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( name, description, lineInfo, m_assertions ) )
{}
~Section() {
if( m_sectionIncluded )
getCurrentContext().getResultCapture().sectionEnded( m_name, m_assertions );
}
// This indicates whether the section should be executed or not
operator bool() {
return m_sectionIncluded;
}
private:
std::string m_name;
Counts m_assertions;
bool m_sectionIncluded;
};
} // end namespace Catch
#define INTERNAL_CATCH_SECTION( name, desc ) \
if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( name, desc, CATCH_INTERNAL_LINEINFO ) )
// #included from: internal/catch_generators.hpp
#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
#include <iterator>
#include <vector>
#include <string>
#include <stdlib.h>
namespace Catch {
template<typename T>
struct IGenerator {
virtual ~IGenerator() {}
virtual T getValue( std::size_t index ) const = 0;
virtual std::size_t size () const = 0;
};
template<typename T>
class BetweenGenerator : public IGenerator<T> {
public:
BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
virtual T getValue( std::size_t index ) const {
return m_from+static_cast<T>( index );
}
virtual std::size_t size() const {
return static_cast<std::size_t>( 1+m_to-m_from );
}
private:
T m_from;
T m_to;
};
template<typename T>
class ValuesGenerator : public IGenerator<T> {
public:
ValuesGenerator(){}
void add( T value ) {
m_values.push_back( value );
}
virtual T getValue( std::size_t index ) const {
return m_values[index];
}
virtual std::size_t size() const {
return m_values.size();
}
private:
std::vector<T> m_values;
};
template<typename T>
class CompositeGenerator {
public:
CompositeGenerator() : m_totalSize( 0 ) {}
// *** Move semantics, similar to auto_ptr ***
CompositeGenerator( CompositeGenerator& other )
: m_fileInfo( other.m_fileInfo ),
m_totalSize( 0 )
{
move( other );
}
CompositeGenerator& setFileInfo( const char* fileInfo ) {
m_fileInfo = fileInfo;
return *this;
}
~CompositeGenerator() {
deleteAll( m_composed );
}
operator T () const {
size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
for( size_t index = 0; it != itEnd; ++it )
{
const IGenerator<T>* generator = *it;
if( overallIndex >= index && overallIndex < index + generator->size() )
{
return generator->getValue( overallIndex-index );
}
index += generator->size();
}
CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
}
void add( const IGenerator<T>* generator ) {
m_totalSize += generator->size();
m_composed.push_back( generator );
}
CompositeGenerator& then( CompositeGenerator& other ) {
move( other );
return *this;
}
CompositeGenerator& then( T value ) {
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
valuesGen->add( value );
add( valuesGen );
return *this;
}
private:
void move( CompositeGenerator& other ) {
std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
m_totalSize += other.m_totalSize;
other.m_composed.clear();
}
std::vector<const IGenerator<T>*> m_composed;
std::string m_fileInfo;
size_t m_totalSize;
};
namespace Generators
{
template<typename T>
CompositeGenerator<T> between( T from, T to ) {
CompositeGenerator<T> generators;
generators.add( new BetweenGenerator<T>( from, to ) );
return generators;
}
template<typename T>
CompositeGenerator<T> values( T val1, T val2 ) {
CompositeGenerator<T> generators;
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
valuesGen->add( val1 );
valuesGen->add( val2 );
generators.add( valuesGen );
return generators;
}
template<typename T>
CompositeGenerator<T> values( T val1, T val2, T val3 ){
CompositeGenerator<T> generators;
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
valuesGen->add( val1 );
valuesGen->add( val2 );
valuesGen->add( val3 );
generators.add( valuesGen );
return generators;
}
template<typename T>
CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
CompositeGenerator<T> generators;
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
valuesGen->add( val1 );
valuesGen->add( val2 );
valuesGen->add( val3 );
valuesGen->add( val4 );
generators.add( valuesGen );
return generators;
}
} // end namespace Generators
using namespace Generators;
} // end namespace Catch
#define INTERNAL_CATCH_LINESTR2( line ) #line
#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
// #included from: internal/catch_interfaces_exception.h
#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
#include <string>
// #included from: catch_interfaces_registry_hub.h
#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
// #included from: catch_interfaces_reporter.h
#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
// #included from: catch_config.hpp
#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
// #included from: catch_test_spec.h
#define TWOBLUECUBES_CATCH_TEST_SPEC_H_INCLUDED
// #included from: catch_test_case_info.h
#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
#include <string>
#include <set>
namespace Catch {
struct ITestCase;
class TestCaseInfo {
public:
TestCaseInfo();
TestCaseInfo( ITestCase* testCase,
const char* name,
const char* description,
const SourceLineInfo& lineInfo );
TestCaseInfo( const TestCaseInfo& other, const std::string& name );
TestCaseInfo( const TestCaseInfo& other );
void invoke() const;
const std::string& getName() const;
const std::string& getDescription() const;
const SourceLineInfo& getLineInfo() const;
bool isHidden() const;
bool hasTag( const std::string& tag ) const;
bool matchesTags( const std::string& tagPattern ) const;
const std::set<std::string>& getTags() const;
void swap( TestCaseInfo& other );
bool operator == ( const TestCaseInfo& other ) const;
bool operator < ( const TestCaseInfo& other ) const;
TestCaseInfo& operator = ( const TestCaseInfo& other );
private:
Ptr<ITestCase> m_test;
std::string m_name;
std::string m_description;
std::set<std::string> m_tags;
SourceLineInfo m_lineInfo;
bool m_isHidden;
};
}
// #included from: catch_tags.hpp
#define TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED
#include <string>
#include <set>
#include <map>
#include <vector>
#ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded"
#endif
namespace Catch {
class TagParser {
public:
virtual ~TagParser();
void parse( const std::string& str ) {
std::size_t pos = 0;
while( pos < str.size() ) {
char c = str[pos];
if( c == '[' ) {
std::size_t end = str.find_first_of( ']', pos );
if( end != std::string::npos ) {
acceptTag( str.substr( pos+1, end-pos-1 ) );
pos = end+1;
}
else {
acceptChar( c );
pos++;
}
}
else {
acceptChar( c );
pos++;
}
}
endParse();
}
protected:
virtual void acceptTag( const std::string& tag ) = 0;
virtual void acceptChar( char c ) = 0;
virtual void endParse() {}
private:
};
class TagExtracter : public TagParser {
public:
TagExtracter( std::set<std::string>& tags )
: m_tags( tags )
{}
virtual ~TagExtracter();
void parse( std::string& description ) {
TagParser::parse( description );
description = m_remainder;
}
private:
virtual void acceptTag( const std::string& tag ) {
m_tags.insert( tag );
}
virtual void acceptChar( char c ) {
m_remainder += c;
}
// Suppress assignment operator to avoid warnings from MSVC saying that
// it can't be implicitly synthesized.
TagExtracter& operator=(const TagExtracter&);
std::set<std::string>& m_tags;
std::string m_remainder;
};
class Tag {
public:
Tag()
: m_isNegated( false )
{}
Tag( const std::string& name, bool isNegated )
: m_name( name ),
m_isNegated( isNegated )
{}
std::string getName() const {
return m_name;
}
bool isNegated() const {
return m_isNegated;
}
bool operator ! () const {
return m_name.empty();
}
private:
std::string m_name;
bool m_isNegated;
};
class TagSet {
typedef std::map<std::string, Tag> TagMap;
public:
void add( const Tag& tag ) {
m_tags.insert( std::make_pair( tag.getName(), tag ) );
}
bool empty() const {
return m_tags.empty();
}
bool matches( const std::set<std::string>& tags ) const {
TagMap::const_iterator it = m_tags.begin();
TagMap::const_iterator itEnd = m_tags.end();
for(; it != itEnd; ++it ) {
bool found = tags.find( it->first ) != tags.end();
if( found == it->second.isNegated() )
return false;
}
return true;
}
private:
TagMap m_tags;
};
class TagExpression {
public:
bool matches( const std::set<std::string>& tags ) const {
std::vector<TagSet>::const_iterator it = m_tagSets.begin();
std::vector<TagSet>::const_iterator itEnd = m_tagSets.end();
for(; it != itEnd; ++it )
if( it->matches( tags ) )
return true;
return false;
}
private:
friend class TagExpressionParser;
std::vector<TagSet> m_tagSets;
};
class TagExpressionParser : public TagParser {
public:
TagExpressionParser( TagExpression& exp )
: m_isNegated( false ),
m_exp( exp )
{}
~TagExpressionParser();
private:
virtual void acceptTag( const std::string& tag ) {
m_currentTagSet.add( Tag( tag, m_isNegated ) );
m_isNegated = false;
}
virtual void acceptChar( char c ) {
switch( c ) {
case '~':
m_isNegated = true;
break;
case ',':
m_exp.m_tagSets.push_back( m_currentTagSet );
break;
}
}
virtual void endParse() {
if( !m_currentTagSet.empty() )
m_exp.m_tagSets.push_back( m_currentTagSet );
}
// Suppress assignment operator to avoid warnings from MSVC saying that
// it can't be implicitly synthesized.
TagExpressionParser& operator=(const TagExpressionParser&);
bool m_isNegated;
TagSet m_currentTagSet;
TagExpression& m_exp;
};
} // end namespace Catch
#include <string>
#include <vector>
namespace Catch {
struct IfFilterMatches{ enum DoWhat {
AutoDetectBehaviour,
IncludeTests,
ExcludeTests
}; };
class TestCaseFilter {
enum WildcardPosition {
NoWildcard = 0,
WildcardAtStart = 1,
WildcardAtEnd = 2,
WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
};
public:
TestCaseFilter( const std::string& testSpec, IfFilterMatches::DoWhat matchBehaviour = IfFilterMatches::AutoDetectBehaviour )
: m_stringToMatch( testSpec ),
m_filterType( matchBehaviour ),
m_wildcardPosition( NoWildcard )
{
if( m_filterType == IfFilterMatches::AutoDetectBehaviour ) {
if( startsWith( m_stringToMatch, "exclude:" ) ) {
m_stringToMatch = m_stringToMatch.substr( 8 );
m_filterType = IfFilterMatches::ExcludeTests;
}
else if( startsWith( m_stringToMatch, "~" ) ) {
m_stringToMatch = m_stringToMatch.substr( 1 );
m_filterType = IfFilterMatches::ExcludeTests;
}
else {
m_filterType = IfFilterMatches::IncludeTests;
}
}
if( m_stringToMatch[0] == '*' ) {
m_stringToMatch = m_stringToMatch.substr( 1 );
m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtStart );
}
if( m_stringToMatch[m_stringToMatch.size()-1] == '*' ) {
m_stringToMatch = m_stringToMatch.substr( 0, m_stringToMatch.size()-1 );
m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtEnd );
}
}
IfFilterMatches::DoWhat getFilterType() const {
return m_filterType;
}
bool shouldInclude( const TestCaseInfo& testCase ) const {
return isMatch( testCase ) == (m_filterType == IfFilterMatches::IncludeTests);
}
private:
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif
bool isMatch( const TestCaseInfo& testCase ) const {
const std::string& name = testCase.getName();
switch( m_wildcardPosition ) {
case NoWildcard:
return m_stringToMatch == name;
case WildcardAtStart:
return endsWith( name, m_stringToMatch );
case WildcardAtEnd:
return startsWith( name, m_stringToMatch );
case WildcardAtBothEnds:
return contains( name, m_stringToMatch );
}
throw std::logic_error( "Unhandled wildcard type" );
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
std::string m_stringToMatch;
IfFilterMatches::DoWhat m_filterType;
WildcardPosition m_wildcardPosition;
};
class TestCaseFilters {
public:
TestCaseFilters( const std::string& name ) : m_name( name ) {}
std::string getName() const {
return m_name;
}
void addFilter( const TestCaseFilter& filter ) {
if( filter.getFilterType() == IfFilterMatches::ExcludeTests )
m_exclusionFilters.push_back( filter );
else
m_inclusionFilters.push_back( filter );
}
void addTags( const std::string& tagPattern ) {
TagExpression exp;
TagExpressionParser( exp ).parse( tagPattern );
m_tagExpressions.push_back( exp );
}
bool shouldInclude( const TestCaseInfo& testCase ) const {
if( !m_tagExpressions.empty() ) {
std::vector<TagExpression>::const_iterator it = m_tagExpressions.begin();
std::vector<TagExpression>::const_iterator itEnd = m_tagExpressions.end();
for(; it != itEnd; ++it )
if( it->matches( testCase.getTags() ) )
break;
if( it == itEnd )
return false;
}
if( !m_inclusionFilters.empty() ) {
std::vector<TestCaseFilter>::const_iterator it = m_inclusionFilters.begin();
std::vector<TestCaseFilter>::const_iterator itEnd = m_inclusionFilters.end();
for(; it != itEnd; ++it )
if( it->shouldInclude( testCase ) )
break;
if( it == itEnd )
return false;
}
else if( m_exclusionFilters.empty() && m_tagExpressions.empty() ) {
return !testCase.isHidden();
}
std::vector<TestCaseFilter>::const_iterator it = m_exclusionFilters.begin();
std::vector<TestCaseFilter>::const_iterator itEnd = m_exclusionFilters.end();
for(; it != itEnd; ++it )
if( !it->shouldInclude( testCase ) )
return false;
return true;
}
private:
std::vector<TagExpression> m_tagExpressions;
std::vector<TestCaseFilter> m_inclusionFilters;
std::vector<TestCaseFilter> m_exclusionFilters;
std::string m_name;
};
}
// #included from: catch_interfaces_config.h
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
namespace Catch {
struct IConfig {
virtual ~IConfig();
virtual bool allowThrows() const = 0;
};
}
// #included from: catch_stream.hpp
#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
// #included from: catch_streambuf.h
#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
#include <streambuf>
namespace Catch {
class StreamBufBase : public std::streambuf {
public:
virtual ~StreamBufBase();
};
}
#include <stdexcept>
#include <cstdio>
namespace Catch {
template<typename WriterF, size_t bufferSize=256>
class StreamBufImpl : public StreamBufBase {
char data[bufferSize];
WriterF m_writer;
public:
StreamBufImpl() {
setp( data, data + sizeof(data) );
}
~StreamBufImpl() {
sync();
}
private:
int overflow( int c ) {
sync();
if( c != EOF ) {
if( pbase() == epptr() )
m_writer( std::string( 1, static_cast<char>( c ) ) );
else
sputc( static_cast<char>( c ) );
}
return 0;
}
int sync() {
if( pbase() != pptr() ) {
m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
setp( pbase(), epptr() );
}
return 0;
}
};
///////////////////////////////////////////////////////////////////////////
struct OutputDebugWriter {
void operator()( const std::string &str ) {
writeToDebugConsole( str );
}
};
class Stream {
public:
Stream()
: streamBuf( NULL ), isOwned( false )
{}
Stream( std::streambuf* _streamBuf, bool _isOwned )
: streamBuf( _streamBuf ), isOwned( _isOwned )
{}
void release() {
if( isOwned ) {
delete streamBuf;
streamBuf = NULL;
isOwned = false;
}
}
std::streambuf* streamBuf;
private:
bool isOwned;
};
}
#include <memory>
#include <vector>
#include <string>
#include <iostream>
namespace Catch {
struct Include { enum WhichResults {
FailedOnly,
SuccessfulResults
}; };
struct List{ enum What {
None = 0,
Reports = 1,
Tests = 2,
All = 3,
TestNames = 6,
WhatMask = 0xf,
AsText = 0x10,
AsXml = 0x20,
AsMask = 0xf0
}; };
struct ConfigData {
struct WarnAbout { enum What {
Nothing = 0x00,
NoAssertions = 0x01
}; };
ConfigData()
: listSpec( List::None ),
shouldDebugBreak( false ),
includeWhichResults( Include::FailedOnly ),
cutoff( -1 ),
allowThrows( true ),
warnings( WarnAbout::Nothing )
{}
std::string reporter;
std::string outputFilename;
List::What listSpec;
std::vector<TestCaseFilters> filters;
bool shouldDebugBreak;
std::string stream;
Include::WhichResults includeWhichResults;
std::string name;
int cutoff;
bool allowThrows;
WarnAbout::What warnings;
};
class Config : public IConfig {
private:
Config( const Config& other );
Config& operator = ( const Config& other );
virtual void dummy();
public:
Config()
: m_os( std::cout.rdbuf() )
{}
Config( const ConfigData& data )
: m_data( data ),
m_os( std::cout.rdbuf() )
{}
virtual ~Config() {
m_os.rdbuf( std::cout.rdbuf() );
m_stream.release();
}
void setFilename( const std::string& filename ) {
m_data.outputFilename = filename;
}
List::What getListSpec( void ) const {
return m_data.listSpec;
}
const std::string& getFilename() const {
return m_data.outputFilename ;
}
List::What listWhat() const {
return static_cast<List::What>( m_data.listSpec & List::WhatMask );
}
List::What listAs() const {
return static_cast<List::What>( m_data.listSpec & List::AsMask );
}
std::string getName() const {
return m_data.name;
}
bool shouldDebugBreak() const {
return m_data.shouldDebugBreak;
}
virtual std::ostream& stream() const {
return m_os;
}
void setStreamBuf( std::streambuf* buf ) {
m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
}
void useStream( const std::string& streamName ) {
Stream stream = createStream( streamName );
setStreamBuf( stream.streamBuf );
m_stream.release();
m_stream = stream;
}
void addTestSpec( const std::string& testSpec ) {
TestCaseFilters filters( testSpec );
filters.addFilter( TestCaseFilter( testSpec ) );
m_data.filters.push_back( filters );
}
virtual bool includeSuccessfulResults() const {
return m_data.includeWhichResults == Include::SuccessfulResults;
}
int getCutoff() const {
return m_data.cutoff;
}
virtual bool allowThrows() const {
return m_data.allowThrows;
}
const ConfigData& data() const {
return m_data;
}
ConfigData& data() {
return m_data;
}
private:
ConfigData m_data;
// !TBD Move these out of here
Stream m_stream;
mutable std::ostream m_os;
};
} // end namespace Catch
#include <string>
#include <ostream>
#include <map>
namespace Catch
{
struct ReporterConfig
{
ReporterConfig( const std::string& _name,
std::ostream& _stream,
bool _includeSuccessfulResults,
const ConfigData& _fullConfig )
: name( _name ),
stream( _stream ),
includeSuccessfulResults( _includeSuccessfulResults ),
fullConfig( _fullConfig )
{}
ReporterConfig( const ReporterConfig& other )
: name( other.name ),
stream( other.stream ),
includeSuccessfulResults( other.includeSuccessfulResults ),
fullConfig( other.fullConfig )
{}
std::string name;
std::ostream& stream;
bool includeSuccessfulResults;
ConfigData fullConfig;
private:
void operator=(const ReporterConfig&);
};
class TestCaseInfo;
class ResultInfo;
struct IReporter : IShared {
virtual ~IReporter();
virtual bool shouldRedirectStdout() const = 0;
virtual void StartTesting() = 0;
virtual void EndTesting( const Totals& totals ) = 0;
virtual void StartGroup( const std::string& groupName ) = 0;
virtual void EndGroup( const std::string& groupName, const Totals& totals ) = 0;
virtual void StartSection( const std::string& sectionName, const std::string& description ) = 0;
virtual void NoAssertionsInSection( const std::string& sectionName ) = 0;
virtual void NoAssertionsInTestCase( const std::string& testName ) = 0;
virtual void EndSection( const std::string& sectionName, const Counts& assertions ) = 0;
virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0;
virtual void Aborted() = 0;
virtual void EndTestCase( const TestCaseInfo& testInfo, const Totals& totals, const std::string& stdOut, const std::string& stdErr ) = 0;
virtual void Result( const ResultInfo& result ) = 0;
};
struct IReporterFactory {
virtual ~IReporterFactory();
virtual IReporter* create( const ReporterConfig& config ) const = 0;
virtual std::string getDescription() const = 0;
};
struct IReporterRegistry {
typedef std::map<std::string, IReporterFactory*> FactoryMap;
virtual ~IReporterRegistry();
virtual IReporter* create( const std::string& name, const ReporterConfig& config ) const = 0;
virtual const FactoryMap& getFactories() const = 0;
};
inline std::string trim( const std::string& str ) {
std::string::size_type start = str.find_first_not_of( "\n\r\t " );
std::string::size_type end = str.find_last_not_of( "\n\r\t " );
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
}
}
#include <vector>
namespace Catch {
class TestCaseInfo;
struct ITestCaseRegistry;
struct IExceptionTranslatorRegistry;
struct IExceptionTranslator;
struct IRegistryHub {
virtual ~IRegistryHub();
virtual const IReporterRegistry& getReporterRegistry() const = 0;
virtual const ITestCaseRegistry& getTestCaseRegistry() const = 0;
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
};
struct IMutableRegistryHub {
virtual ~IMutableRegistryHub();
virtual void registerReporter( const std::string& name, IReporterFactory* factory ) = 0;
virtual void registerTest( const TestCaseInfo& testInfo ) = 0;
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
};
IRegistryHub& getRegistryHub();
IMutableRegistryHub& getMutableRegistryHub();
void cleanUp();
}
namespace Catch {
typedef std::string(*exceptionTranslateFunction)();
struct IExceptionTranslator {
virtual ~IExceptionTranslator();
virtual std::string translate() const = 0;
};
struct IExceptionTranslatorRegistry {
virtual ~IExceptionTranslatorRegistry();
virtual std::string translateActiveException() const = 0;
};
class ExceptionTranslatorRegistrar {
template<typename T>
class ExceptionTranslator : public IExceptionTranslator {
public:
ExceptionTranslator( std::string(*translateFunction)( T& ) )
: m_translateFunction( translateFunction )
{}
virtual std::string translate() const {
try {
throw;
}
catch( T& ex ) {
return m_translateFunction( ex );
}
}
protected:
std::string(*m_translateFunction)( T& );
};
public:
template<typename T>
ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
getMutableRegistryHub().registerTranslator
( new ExceptionTranslator<T>( translateFunction ) );
}
};
}
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
// #included from: internal/catch_approx.hpp
#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
#include <cmath>
#include <limits>
namespace Catch {
namespace Detail {
class Approx {
public:
explicit Approx ( double value )
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
m_scale( 1.0 ),
m_value( value )
{}
Approx( const Approx& other )
: m_epsilon( other.m_epsilon ),
m_scale( other.m_scale ),
m_value( other.m_value )
{}
static Approx custom() {
return Approx( 0 );
}
Approx operator()( double value ) {
Approx approx( value );
approx.epsilon( m_epsilon );
approx.scale( m_scale );
return approx;
}
friend bool operator == ( double lhs, const Approx& rhs ) {
// Thanks to Richard Harris for his help refining this formula
return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
}
friend bool operator == ( const Approx& lhs, double rhs ) {
return operator==( rhs, lhs );
}
friend bool operator != ( double lhs, const Approx& rhs ) {
return !operator==( lhs, rhs );
}
friend bool operator != ( const Approx& lhs, double rhs ) {
return !operator==( rhs, lhs );
}
Approx& epsilon( double newEpsilon ) {
m_epsilon = newEpsilon;
return *this;
}
Approx& scale( double newScale ) {
m_scale = newScale;
return *this;
}
std::string toString() const {
std::ostringstream oss;
oss << "Approx( " << m_value << " )";
return oss.str();
}
private:
double m_epsilon;
double m_scale;
double m_value;
};
}
template<>
inline std::string toString<Detail::Approx>( const Detail::Approx& value ) {
return value.toString();
}
} // end namespace Catch
// #included from: internal/catch_matchers.hpp
#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
namespace Catch {
namespace Matchers {
namespace Impl {
template<typename ExpressionT>
struct Matcher : SharedImpl<IShared>
{
virtual ~Matcher() {}
virtual Ptr<Matcher> clone() const = 0;
virtual bool match( const ExpressionT& expr ) const = 0;
virtual std::string toString() const = 0;
};
template<typename DerivedT, typename ExpressionT>
struct MatcherImpl : Matcher<ExpressionT> {
virtual Ptr<Matcher<ExpressionT> > clone() const {
return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<const DerivedT&>( *this ) ) );
}
};
namespace Generic {
template<typename ExpressionT>
class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
public:
AllOf() {}
AllOf( const AllOf& other ) : m_matchers( other.m_matchers ) {}
AllOf& add( const Matcher<ExpressionT>& matcher ) {
m_matchers.push_back( matcher.clone() );
return *this;
}
virtual bool match( const ExpressionT& expr ) const
{
for( std::size_t i = 0; i < m_matchers.size(); ++i )
if( !m_matchers[i]->match( expr ) )
return false;
return true;
}
virtual std::string toString() const {
std::ostringstream oss;
oss << "( ";
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if( i != 0 )
oss << " and ";
oss << m_matchers[i]->toString();
}
oss << " )";
return oss.str();
}
private:
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
};
template<typename ExpressionT>
class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
public:
AnyOf() {}
AnyOf( const AnyOf& other ) : m_matchers( other.m_matchers ) {}
AnyOf& add( const Matcher<ExpressionT>& matcher ) {
m_matchers.push_back( matcher.clone() );
return *this;
}
virtual bool match( const ExpressionT& expr ) const
{
for( std::size_t i = 0; i < m_matchers.size(); ++i )
if( m_matchers[i]->match( expr ) )
return true;
return false;
}
virtual std::string toString() const {
std::ostringstream oss;
oss << "( ";
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if( i != 0 )
oss << " or ";
oss << m_matchers[i]->toString();
}
oss << " )";
return oss.str();
}
private:
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
};
}
namespace StdString {
struct Equals : MatcherImpl<Equals, std::string> {
Equals( const std::string& str ) : m_str( str ){}
Equals( const Equals& other ) : m_str( other.m_str ){}
virtual ~Equals();
virtual bool match( const std::string& expr ) const {
return m_str == expr;
}
virtual std::string toString() const {
return "equals: \"" + m_str + "\"";
}
std::string m_str;
};
struct Contains : MatcherImpl<Contains, std::string> {
Contains( const std::string& substr ) : m_substr( substr ){}
Contains( const Contains& other ) : m_substr( other.m_substr ){}
virtual ~Contains();
virtual bool match( const std::string& expr ) const {
return expr.find( m_substr ) != std::string::npos;
}
virtual std::string toString() const {
return "contains: \"" + m_substr + "\"";
}
std::string m_substr;
};
struct StartsWith : MatcherImpl<StartsWith, std::string> {
StartsWith( const std::string& substr ) : m_substr( substr ){}
StartsWith( const StartsWith& other ) : m_substr( other.m_substr ){}
virtual ~StartsWith();
virtual bool match( const std::string& expr ) const {
return expr.find( m_substr ) == 0;
}
virtual std::string toString() const {
return "starts with: \"" + m_substr + "\"";
}
std::string m_substr;
};
struct EndsWith : MatcherImpl<EndsWith, std::string> {
EndsWith( const std::string& substr ) : m_substr( substr ){}
EndsWith( const EndsWith& other ) : m_substr( other.m_substr ){}
virtual ~EndsWith();
virtual bool match( const std::string& expr ) const {
return expr.find( m_substr ) == expr.size() - m_substr.size();
}
virtual std::string toString() const {
return "ends with: \"" + m_substr + "\"";
}
std::string m_substr;
};
} // namespace StdString
} // namespace Impl
// The following functions create the actual matcher objects.
// This allows the types to be inferred
template<typename ExpressionT>
inline Impl::Generic::AllOf<ExpressionT> AllOf( const Impl::Matcher<ExpressionT>& m1,
const Impl::Matcher<ExpressionT>& m2 ) {
return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
}
template<typename ExpressionT>
inline Impl::Generic::AllOf<ExpressionT> AllOf( const Impl::Matcher<ExpressionT>& m1,
const Impl::Matcher<ExpressionT>& m2,
const Impl::Matcher<ExpressionT>& m3 ) {
return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
}
template<typename ExpressionT>
inline Impl::Generic::AnyOf<ExpressionT> AnyOf( const Impl::Matcher<ExpressionT>& m1,
const Impl::Matcher<ExpressionT>& m2 ) {
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
}
template<typename ExpressionT>
inline Impl::Generic::AnyOf<ExpressionT> AnyOf( const Impl::Matcher<ExpressionT>& m1,
const Impl::Matcher<ExpressionT>& m2,
const Impl::Matcher<ExpressionT>& m3 ) {
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
}
inline Impl::StdString::Equals Equals( const std::string& str ){ return Impl::StdString::Equals( str ); }
inline Impl::StdString::Contains Contains( const std::string& substr ){ return Impl::StdString::Contains( substr ); }
inline Impl::StdString::StartsWith StartsWith( const std::string& substr ){ return Impl::StdString::StartsWith( substr ); }
inline Impl::StdString::EndsWith EndsWith( const std::string& substr ){ return Impl::StdString::EndsWith( substr ); }
} // namespace Matchers
using namespace Matchers;
} // namespace Catch
// These files are included here so the single_include script doesn't put them
// in the conditionally compiled sections
// #included from: internal/catch_interfaces_runner.h
#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
#include <string>
namespace Catch {
class TestCaseInfo;
struct IRunner {
virtual ~IRunner();
};
}
#ifdef __OBJC__
// #included from: internal/catch_objc.hpp
#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
#import <objc/runtime.h>
#include <string>
// NB. Any general catch headers included here must be included
// in catch.hpp first to make sure they are included by the single
// header for non obj-usage
///////////////////////////////////////////////////////////////////////////////
// This protocol is really only here for (self) documenting purposes, since
// all its methods are optional.
@protocol OcFixture
@optional
-(void) setUp;
-(void) tearDown;
@end
namespace Catch {
class OcMethod : public SharedImpl<ITestCase> {
public:
OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
virtual void invoke() const {
id obj = [[m_cls alloc] init];
performOptionalSelector( obj, @selector(setUp) );
performOptionalSelector( obj, m_sel );
performOptionalSelector( obj, @selector(tearDown) );
arcSafeRelease( obj );
}
private:
virtual ~OcMethod() {}
Class m_cls;
SEL m_sel;
};
namespace Detail{
inline bool startsWith( const std::string& str, const std::string& sub ) {
return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
}
inline std::string getAnnotation( Class cls,
const std::string& annotationName,
const std::string& testCaseName ) {
NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
SEL sel = NSSelectorFromString( selStr );
arcSafeRelease( selStr );
id value = performOptionalSelector( cls, sel );
if( value )
return [(NSString*)value UTF8String];
return "";
}
}
inline size_t registerTestMethods() {
size_t noTestMethods = 0;
int noClasses = objc_getClassList( NULL, 0 );
Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
objc_getClassList( classes, noClasses );
for( int c = 0; c < noClasses; c++ ) {
Class cls = classes[c];
{
u_int count;
Method* methods = class_copyMethodList( cls, &count );
for( u_int m = 0; m < count ; m++ ) {
SEL selector = method_getName(methods[m]);
std::string methodName = sel_getName(selector);
if( Detail::startsWith( methodName, "Catch_TestCase_" ) ) {
std::string testCaseName = methodName.substr( 15 );
std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
getMutableRegistryHub().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) );
noTestMethods++;
}
}
free(methods);
}
}
return noTestMethods;
}
namespace Matchers {
namespace Impl {
namespace NSStringMatchers {
struct StringHolder {
StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
StringHolder() {
arcSafeRelease( m_substr );
}
NSString* m_substr;
};
struct Equals : StringHolder {
Equals( NSString* substr ) : StringHolder( substr ){}
bool operator()( NSString* str ) const {
return [str isEqualToString:m_substr];
}
friend std::ostream& operator<<( std::ostream& os, const Equals& matcher ) {
os << "equals string: " << Catch::toString( matcher.m_substr );
return os;
}
};
struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
bool operator()( NSString* str ) const {
return [str rangeOfString:m_substr].location != NSNotFound;
}
friend std::ostream& operator<<( std::ostream& os, const Contains& matcher ) {
os << "contains: " << Catch::toString( matcher.m_substr );
return os;
}
};
struct StartsWith : StringHolder {
StartsWith( NSString* substr ) : StringHolder( substr ){}
bool operator()( NSString* str ) const {
return [str rangeOfString:m_substr].location == 0;
}
friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher ) {
os << "starts with: " << Catch::toString( matcher.m_substr );
return os;
}
};
struct EndsWith : StringHolder {
EndsWith( NSString* substr ) : StringHolder( substr ){}
bool operator()( NSString* str ) const {
return [str rangeOfString:m_substr].location == [str length] - [m_substr length];
}
friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher ) {
os << "ends with: " << Catch::toString( matcher.m_substr );
return os;
}
};
} // namespace NSStringMatchers
} // namespace Impl
inline Impl::NSStringMatchers::Equals
Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
inline Impl::NSStringMatchers::Contains
Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
inline Impl::NSStringMatchers::StartsWith
StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
inline Impl::NSStringMatchers::EndsWith
EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
} // namespace Matchers
using namespace Matchers;
} // namespace Catch
///////////////////////////////////////////////////////////////////////////////
#define OC_TEST_CASE( name, desc )\
+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
{\
return @ name; \
}\
+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
{ \
return @ desc; \
} \
-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
#endif
#if defined( CATCH_CONFIG_MAIN ) || defined( CATCH_CONFIG_RUNNER )
// #included from: internal/catch_impl.hpp
#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
// Collect all the implementation files together here
// These are the equivalent of what would usually be cpp files
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wweak-vtables"
#endif
// #included from: catch_runner.hpp
#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
// #included from: internal/catch_commandline.hpp
#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
namespace Catch {
class Command {
public:
Command(){}
explicit Command( const std::string& name ) : m_name( name ) {
}
Command& operator += ( const std::string& arg ) {
m_args.push_back( arg );
return *this;
}
Command& operator += ( const Command& other ) {
std::copy( other.m_args.begin(), other.m_args.end(), std::back_inserter( m_args ) );
if( m_name.empty() )
m_name = other.m_name;
return *this;
}
Command operator + ( const Command& other ) {
Command newCommand( *this );
newCommand += other;
return newCommand;
}
operator SafeBool::type() const {
return SafeBool::makeSafe( !m_name.empty() || !m_args.empty() );
}
std::string name() const { return m_name; }
std::string operator[]( std::size_t i ) const { return m_args[i]; }
std::size_t argsCount() const { return m_args.size(); }
CATCH_ATTRIBUTE_NORETURN
void raiseError( const std::string& message ) const {
std::ostringstream oss;
if( m_name.empty() )
oss << "Error while parsing " << m_name << ". " << message << ".";
else
oss << "Error while parsing arguments. " << message << ".";
if( m_args.size() > 0 )
oss << " Arguments were:";
for( std::size_t i = 0; i < m_args.size(); ++i )
oss << " " << m_args[i];
throw std::domain_error( oss.str() );
}
private:
std::string m_name;
std::vector<std::string> m_args;
};
class CommandParser {
public:
CommandParser( int argc, char const * const * argv ) : m_argc( static_cast<std::size_t>( argc ) ), m_argv( argv ) {}
std::string exeName() const {
return m_argv[0];
}
Command find( const std::string& arg1, const std::string& arg2, const std::string& arg3 ) const {
return find( arg1 ) + find( arg2 ) + find( arg3 );
}
Command find( const std::string& shortArg, const std::string& longArg ) const {
return find( shortArg ) + find( longArg );
}
Command find( const std::string& arg ) const {
if( arg.empty() )
return getArgs( "", 1 );
else
for( std::size_t i = 1; i < m_argc; ++i )
if( m_argv[i] == arg )
return getArgs( m_argv[i], i+1 );
return Command();
}
Command getDefaultArgs() const {
return getArgs( "", 1 );
}
private:
Command getArgs( const std::string& cmdName, std::size_t from ) const {
Command command( cmdName );
for( std::size_t i = from; i < m_argc && m_argv[i][0] != '-'; ++i )
command += m_argv[i];
return command;
}
std::size_t m_argc;
char const * const * m_argv;
};
class OptionParser : public SharedImpl<IShared> {
public:
OptionParser( int minArgs = 0, int maxArgs = 0 )
: m_minArgs( minArgs ), m_maxArgs( maxArgs )
{}
virtual ~OptionParser() {}
Command find( const CommandParser& parser ) const {
Command cmd;
for( std::vector<std::string>::const_iterator it = m_optionNames.begin();
it != m_optionNames.end();
++it )
cmd += parser.find( *it );
return cmd;
}
void validateArgs( const Command& args ) const {
if( tooFewArgs( args ) || tooManyArgs( args ) ) {
std::ostringstream oss;
if( m_maxArgs == -1 )
oss <<"Expected at least " << pluralise( static_cast<std::size_t>( m_minArgs ), "argument" );
else if( m_minArgs == m_maxArgs )
oss <<"Expected " << pluralise( static_cast<std::size_t>( m_minArgs ), "argument" );
else
oss <<"Expected between " << m_minArgs << " and " << m_maxArgs << " argument";
args.raiseError( oss.str() );
}
}
void parseIntoConfig( const CommandParser& parser, ConfigData& config ) {
if( Command cmd = find( parser ) ) {
validateArgs( cmd );
parseIntoConfig( cmd, config );
}
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) = 0;
virtual std::string argsSynopsis() const = 0;
virtual std::string optionSummary() const = 0;
virtual std::string optionDescription() const { return ""; };
std::string optionNames() const {
std::string names;
for( std::vector<std::string>::const_iterator it = m_optionNames.begin();
it != m_optionNames.end();
++it ) {
if( !it->empty() ) {
if( !names.empty() )
names += ", ";
names += *it;
}
else {
names = "[" + names;
}
}
if( names[0] == '[' )
names += "]";
return names;
}
protected:
bool tooFewArgs( const Command& args ) const {
return args.argsCount() < static_cast<std::size_t>( m_minArgs );
}
bool tooManyArgs( const Command& args ) const {
return m_maxArgs >= 0 && args.argsCount() > static_cast<std::size_t>( m_maxArgs );
}
std::vector<std::string> m_optionNames;
int m_minArgs;
int m_maxArgs;
};
namespace Options {
class HelpOptionParser : public OptionParser {
public:
HelpOptionParser() {
m_optionNames.push_back( "-?" );
m_optionNames.push_back( "-h" );
m_optionNames.push_back( "--help" );
}
virtual std::string argsSynopsis() const {
return "[<option for help on> ...]";
}
virtual std::string optionSummary() const {
return "Shows this usage summary, or help on a specific option, or options, if supplied";
}
virtual std::string optionDescription() const {
return "";
}
virtual void parseIntoConfig( const Command&, ConfigData& ) {
// Does not affect config
}
};
class TestCaseOptionParser : public OptionParser {
public:
TestCaseOptionParser() : OptionParser( 1, -1 ) {
m_optionNames.push_back( "-t" );
m_optionNames.push_back( "--test" );
m_optionNames.push_back( "" ); // default option
}
virtual std::string argsSynopsis() const {
return "<testspec> [<testspec>...]";
}
virtual std::string optionSummary() const {
return "Specifies which test case or cases to run";
}
// Lines are split at the nearest prior space char to the 80 char column.
// Tab chars are removed from the output but their positions are used to align
// subsequently wrapped lines
virtual std::string optionDescription() const {
return
"This option allows one ore more test specs to be supplied. Each spec either fully "
"specifies a test case or is a pattern containing wildcards to match a set of test "
"cases. If this option is not provided then all test cases, except those prefixed "
"by './' are run\n"
"\n"
"Specs must be enclosed in \"quotes\" if they contain spaces. If they do not "
"contain spaces the quotes are optional.\n"
"\n"
"Wildcards consist of the * character at the beginning, end, or both and can substitute for "
"any number of any characters (including none)\n"
"\n"
"If spec is prefixed with exclude: or the ~ character then the pattern matches an exclusion. "
"This means that tests matching the pattern are excluded from the set - even if a prior "
"inclusion spec included them. Subsequent inclusion specs will take precedence, however. "
"Inclusions and exclusions are evaluated in left-to-right order.\n"
"\n"
"Examples:\n"
"\n"
" -t thisTestOnly \tMatches the test case called, 'thisTestOnly'\n"
" -t \"this test only\" \tMatches the test case called, 'this test only'\n"
" -t these/* \tMatches all cases starting with 'these/'\n"
" -t exclude:notThis \tMatches all tests except, 'notThis'\n"
" -t ~notThis \tMatches all tests except, 'notThis'\n"
" -t ~*private* \tMatches all tests except those that contain 'private'\n"
" -t a/* ~a/b/* a/b/c \tMatches all tests that start with 'a/', except those "
"that start with 'a/b/', except 'a/b/c', which is included";
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
std::string groupName;
for( std::size_t i = 0; i < cmd.argsCount(); ++i ) {
if( i != 0 )
groupName += " ";
groupName += cmd[i];
}
TestCaseFilters filters( groupName );
for( std::size_t i = 0; i < cmd.argsCount(); ++i )
filters.addFilter( TestCaseFilter( cmd[i] ) );
config.filters.push_back( filters );
}
};
class TagOptionParser : public OptionParser {
public:
TagOptionParser() : OptionParser( 1, -1 ) {
m_optionNames.push_back( "-g" );
m_optionNames.push_back( "--tag" );
}
virtual std::string argsSynopsis() const {
return "<tagspec> [,<tagspec>...]";
}
virtual std::string optionSummary() const {
return "Matches test cases against tags or tag patterns";
}
// Lines are split at the nearest prior space char to the 80 char column.
// Tab chars are removed from the output but their positions are used to align
// subsequently wrapped lines
virtual std::string optionDescription() const {
return
"!TBD";
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
std::string groupName;
for( std::size_t i = 0; i < cmd.argsCount(); ++i ) {
if( i != 0 )
groupName += " ";
groupName += cmd[i];
}
TestCaseFilters filters( groupName );
for( std::size_t i = 0; i < cmd.argsCount(); ++i )
filters.addTags( cmd[i] );
config.filters.push_back( filters );
}
};
class ListOptionParser : public OptionParser {
public:
ListOptionParser() : OptionParser( 0, 2 ) {
m_optionNames.push_back( "-l" );
m_optionNames.push_back( "--list" );
}
virtual std::string argsSynopsis() const {
return "[all | tests | reporters [xml]]";
}
virtual std::string optionSummary() const {
return "Lists available tests or reporters";
}
virtual std::string optionDescription() const {
return
"With no arguments this option will list all registered tests - one per line.\n"
"Supplying the xml argument formats the list as an xml document (which may be useful for "
"consumption by other tools).\n"
"Supplying the tests or reporters lists tests or reporters respectively - with descriptions.\n"
"\n"
"Examples:\n"
"\n"
" -l\n"
" -l tests\n"
" -l reporters xml\n"
" -l xml";
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
config.listSpec = List::TestNames;
if( cmd.argsCount() >= 1 ) {
if( cmd[0] == "all" )
config.listSpec = List::All;
else if( cmd[0] == "tests" )
config.listSpec = List::Tests;
else if( cmd[0] == "reporters" )
config.listSpec = List::Reports;
else
cmd.raiseError( "Expected [tests] or [reporters]" );
}
if( cmd.argsCount() >= 2 ) {
if( cmd[1] == "xml" )
config.listSpec = static_cast<List::What>( config.listSpec | List::AsXml );
else if( cmd[1] == "text" )
config.listSpec = static_cast<List::What>( config.listSpec | List::AsText );
else
cmd.raiseError( "Expected [xml] or [text]" );
}
}
};
class ReporterOptionParser : public OptionParser {
public:
ReporterOptionParser() : OptionParser( 1, 1 ) {
m_optionNames.push_back( "-r" );
m_optionNames.push_back( "--reporter" );
}
virtual std::string argsSynopsis() const {
return "<reporter name>";
}
virtual std::string optionSummary() const {
return "Specifies type of reporter";
}
virtual std::string optionDescription() const {
return
"A reporter is an object that formats and structures the output of running "
"tests, and potentially summarises the results. By default a basic reporter "
"is used that writes IDE friendly results. CATCH comes bundled with some "
"alternative reporters, but more can be added in client code.\n"
"\n"
"The bundled reporters are:\n"
" -r basic\n"
" -r xml\n"
" -r junit\n"
"\n"
"The JUnit reporter is an xml format that follows the structure of the JUnit "
"XML Report ANT task, as consumed by a number of third-party tools, "
"including Continuous Integration servers such as Jenkins.\n"
"If not otherwise needed, the standard XML reporter is preferred as this is "
"a streaming reporter, whereas the Junit reporter needs to hold all its "
"results until the end so it can write the overall results into attributes "
"of the root node.";
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
config.reporter = cmd[0];
}
};
class OutputOptionParser : public OptionParser {
public:
OutputOptionParser() : OptionParser( 1, 1 ) {
m_optionNames.push_back( "-o" );
m_optionNames.push_back( "--out" );
}
virtual std::string argsSynopsis() const {
return "<file name>|<%stream name>";
}
virtual std::string optionSummary() const {
return "Sends output to a file or stream";
}
virtual std::string optionDescription() const {
return
"Use this option to send all output to a file or a stream. By default output is "
"sent to stdout (note that uses of stdout and stderr from within test cases are "
"redirected and included in the report - so even stderr will effectively end up "
"on stdout). If the name begins with % it is interpreted as a stream. "
"Otherwise it is treated as a filename.\n"
"\n"
"Examples are:\n"
"\n"
" -o filename.txt\n"
" -o \"long filename.txt\"\n"
" -o %stdout\n"
" -o %stderr\n"
" -o %debug \t(The IDE's debug output window - currently only Windows' "
"OutputDebugString is supported).";
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
if( cmd[0][0] == '%' )
config.stream = cmd[0].substr( 1 );
else
config.outputFilename = cmd[0];
}
};
class SuccessOptionParser : public OptionParser {
public:
SuccessOptionParser() {
m_optionNames.push_back( "-s" );
m_optionNames.push_back( "--success" );
}
virtual std::string argsSynopsis() const {
return "";
}
virtual std::string optionSummary() const {
return "Shows results for successful tests";
}
virtual std::string optionDescription() const {
return
"Usually you only want to see reporting for failed tests. Sometimes it's useful "
"to see all the output (especially when you don't trust that that test you just "
"added worked first time!). To see successful, as well as failing, test results "
"just pass this option.";
}
virtual void parseIntoConfig( const Command&, ConfigData& config ) {
config.includeWhichResults = Include::SuccessfulResults;
}
};
class DebugBreakOptionParser : public OptionParser {
public:
DebugBreakOptionParser() {
m_optionNames.push_back( "-b" );
m_optionNames.push_back( "--break" );
}
virtual std::string argsSynopsis() const {
return "";
}
virtual std::string optionSummary() const {
return "Breaks into the debugger on failure";
}
virtual std::string optionDescription() const {
return
"In some IDEs (currently XCode and Visual Studio) it is possible for CATCH to "
"break into the debugger on a test failure. This can be very helpful during "
"debug sessions - especially when there is more than one path through a "
"particular test. In addition to the command line option, ensure you have "
"built your code with the DEBUG preprocessor symbol";
}
virtual void parseIntoConfig( const Command&, ConfigData& config ) {
config.shouldDebugBreak = true;
}
};
class NameOptionParser : public OptionParser {
public:
NameOptionParser() : OptionParser( 1, 1 ) {
m_optionNames.push_back( "-n" );
m_optionNames.push_back( "--name" );
}
virtual std::string argsSynopsis() const {
return "<name>";
}
virtual std::string optionSummary() const {
return "Names a test run";
}
virtual std::string optionDescription() const {
return
"If a name is supplied it will be used by the reporter to provide an overall "
"name for the test run. This can be useful if you are sending to a file, for "
"example, and need to distinguish different test runs - either from different "
"Catch executables or runs of the same executable with different options.\n"
"\n"
"Examples:\n"
"\n"
" -n testRun\n"
" -n \"tests of the widget component\"";
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
config.name = cmd[0];
}
};
class AbortOptionParser : public OptionParser {
public:
AbortOptionParser() : OptionParser( 0, 1 ) {
m_optionNames.push_back( "-a" );
m_optionNames.push_back( "--abort" );
}
virtual std::string argsSynopsis() const {
return "[#]";
}
virtual std::string optionSummary() const {
return "Aborts after a certain number of failures";
}
virtual std::string optionDescription() const {
return
"If a REQUIRE assertion fails the test case aborts, but subsequent test cases "
"are still run. If a CHECK assertion fails even the current test case is not "
"aborted.\n"
"\n"
"Sometimes this results in a flood of failure messages and you'd rather just "
"see the first few. Specifying -a or --abort on its own will abort the whole "
"test run on the first failed assertion of any kind. Following it with a "
"number causes it to abort after that number of assertion failures.";
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
int threshold = 1;
if( cmd.argsCount() == 1 ) {
std::stringstream ss;
ss << cmd[0];
ss >> threshold;
if( ss.fail() || threshold <= 0 )
cmd.raiseError( "threshold must be a number greater than zero" );
}
config.cutoff = threshold;
}
};
class NoThrowOptionParser : public OptionParser {
public:
NoThrowOptionParser() {
m_optionNames.push_back( "-nt" );
m_optionNames.push_back( "--nothrow" );
}
virtual std::string argsSynopsis() const {
return "";
}
virtual std::string optionSummary() const {
return "Elides assertions expected to throw";
}
virtual std::string optionDescription() const {
return
"Skips all assertions that test that an exception is thrown, "
"e.g. REQUIRE_THROWS.\n"
"\n"
"These can be a nuisance in certain debugging environments that may break when "
"exceptions are thrown (while this is usually optional for handled exceptions, "
"it can be useful to have enabled if you are trying to track down something "
"unexpected).\n"
"\n"
"When running with this option the throw checking assertions are skipped so "
"as not to contribute additional noise.";
}
virtual void parseIntoConfig( const Command&, ConfigData& config ) {
config.allowThrows = false;
}
};
class WarningsOptionParser : public OptionParser {
public:
WarningsOptionParser() : OptionParser( 1, -1 ) {
m_optionNames.push_back( "-w" );
m_optionNames.push_back( "--warnings" );
}
virtual std::string argsSynopsis() const {
return "<warning>";
}
virtual std::string optionSummary() const {
return "Enable warnings";
}
virtual std::string optionDescription() const {
return
"Enables the named warnings. If the warnings are violated the test case is "
"failed.\n"
"\n"
"At present only one warning has been provided: NoAssertions. If this warning "
"is enabled then any test case that completes without an assertions (CHECK, "
"REQUIRE etc) being encountered violates the warning.\n"
"\n"
"e.g.:\n"
"\n"
" -w NoAssertions";
}
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
for( std::size_t i = 0; i < cmd.argsCount(); ++i ) {
if( cmd[i] == "NoAssertions" )
config.warnings = (ConfigData::WarnAbout::What)( config.warnings | ConfigData::WarnAbout::NoAssertions );
else
cmd.raiseError( "Unrecognised warning: " + cmd[i] );
}
}
};
}
class AllOptions
{
public:
typedef std::vector<Ptr<OptionParser> > Parsers;
typedef Parsers::const_iterator const_iterator;
typedef Parsers::const_iterator iterator;
AllOptions() {
add<Options::TestCaseOptionParser>(); // Keep this one first
add<Options::TagOptionParser>();
add<Options::ListOptionParser>();
add<Options::ReporterOptionParser>();
add<Options::OutputOptionParser>();
add<Options::SuccessOptionParser>();
add<Options::DebugBreakOptionParser>();
add<Options::NameOptionParser>();
add<Options::AbortOptionParser>();
add<Options::NoThrowOptionParser>();
add<Options::WarningsOptionParser>();
add<Options::HelpOptionParser>(); // Keep this one last
}
void parseIntoConfig( const CommandParser& parser, ConfigData& config ) {
for( const_iterator it = m_parsers.begin(); it != m_parsers.end(); ++it )
(*it)->parseIntoConfig( parser, config );
}
const_iterator begin() const {
return m_parsers.begin();
}
const_iterator end() const {
return m_parsers.end();
}
private:
template<typename T>
void add() {
m_parsers.push_back( new T() );
}
Parsers m_parsers;
};
} // end namespace Catch
// #included from: internal/catch_list.hpp
#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
#include <limits>
namespace Catch {
inline bool matchesFilters( const std::vector<TestCaseFilters>& filters, const TestCaseInfo& testCase ) {
std::vector<TestCaseFilters>::const_iterator it = filters.begin();
std::vector<TestCaseFilters>::const_iterator itEnd = filters.end();
for(; it != itEnd; ++it )
if( !it->shouldInclude( testCase ) )
return false;
return true;
}
inline void List( const ConfigData& config ) {
if( config.listSpec & List::Reports ) {
std::cout << "Available reports:\n";
IReporterRegistry::FactoryMap::const_iterator it = getRegistryHub().getReporterRegistry().getFactories().begin();
IReporterRegistry::FactoryMap::const_iterator itEnd = getRegistryHub().getReporterRegistry().getFactories().end();
for(; it != itEnd; ++it ) {
// !TBD: consider listAs()
std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n";
}
std::cout << std::endl;
}
if( config.listSpec & List::Tests ) {
if( config.filters.empty() )
std::cout << "All available test cases:\n";
else
std::cout << "Matching test cases:\n";
std::vector<TestCaseInfo>::const_iterator it = getRegistryHub().getTestCaseRegistry().getAllTests().begin();
std::vector<TestCaseInfo>::const_iterator itEnd = getRegistryHub().getTestCaseRegistry().getAllTests().end();
std::size_t matchedTests = 0;
for(; it != itEnd; ++it ) {
if( matchesFilters( config.filters, *it ) ) {
matchedTests++;
// !TBD: consider listAs()
std::cout << "\t" << it->getName() << "\n";
if( ( config.listSpec & List::TestNames ) != List::TestNames )
std::cout << "\t\t '" << it->getDescription() << "'\n";
}
}
if( config.filters.empty() )
std::cout << pluralise( matchedTests, "test case" ) << std::endl;
else
std::cout << pluralise( matchedTests, "matching test case" ) << std::endl;
}
if( ( config.listSpec & List::All ) == 0 ) {
std::ostringstream oss;
oss << "Unknown list type";
throw std::domain_error( oss.str() );
}
}
} // end namespace Catch
// #included from: internal/catch_runner_impl.hpp
#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
// #included from: catch_running_test.hpp
#define TWOBLUECUBES_CATCH_RUNNING_TEST_HPP_INCLUDED
// #included from: catch_section_info.hpp
#define TWOBLUECUBES_CATCH_SECTION_INFO_HPP_INCLUDED
#include <map>
#include <string>
namespace Catch {
class SectionInfo {
public:
enum Status {
Root,
Unknown,
Branch,
TestedBranch,
TestedLeaf
};
SectionInfo( SectionInfo* parent )
: m_status( Unknown ),
m_parent( parent )
{}
SectionInfo()
: m_status( Root ),
m_parent( NULL )
{}
~SectionInfo() {
deleteAllValues( m_subSections );
}
bool shouldRun() const {
return m_status < TestedBranch;
}
bool ran() {
if( m_status < Branch ) {
m_status = TestedLeaf;
return true;
}
return false;
}
bool isBranch() const {
return m_status == Branch;
}
void ranToCompletion() {
if( m_status == Branch && !hasUntestedSections() )
m_status = TestedBranch;
}
SectionInfo* findSubSection( const std::string& name ) {
std::map<std::string, SectionInfo*>::const_iterator it = m_subSections.find( name );
return it != m_subSections.end()
? it->second
: NULL;
}
SectionInfo* addSubSection( const std::string& name ) {
SectionInfo* subSection = new SectionInfo( this );
m_subSections.insert( std::make_pair( name, subSection ) );
m_status = Branch;
return subSection;
}
SectionInfo* getParent() {
return m_parent;
}
bool hasUntestedSections() const {
if( m_status == Unknown )
return true;
std::map<std::string, SectionInfo*>::const_iterator it = m_subSections.begin();
std::map<std::string, SectionInfo*>::const_iterator itEnd = m_subSections.end();
for(; it != itEnd; ++it ) {
if( it->second->hasUntestedSections() )
return true;
}
return false;
}
private:
Status m_status;
std::map<std::string, SectionInfo*> m_subSections;
SectionInfo* m_parent;
};
}
namespace Catch {
class RunningTest {
enum RunStatus {
NothingRun,
EncounteredASection,
RanAtLeastOneSection,
RanToCompletionWithSections,
RanToCompletionWithNoSections
};
public:
explicit RunningTest( const TestCaseInfo* info = NULL )
: m_info( info ),
m_runStatus( RanAtLeastOneSection ),
m_currentSection( &m_rootSection ),
m_changed( false )
{}
bool wasSectionSeen() const {
return m_runStatus == RanAtLeastOneSection ||
m_runStatus == RanToCompletionWithSections;
}
bool isBranchSection() const {
return m_currentSection &&
m_currentSection->isBranch();
}
bool hasSections() const {
return m_runStatus == RanAtLeastOneSection ||
m_runStatus == RanToCompletionWithSections ||
m_runStatus == EncounteredASection;
}
void reset() {
m_runStatus = NothingRun;
m_changed = false;
m_lastSectionToRun = NULL;
}
void ranToCompletion() {
if( m_runStatus == RanAtLeastOneSection ||
m_runStatus == EncounteredASection ) {
m_runStatus = RanToCompletionWithSections;
if( m_lastSectionToRun ) {
m_lastSectionToRun->ranToCompletion();
m_changed = true;
}
}
else {
m_runStatus = RanToCompletionWithNoSections;
}
}
bool addSection( const std::string& name ) {
if( m_runStatus == NothingRun )
m_runStatus = EncounteredASection;
SectionInfo* thisSection = m_currentSection->findSubSection( name );
if( !thisSection ) {
thisSection = m_currentSection->addSubSection( name );
m_changed = true;
}
if( !wasSectionSeen() && thisSection->shouldRun() ) {
m_currentSection = thisSection;
m_lastSectionToRun = NULL;
return true;
}
return false;
}
void endSection( const std::string& ) {
if( m_currentSection->ran() ) {
m_runStatus = RanAtLeastOneSection;
m_changed = true;
}
else if( m_runStatus == EncounteredASection ) {
m_runStatus = RanAtLeastOneSection;
m_lastSectionToRun = m_currentSection;
}
m_currentSection = m_currentSection->getParent();
}
const TestCaseInfo& getTestCaseInfo() const {
return *m_info;
}
bool hasUntestedSections() const {
return m_runStatus == RanAtLeastOneSection ||
( m_rootSection.hasUntestedSections() && m_changed );
}
private:
const TestCaseInfo* m_info;
RunStatus m_runStatus;
SectionInfo m_rootSection;
SectionInfo* m_currentSection;
SectionInfo* m_lastSectionToRun;
bool m_changed;
};
}
#include <set>
#include <string>
namespace Catch {
class StreamRedirect {
public:
StreamRedirect( std::ostream& stream, std::string& targetString )
: m_stream( stream ),
m_prevBuf( stream.rdbuf() ),
m_targetString( targetString )
{
stream.rdbuf( m_oss.rdbuf() );
}
~StreamRedirect() {
m_targetString += m_oss.str();
m_stream.rdbuf( m_prevBuf );
}
private:
std::ostream& m_stream;
std::streambuf* m_prevBuf;
std::ostringstream m_oss;
std::string& m_targetString;
};
///////////////////////////////////////////////////////////////////////////
class Runner : public IResultCapture, public IRunner {
Runner( const Runner& );
void operator =( const Runner& );
public:
explicit Runner( const Config& config, const Ptr<IReporter>& reporter )
: m_context( getCurrentMutableContext() ),
m_runningTest( NULL ),
m_config( config ),
m_reporter( reporter ),
m_prevRunner( &m_context.getRunner() ),
m_prevResultCapture( &m_context.getResultCapture() ),
m_prevConfig( m_context.getConfig() )
{
m_context.setRunner( this );
m_context.setConfig( &m_config );
m_context.setResultCapture( this );
m_reporter->StartTesting();
}
virtual ~Runner() {
m_reporter->EndTesting( m_totals );
m_context.setRunner( m_prevRunner );
m_context.setConfig( NULL );
m_context.setResultCapture( m_prevResultCapture );
m_context.setConfig( m_prevConfig );
}
Totals runMatching( const std::string& testSpec ) {
std::vector<TestCaseInfo> matchingTests = getRegistryHub().getTestCaseRegistry().getMatchingTestCases( testSpec );
Totals totals;
m_reporter->StartGroup( testSpec );
std::vector<TestCaseInfo>::const_iterator it = matchingTests.begin();
std::vector<TestCaseInfo>::const_iterator itEnd = matchingTests.end();
for(; it != itEnd; ++it )
totals += runTest( *it );
// !TBD use std::accumulate?
m_reporter->EndGroup( testSpec, totals );
return totals;
}
Totals runTest( const TestCaseInfo& testInfo ) {
Totals prevTotals = m_totals;
std::string redirectedCout;
std::string redirectedCerr;
m_reporter->StartTestCase( testInfo );
m_runningTest = new RunningTest( &testInfo );
do {
do {
m_currentResult.setLineInfo( m_runningTest->getTestCaseInfo().getLineInfo() );
runCurrentTest( redirectedCout, redirectedCerr );
}
while( m_runningTest->hasUntestedSections() && !aborting() );
}
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
delete m_runningTest;
m_runningTest = NULL;
Totals deltaTotals = m_totals.delta( prevTotals );
m_totals.testCases += deltaTotals.testCases;
m_reporter->EndTestCase( testInfo, deltaTotals, redirectedCout, redirectedCerr );
return deltaTotals;
}
const Config& config() const {
return m_config;
}
private: // IResultCapture
virtual ResultAction::Value acceptResult( bool result ) {
return acceptResult( result ? ResultWas::Ok : ResultWas::ExpressionFailed );
}
virtual ResultAction::Value acceptResult( ResultWas::OfType result ) {
m_currentResult.setResultType( result );
return actOnCurrentResult();
}
virtual ResultAction::Value acceptExpression( const ResultInfoBuilder& resultInfo ) {
m_currentResult = resultInfo;
return actOnCurrentResult();
}
virtual void acceptMessage( const std::string& msg ) {
m_currentResult.setMessage( msg );
}
virtual void testEnded( const ResultInfo& result ) {
if( result.getResultType() == ResultWas::Ok ) {
m_totals.assertions.passed++;
}
else if( !result.ok() ) {
m_totals.assertions.failed++;
{
std::vector<ScopedInfo*>::const_iterator it = m_scopedInfos.begin();
std::vector<ScopedInfo*>::const_iterator itEnd = m_scopedInfos.end();
for(; it != itEnd; ++it )
m_reporter->Result( (*it)->getInfo() );
}
{
std::vector<ResultInfo>::const_iterator it = m_info.begin();
std::vector<ResultInfo>::const_iterator itEnd = m_info.end();
for(; it != itEnd; ++it )
m_reporter->Result( *it );
}
m_info.clear();
}
if( result.getResultType() == ResultWas::Info )
m_info.push_back( result );
else
m_reporter->Result( result );
}
virtual bool sectionStarted (
const std::string& name,
const std::string& description,
const SourceLineInfo& lineInfo,
Counts& assertions
)
{
std::ostringstream oss;
oss << name << "@" << lineInfo;
if( !m_runningTest->addSection( oss.str() ) )
return false;
m_currentResult.setLineInfo( lineInfo );
m_reporter->StartSection( name, description );
assertions = m_totals.assertions;
return true;
}
virtual void sectionEnded( const std::string& name, const Counts& prevAssertions ) {
Counts assertions = m_totals.assertions - prevAssertions;
if( assertions.total() == 0 &&
( m_config.data().warnings & ConfigData::WarnAbout::NoAssertions ) &&
!m_runningTest->isBranchSection() ) {
m_reporter->NoAssertionsInSection( name );
m_totals.assertions.failed++;
assertions.failed++;
}
m_runningTest->endSection( name );
m_reporter->EndSection( name, assertions );
}
virtual void pushScopedInfo( ScopedInfo* scopedInfo ) {
m_scopedInfos.push_back( scopedInfo );
}
virtual void popScopedInfo( ScopedInfo* scopedInfo ) {
if( m_scopedInfos.back() == scopedInfo )
m_scopedInfos.pop_back();
}
virtual bool shouldDebugBreak() const {
return m_config.shouldDebugBreak();
}
virtual std::string getCurrentTestName() const {
return m_runningTest
? m_runningTest->getTestCaseInfo().getName()
: "";
}
virtual const ResultInfo* getLastResult() const {
return &m_lastResult;
}
public:
// !TBD We need to do this another way!
bool aborting() const {
return m_totals.assertions.failed == static_cast<std::size_t>( m_config.getCutoff() );
}
private:
ResultAction::Value actOnCurrentResult() {
m_lastResult = m_currentResult.build();
testEnded( m_lastResult );
m_currentResult = ResultInfoBuilder();
ResultAction::Value action = ResultAction::None;
if( !m_lastResult.ok() ) {
action = ResultAction::Failed;
if( shouldDebugBreak() )
action = (ResultAction::Value)( action | ResultAction::Debug );
if( aborting() )
action = (ResultAction::Value)( action | ResultAction::Abort );
}
return action;
}
void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
try {
m_runningTest->reset();
Counts prevAssertions = m_totals.assertions;
if( m_reporter->shouldRedirectStdout() ) {
StreamRedirect coutRedir( std::cout, redirectedCout );
StreamRedirect cerrRedir( std::cerr, redirectedCerr );
m_runningTest->getTestCaseInfo().invoke();
}
else {
m_runningTest->getTestCaseInfo().invoke();
}
Counts assertions = m_totals.assertions - prevAssertions;
if( assertions.total() == 0 &&
( m_config.data().warnings & ConfigData::WarnAbout::NoAssertions ) &&
!m_runningTest->hasSections() ) {
m_totals.assertions.failed++;
m_reporter->NoAssertionsInTestCase( m_runningTest->getTestCaseInfo().getName() );
}
m_runningTest->ranToCompletion();
}
catch( TestFailureException& ) {
// This just means the test was aborted due to failure
}
catch(...) {
acceptMessage( getRegistryHub().getExceptionTranslatorRegistry().translateActiveException() );
acceptResult( ResultWas::ThrewException );
}
m_info.clear();
}
private:
IMutableContext& m_context;
RunningTest* m_runningTest;
ResultInfoBuilder m_currentResult;
ResultInfo m_lastResult;
const Config& m_config;
Totals m_totals;
Ptr<IReporter> m_reporter;
std::vector<ScopedInfo*> m_scopedInfos;
std::vector<ResultInfo> m_info;
IRunner* m_prevRunner;
IResultCapture* m_prevResultCapture;
const IConfig* m_prevConfig;
};
} // end namespace Catch
#include <fstream>
#include <stdlib.h>
#include <limits>
namespace Catch {
class Runner2 { // This will become Runner when Runner becomes Context
public:
Runner2( Config& configWrapper )
: m_configWrapper( configWrapper ),
m_config( configWrapper.data() )
{
openStream();
makeReporter();
}
Totals runTests() {
std::vector<TestCaseFilters> filterGroups = m_config.filters;
if( filterGroups.empty() ) {
TestCaseFilters filterGroup( "" );
filterGroups.push_back( filterGroup );
}
Runner context( m_configWrapper, m_reporter ); // This Runner will be renamed Context
Totals totals;
std::vector<TestCaseFilters>::const_iterator it = filterGroups.begin();
std::vector<TestCaseFilters>::const_iterator itEnd = filterGroups.end();
for(; it != itEnd && !context.aborting(); ++it ) {
m_reporter->StartGroup( it->getName() );
totals += runTestsForGroup( context, *it );
if( context.aborting() )
m_reporter->Aborted();
m_reporter->EndGroup( it->getName(), totals );
}
return totals;
}
Totals runTestsForGroup( Runner& context, const TestCaseFilters& filterGroup ) {
Totals totals;
std::vector<TestCaseInfo>::const_iterator it = getRegistryHub().getTestCaseRegistry().getAllTests().begin();
std::vector<TestCaseInfo>::const_iterator itEnd = getRegistryHub().getTestCaseRegistry().getAllTests().end();
int testsRunForGroup = 0;
for(; it != itEnd; ++it ) {
if( filterGroup.shouldInclude( *it ) ) {
testsRunForGroup++;
if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
if( context.aborting() )
break;
totals += context.runTest( *it );
m_testsAlreadyRun.insert( *it );
}
}
}
if( testsRunForGroup == 0 )
std::cerr << "\n[No test cases matched with: " << filterGroup.getName() << "]" << std::endl;
return totals;
}
private:
void openStream() {
if( !m_config.stream.empty() )
m_configWrapper.useStream( m_config.stream );
// Open output file, if specified
if( !m_config.outputFilename.empty() ) {
m_ofs.open( m_config.outputFilename.c_str() );
if( m_ofs.fail() ) {
std::ostringstream oss;
oss << "Unable to open file: '" << m_config.outputFilename << "'";
throw std::domain_error( oss.str() );
}
m_configWrapper.setStreamBuf( m_ofs.rdbuf() );
}
}
void makeReporter() {
std::string reporterName = m_config.reporter.empty()
? "basic"
: m_config.reporter;
ReporterConfig reporterConfig( m_config.name, m_configWrapper.stream(), m_config.includeWhichResults == Include::SuccessfulResults, m_config );
m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, reporterConfig );
if( !m_reporter ) {
std::ostringstream oss;
oss << "No reporter registered with name: '" << reporterName << "'";
throw std::domain_error( oss.str() );
}
}
private:
Config& m_configWrapper;
const ConfigData& m_config;
std::ofstream m_ofs;
Ptr<IReporter> m_reporter;
std::set<TestCaseInfo> m_testsAlreadyRun;
};
inline int Main( Config& configWrapper ) {
int result = 0;
try
{
Runner2 runner( configWrapper );
const ConfigData& config = configWrapper.data();
// Handle list request
if( config.listSpec != List::None ) {
List( config );
Catch::cleanUp();
return 0;
}
result = static_cast<int>( runner.runTests().assertions.failed );
}
catch( std::exception& ex ) {
std::cerr << ex.what() << std::endl;
result = (std::numeric_limits<int>::max)();
}
Catch::cleanUp();
return result;
}
inline void showUsage( std::ostream& os ) {
AllOptions options;
for( AllOptions::const_iterator it = options.begin(); it != options.end(); ++it ) {
OptionParser& opt = **it;
os << " " << opt.optionNames() << " " << opt.argsSynopsis() << "\n";
}
os << "\nFor more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line\n" << std::endl;
}
inline void addIndent( std::ostream& os, std::size_t indent ) {
while( indent-- > 0 )
os << ' ';
}
inline void recursivelyWrapLine( std::ostream& os, std::string paragraph, std::size_t columns, std::size_t indent ) {
std::size_t width = columns-indent;
std::size_t tab = 0;
std::size_t wrapPoint = width;
for( std::size_t pos = 0; pos < paragraph.size(); ++pos ) {
if( pos == width ) {
addIndent( os, indent );
os << paragraph.substr( 0, wrapPoint ) << "\n";
return recursivelyWrapLine( os, paragraph.substr( wrapPoint+1 ), columns, indent+tab );
}
if( paragraph[pos] == '\t' ) {
tab = pos;
paragraph = paragraph.substr( 0, tab ) + paragraph.substr( tab+1 );
pos--;
}
else if( paragraph[pos] == ' ' ) {
wrapPoint = pos;
}
}
addIndent( os, indent );
os << paragraph << "\n";
}
inline std::string addLineBreaks( const std::string& str, std::size_t columns, std::size_t indent = 0 ) {
std::ostringstream oss;
std::string::size_type pos = 0;
std::string::size_type newline = str.find_first_of( '\n' );
while( newline != std::string::npos ) {
std::string paragraph = str.substr( pos, newline-pos );
recursivelyWrapLine( oss, paragraph, columns, indent );
pos = newline+1;
newline = str.find_first_of( '\n', pos );
}
if( pos != str.size() )
recursivelyWrapLine( oss, str.substr( pos, str.size()-pos ), columns, indent );
return oss.str();
}
inline void showHelp( const CommandParser& parser ) {
std::string exeName = parser.exeName();
std::string::size_type pos = exeName.find_last_of( "/\\" );
if( pos != std::string::npos ) {
exeName = exeName.substr( pos+1 );
}
AllOptions options;
Options::HelpOptionParser helpOpt;
bool displayedSpecificOption = false;
for( AllOptions::const_iterator it = options.begin(); it != options.end(); ++it ) {
OptionParser& opt = **it;
if( opt.find( parser ) && opt.optionNames() != helpOpt.optionNames() ) {
displayedSpecificOption = true;
std::cout << "\n" << opt.optionNames() << " " << opt.argsSynopsis() << "\n\n"
<< opt.optionSummary() << "\n\n"
<< addLineBreaks( opt.optionDescription(), 80, 2 ) << "\n" << std::endl;
}
}
if( !displayedSpecificOption ) {
std::cout << exeName << " is a CATCH host application. Options are as follows:\n\n";
showUsage( std::cout );
}
}
inline int Main( int argc, char* const argv[], Config& config ) {
try {
CommandParser parser( argc, argv );
if( Command cmd = Options::HelpOptionParser().find( parser ) ) {
if( cmd.argsCount() != 0 )
cmd.raiseError( "Does not accept arguments" );
showHelp( parser );
Catch::cleanUp();
return 0;
}
AllOptions options;
options.parseIntoConfig( parser, config.data() );
}
catch( std::exception& ex ) {
std::cerr << ex.what() << "\n\nUsage: ...\n\n";
showUsage( std::cerr );
Catch::cleanUp();
return (std::numeric_limits<int>::max)();
}
return Main( config );
}
inline int Main( int argc, char* const argv[] ) {
Config config;
// !TBD: This doesn't always work, for some reason
// if( isDebuggerActive() )
// config.useStream( "debug" );
return Main( argc, argv, config );
}
} // end namespace Catch
// #included from: catch_registry_hub.hpp
#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
// #included from: catch_test_case_registry_impl.hpp
#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
#include <vector>
#include <set>
#include <sstream>
#include <iostream>
namespace Catch {
class TestRegistry : public ITestCaseRegistry {
public:
TestRegistry() : m_unnamedCount( 0 ) {}
virtual ~TestRegistry();
virtual void registerTest( const TestCaseInfo& testInfo ) {
if( testInfo.getName() == "" ) {
std::ostringstream oss;
oss << testInfo.getName() << "unnamed/" << ++m_unnamedCount;
return registerTest( TestCaseInfo( testInfo, oss.str() ) );
}
if( m_functions.find( testInfo ) == m_functions.end() ) {
m_functions.insert( testInfo );
m_functionsInOrder.push_back( testInfo );
if( !testInfo.isHidden() )
m_nonHiddenFunctions.push_back( testInfo );
}
else {
const TestCaseInfo& prev = *m_functions.find( testInfo );
std::cerr << "error: TEST_CASE( \"" << testInfo.getName() << "\" ) already defined.\n"
<< "\tFirst seen at " << SourceLineInfo( prev.getLineInfo() ) << "\n"
<< "\tRedefined at " << SourceLineInfo( testInfo.getLineInfo() ) << std::endl;
exit(1);
}
}
virtual const std::vector<TestCaseInfo>& getAllTests() const {
return m_functionsInOrder;
}
virtual const std::vector<TestCaseInfo>& getAllNonHiddenTests() const {
return m_nonHiddenFunctions;
}
// !TBD deprecated
virtual std::vector<TestCaseInfo> getMatchingTestCases( const std::string& rawTestSpec ) const {
std::vector<TestCaseInfo> matchingTests;
getMatchingTestCases( rawTestSpec, matchingTests );
return matchingTests;
}
// !TBD deprecated
virtual void getMatchingTestCases( const std::string& rawTestSpec, std::vector<TestCaseInfo>& matchingTestsOut ) const {
TestCaseFilter filter( rawTestSpec );
std::vector<TestCaseInfo>::const_iterator it = m_functionsInOrder.begin();
std::vector<TestCaseInfo>::const_iterator itEnd = m_functionsInOrder.end();
for(; it != itEnd; ++it ) {
if( filter.shouldInclude( *it ) ) {
matchingTestsOut.push_back( *it );
}
}
}
virtual void getMatchingTestCases( const TestCaseFilters& filters, std::vector<TestCaseInfo>& matchingTestsOut ) const {
std::vector<TestCaseInfo>::const_iterator it = m_functionsInOrder.begin();
std::vector<TestCaseInfo>::const_iterator itEnd = m_functionsInOrder.end();
// !TBD: replace with algorithm
for(; it != itEnd; ++it )
if( filters.shouldInclude( *it ) )
matchingTestsOut.push_back( *it );
}
private:
std::set<TestCaseInfo> m_functions;
std::vector<TestCaseInfo> m_functionsInOrder;
std::vector<TestCaseInfo> m_nonHiddenFunctions;
size_t m_unnamedCount;
};
///////////////////////////////////////////////////////////////////////////
class FreeFunctionTestCase : public SharedImpl<ITestCase> {
public:
FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
virtual void invoke() const {
m_fun();
}
private:
virtual ~FreeFunctionTestCase();
TestFunction m_fun;
};
///////////////////////////////////////////////////////////////////////////
AutoReg::AutoReg( TestFunction function,
const char* name,
const char* description,
const SourceLineInfo& lineInfo ) {
registerTestCase( new FreeFunctionTestCase( function ), name, description, lineInfo );
}
AutoReg::~AutoReg() {}
void AutoReg::registerTestCase( ITestCase* testCase,
const char* name,
const char* description,
const SourceLineInfo& lineInfo ) {
getMutableRegistryHub().registerTest( TestCaseInfo( testCase, name, description, lineInfo ) );
}
} // end namespace Catch
// #included from: catch_reporter_registry.hpp
#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
#include <map>
namespace Catch {
class ReporterRegistry : public IReporterRegistry {
public:
virtual ~ReporterRegistry() {
deleteAllValues( m_factories );
}
virtual IReporter* create( const std::string& name, const ReporterConfig& config ) const {
FactoryMap::const_iterator it = m_factories.find( name );
if( it == m_factories.end() )
return NULL;
return it->second->create( config );
}
void registerReporter( const std::string& name, IReporterFactory* factory ) {
m_factories.insert( std::make_pair( name, factory ) );
}
const FactoryMap& getFactories() const {
return m_factories;
}
private:
FactoryMap m_factories;
};
}
// #included from: catch_exception_translator_registry.hpp
#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
#ifdef __OBJC__
#import "Foundation/Foundation.h"
#endif
namespace Catch {
class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
public:
~ExceptionTranslatorRegistry() {
deleteAll( m_translators );
}
virtual void registerTranslator( const IExceptionTranslator* translator ) {
m_translators.push_back( translator );
}
virtual std::string translateActiveException() const {
try {
#ifdef __OBJC__
// In Objective-C try objective-c exceptions first
@try {
throw;
}
@catch (NSException *exception) {
return toString( [exception description] );
}
#else
throw;
#endif
}
catch( std::exception& ex ) {
return ex.what();
}
catch( std::string& msg ) {
return msg;
}
catch( const char* msg ) {
return msg;
}
catch(...) {
return tryTranslators( m_translators.begin() );
}
}
std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
if( it == m_translators.end() )
return "Unknown exception";
try {
return (*it)->translate();
}
catch(...) {
return tryTranslators( it+1 );
}
}
private:
std::vector<const IExceptionTranslator*> m_translators;
};
}
namespace Catch {
namespace {
class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
RegistryHub( const RegistryHub& );
void operator=( const RegistryHub& );
public: // IRegistryHub
RegistryHub() {
}
virtual const IReporterRegistry& getReporterRegistry() const {
return m_reporterRegistry;
}
virtual const ITestCaseRegistry& getTestCaseRegistry() const {
return m_testCaseRegistry;
}
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
return m_exceptionTranslatorRegistry;
}
public: // IMutableRegistryHub
virtual void registerReporter( const std::string& name, IReporterFactory* factory ) {
m_reporterRegistry.registerReporter( name, factory );
}
virtual void registerTest( const TestCaseInfo& testInfo ) {
m_testCaseRegistry.registerTest( testInfo );
}
virtual void registerTranslator( const IExceptionTranslator* translator ) {
m_exceptionTranslatorRegistry.registerTranslator( translator );
}
private:
TestRegistry m_testCaseRegistry;
ReporterRegistry m_reporterRegistry;
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
};
// Single, global, instance
inline RegistryHub*& getTheRegistryHub() {
static RegistryHub* theRegistryHub = NULL;
if( !theRegistryHub )
theRegistryHub = new RegistryHub();
return theRegistryHub;
}
}
IRegistryHub& getRegistryHub() {
return *getTheRegistryHub();
}
IMutableRegistryHub& getMutableRegistryHub() {
return *getTheRegistryHub();
}
void cleanUp() {
delete getTheRegistryHub();
getTheRegistryHub() = NULL;
cleanUpContext();
}
} // end namespace Catch
// #included from: catch_notimplemented_exception.hpp
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
#include <ostream>
namespace Catch {
NotImplementedException::NotImplementedException( const SourceLineInfo& lineInfo )
: m_lineInfo( lineInfo ) {
std::ostringstream oss;
oss << lineInfo << "function ";
if( !lineInfo.function.empty() )
oss << lineInfo.function << " ";
oss << "not implemented";
m_what = oss.str();
}
const char* NotImplementedException::what() const throw() {
return m_what.c_str();
}
} // end namespace Catch
// #included from: catch_context_impl.hpp
#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
namespace Catch {
class Context : public IMutableContext {
Context() : m_config( NULL ) {}
Context( const Context& );
void operator=( const Context& );
public: // IContext
virtual IResultCapture& getResultCapture() {
return *m_resultCapture;
}
virtual IRunner& getRunner() {
return *m_runner;
}
virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) {
return getGeneratorsForCurrentTest()
.getGeneratorInfo( fileInfo, totalSize )
.getCurrentIndex();
}
virtual bool advanceGeneratorsForCurrentTest() {
IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
return generators && generators->moveNext();
}
virtual const IConfig* getConfig() const {
return m_config;
}
public: // IMutableContext
virtual void setResultCapture( IResultCapture* resultCapture ) {
m_resultCapture = resultCapture;
}
virtual void setRunner( IRunner* runner ) {
m_runner = runner;
}
virtual void setConfig( const IConfig* config ) {
m_config = config;
}
friend IMutableContext& getCurrentMutableContext();
private:
IGeneratorsForTest* findGeneratorsForCurrentTest() {
std::string testName = getResultCapture().getCurrentTestName();
std::map<std::string, IGeneratorsForTest*>::const_iterator it =
m_generatorsByTestName.find( testName );
return it != m_generatorsByTestName.end()
? it->second
: NULL;
}
IGeneratorsForTest& getGeneratorsForCurrentTest() {
IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
if( !generators ) {
std::string testName = getResultCapture().getCurrentTestName();
generators = createGeneratorsForTest();
m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
}
return *generators;
}
private:
IRunner* m_runner;
IResultCapture* m_resultCapture;
const IConfig* m_config;
std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
};
namespace {
Context* currentContext = NULL;
}
IMutableContext& getCurrentMutableContext() {
if( !currentContext )
currentContext = new Context();
return *currentContext;
}
IContext& getCurrentContext() {
return getCurrentMutableContext();
}
Stream createStream( const std::string& streamName ) {
if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false );
if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false );
if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
throw std::domain_error( "Unknown stream: " + streamName );
}
void cleanUpContext() {
delete currentContext;
currentContext = NULL;
}
}
// #included from: catch_console_colour_impl.hpp
#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
// #included from: catch_console_colour.hpp
#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
namespace Catch {
struct ConsoleColourImpl;
class TextColour : NonCopyable {
public:
enum Colours {
None,
FileName,
ResultError,
ResultSuccess,
Error,
Success,
OriginalExpression,
ReconstructedExpression
};
TextColour( Colours colour = None );
void set( Colours colour );
~TextColour();
private:
ConsoleColourImpl* m_impl;
};
} // end namespace Catch
#ifdef CATCH_PLATFORM_WINDOWS
#include <windows.h>
namespace Catch {
namespace {
WORD mapConsoleColour( TextColour::Colours colour ) {
switch( colour ) {
case TextColour::FileName:
return FOREGROUND_INTENSITY; // greyed out
case TextColour::ResultError:
return FOREGROUND_RED | FOREGROUND_INTENSITY; // bright red
case TextColour::ResultSuccess:
return FOREGROUND_GREEN | FOREGROUND_INTENSITY; // bright green
case TextColour::Error:
return FOREGROUND_RED; // dark red
case TextColour::Success:
return FOREGROUND_GREEN; // dark green
case TextColour::OriginalExpression:
return FOREGROUND_BLUE | FOREGROUND_GREEN; // turquoise
case TextColour::ReconstructedExpression:
return FOREGROUND_RED | FOREGROUND_GREEN; // greeny-yellow
default: return 0;
}
}
}
struct ConsoleColourImpl {
ConsoleColourImpl()
: hStdout( GetStdHandle(STD_OUTPUT_HANDLE) ),
wOldColorAttrs( 0 )
{
GetConsoleScreenBufferInfo( hStdout, &csbiInfo );
wOldColorAttrs = csbiInfo.wAttributes;
}
~ConsoleColourImpl() {
SetConsoleTextAttribute( hStdout, wOldColorAttrs );
}
void set( TextColour::Colours colour ) {
WORD consoleColour = mapConsoleColour( colour );
if( consoleColour > 0 )
SetConsoleTextAttribute( hStdout, consoleColour );
}
HANDLE hStdout;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
WORD wOldColorAttrs;
};
TextColour::TextColour( Colours colour )
: m_impl( new ConsoleColourImpl() )
{
if( colour )
m_impl->set( colour );
}
TextColour::~TextColour() {
delete m_impl;
}
void TextColour::set( Colours colour ) {
m_impl->set( colour );
}
} // end namespace Catch
#else
namespace Catch {
TextColour::TextColour( Colours ){}
TextColour::~TextColour(){}
void TextColour::set( Colours ){}
} // end namespace Catch
#endif
// #included from: catch_generators_impl.hpp
#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
#include <vector>
#include <string>
#include <map>
namespace Catch {
struct GeneratorInfo : IGeneratorInfo {
GeneratorInfo( std::size_t size )
: m_size( size ),
m_currentIndex( 0 )
{}
bool moveNext() {
if( ++m_currentIndex == m_size ) {
m_currentIndex = 0;
return false;
}
return true;
}
std::size_t getCurrentIndex() const {
return m_currentIndex;
}
std::size_t m_size;
std::size_t m_currentIndex;
};
///////////////////////////////////////////////////////////////////////////
class GeneratorsForTest : public IGeneratorsForTest {
public:
~GeneratorsForTest() {
deleteAll( m_generatorsInOrder );
}
IGeneratorInfo& getGeneratorInfo( const std::string& fileInfo, std::size_t size ) {
std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
if( it == m_generatorsByName.end() ) {
IGeneratorInfo* info = new GeneratorInfo( size );
m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
m_generatorsInOrder.push_back( info );
return *info;
}
return *it->second;
}
bool moveNext() {
std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
for(; it != itEnd; ++it ) {
if( (*it)->moveNext() )
return true;
}
return false;
}
private:
std::map<std::string, IGeneratorInfo*> m_generatorsByName;
std::vector<IGeneratorInfo*> m_generatorsInOrder;
};
IGeneratorsForTest* createGeneratorsForTest()
{
return new GeneratorsForTest();
}
} // end namespace Catch
// #included from: catch_resultinfo.hpp
#define TWOBLUECUBES_CATCH_RESULTINFO_HPP_INCLUDED
namespace Catch {
ResultInfo::ResultInfo() {}
ResultInfo::ResultInfo( const ResultData& data ) : m_data( data ) {}
ResultInfo::~ResultInfo() {}
bool ResultInfo::ok() const {
return isOk( m_data.resultType );
}
ResultWas::OfType ResultInfo::getResultType() const {
return m_data.resultType;
}
bool ResultInfo::hasExpression() const {
return !m_data.capturedExpression.empty();
}
bool ResultInfo::hasMessage() const {
return !m_data.message.empty();
}
std::string ResultInfo::getExpression() const {
return m_data.capturedExpression;
}
bool ResultInfo::hasExpandedExpression() const {
return hasExpression() && getExpandedExpression() != getExpression();
}
std::string ResultInfo::getExpandedExpression() const {
return m_data.reconstructedExpression;
}
std::string ResultInfo::getMessage() const {
return m_data.message;
}
std::string ResultInfo::getFilename() const {
return m_data.lineInfo.file;
}
std::size_t ResultInfo::getLine() const {
return m_data.lineInfo.line;
}
std::string ResultInfo::getTestMacroName() const {
return m_data.macroName;
}
} // end namespace Catch
// #included from: catch_resultinfo_builder.hpp
#define TWOBLUECUBES_CATCH_RESULTINFO_BUILDER_HPP_INCLUDED
namespace Catch {
ResultInfoBuilder::ResultInfoBuilder() {}
ResultInfoBuilder& ResultInfoBuilder::setResultType( ResultWas::OfType result ) {
// Flip bool results if isFalse is set
if( m_isFalse && result == ResultWas::Ok )
m_data.resultType = ResultWas::ExpressionFailed;
else if( m_isFalse && result == ResultWas::ExpressionFailed )
m_data.resultType = ResultWas::Ok;
else
m_data.resultType = result;
return *this;
}
ResultInfoBuilder& ResultInfoBuilder::setCapturedExpression( const std::string& capturedExpression ) {
m_data.capturedExpression = capturedExpression;
return *this;
}
ResultInfoBuilder& ResultInfoBuilder::setIsFalse( bool isFalse ) {
m_isFalse = isFalse;
return *this;
}
ResultInfoBuilder& ResultInfoBuilder::setMessage( const std::string& message ) {
m_data.message = message;
return *this;
}
ResultInfoBuilder& ResultInfoBuilder::setLineInfo( const SourceLineInfo& lineInfo ) {
m_data.lineInfo = lineInfo;
return *this;
}
ResultInfoBuilder& ResultInfoBuilder::setMacroName( const std::string& macroName ) {
m_data.macroName = macroName;
return *this;
}
ResultInfoBuilder& ResultInfoBuilder::setLhs( const std::string& lhs ) {
m_lhs = lhs;
return *this;
}
ResultInfoBuilder& ResultInfoBuilder::setRhs( const std::string& rhs ) {
m_rhs = rhs;
return *this;
}
ResultInfoBuilder& ResultInfoBuilder::setOp( const std::string& op ) {
m_op = op;
return *this;
}
ResultInfo ResultInfoBuilder::build() const
{
ResultData data = m_data;
data.reconstructedExpression = reconstructExpression();
if( m_isFalse ) {
if( m_op == "" ) {
data.capturedExpression = "!" + data.capturedExpression;
data.reconstructedExpression = "!" + data.reconstructedExpression;
}
else {
data.capturedExpression = "!(" + data.capturedExpression + ")";
data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
}
}
return ResultInfo( data );
}
std::string ResultInfoBuilder::reconstructExpression() const {
if( m_op == "" )
return m_lhs.empty() ? m_data.capturedExpression : m_op + m_lhs;
else if( m_op == "matches" )
return m_lhs + " " + m_rhs;
else if( m_op != "!" ) {
if( m_lhs.size() + m_rhs.size() < 30 )
return m_lhs + " " + m_op + " " + m_rhs;
else if( m_lhs.size() < 70 && m_rhs.size() < 70 )
return "\n\t" + m_lhs + "\n\t" + m_op + "\n\t" + m_rhs;
else
return "\n" + m_lhs + "\n" + m_op + "\n" + m_rhs + "\n\n";
}
else
return "{can't expand - use " + m_data.macroName + "_FALSE( " + m_data.capturedExpression.substr(1) + " ) instead of " + m_data.macroName + "( " + m_data.capturedExpression + " ) for better diagnostics}";
}
} // end namespace Catch
// #included from: catch_test_case_info.hpp
#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
namespace Catch {
TestCaseInfo::TestCaseInfo( ITestCase* testCase,
const char* name,
const char* description,
const SourceLineInfo& lineInfo )
: m_test( testCase ),
m_name( name ),
m_description( description ),
m_lineInfo( lineInfo ),
m_isHidden( startsWith( name, "./" ) )
{
TagExtracter( m_tags ).parse( m_description );
if( hasTag( "hide" ) )
m_isHidden = true;
}
TestCaseInfo::TestCaseInfo()
: m_test( NULL ),
m_name(),
m_description(),
m_isHidden( false )
{}
TestCaseInfo::TestCaseInfo( const TestCaseInfo& other, const std::string& name )
: m_test( other.m_test ),
m_name( name ),
m_description( other.m_description ),
m_tags( other.m_tags ),
m_lineInfo( other.m_lineInfo ),
m_isHidden( other.m_isHidden )
{}
TestCaseInfo::TestCaseInfo( const TestCaseInfo& other )
: m_test( other.m_test ),
m_name( other.m_name ),
m_description( other.m_description ),
m_tags( other.m_tags ),
m_lineInfo( other.m_lineInfo ),
m_isHidden( other.m_isHidden )
{}
void TestCaseInfo::invoke() const {
m_test->invoke();
}
const std::string& TestCaseInfo::getName() const {
return m_name;
}
const std::string& TestCaseInfo::getDescription() const {
return m_description;
}
const SourceLineInfo& TestCaseInfo::getLineInfo() const {
return m_lineInfo;
}
bool TestCaseInfo::isHidden() const {
return m_isHidden;
}
bool TestCaseInfo::hasTag( const std::string& tag ) const {
return m_tags.find( tag ) != m_tags.end();
}
bool TestCaseInfo::matchesTags( const std::string& tagPattern ) const {
TagExpression exp;
TagExpressionParser( exp ).parse( tagPattern );
return exp.matches( m_tags );
}
const std::set<std::string>& TestCaseInfo::getTags() const {
return m_tags;
}
void TestCaseInfo::swap( TestCaseInfo& other ) {
m_test.swap( other.m_test );
m_name.swap( other.m_name );
m_description.swap( other.m_description );
m_lineInfo.swap( other.m_lineInfo );
}
bool TestCaseInfo::operator == ( const TestCaseInfo& other ) const {
return m_test.get() == other.m_test.get() && m_name == other.m_name;
}
bool TestCaseInfo::operator < ( const TestCaseInfo& other ) const {
return m_name < other.m_name;
}
TestCaseInfo& TestCaseInfo::operator = ( const TestCaseInfo& other ) {
TestCaseInfo temp( other );
swap( temp );
return *this;
}
} // end namespace Catch
// #included from: ../reporters/catch_reporter_basic.hpp
#define TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED
// #included from: ../internal/catch_reporter_registrars.hpp
#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
namespace Catch {
template<typename T>
class ReporterRegistrar {
class ReporterFactory : public IReporterFactory {
virtual IReporter* create( const ReporterConfig& config ) const {
return new T( config );
}
virtual std::string getDescription() const {
return T::getDescription();
}
};
public:
ReporterRegistrar( const std::string& name ) {
getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
}
};
}
#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name );
namespace Catch {
class BasicReporter : public SharedImpl<IReporter> {
struct SpanInfo {
SpanInfo()
: emitted( false )
{}
SpanInfo( const std::string& spanName )
: name( spanName ),
emitted( false )
{}
SpanInfo( const SpanInfo& other )
: name( other.name ),
emitted( other.emitted )
{}
std::string name;
bool emitted;
};
public:
BasicReporter( const ReporterConfig& config )
: m_config( config ),
m_firstSectionInTestCase( true ),
m_aborted( false )
{}
virtual ~BasicReporter();
static std::string getDescription() {
return "Reports test results as lines of text";
}
private:
void ReportCounts( const std::string& label, const Counts& counts, const std::string& allPrefix = "All " ) {
if( counts.passed )
m_config.stream << counts.failed << " of " << counts.total() << " " << label << "s failed";
else
m_config.stream << ( counts.failed > 1 ? allPrefix : "" ) << pluralise( counts.failed, label ) << " failed";
}
void ReportCounts( const Totals& totals, const std::string& allPrefix = "All " ) {
if( totals.assertions.total() == 0 ) {
m_config.stream << "No tests ran";
}
else if( totals.assertions.failed ) {
TextColour colour( TextColour::ResultError );
ReportCounts( "test case", totals.testCases, allPrefix );
if( totals.testCases.failed > 0 ) {
m_config.stream << " (";
ReportCounts( "assertion", totals.assertions, allPrefix );
m_config.stream << ")";
}
}
else {
TextColour colour( TextColour::ResultSuccess );
m_config.stream << allPrefix << "tests passed ("
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
<< pluralise( totals.testCases.passed, "test case" ) << ")";
}
}
private: // IReporter
virtual bool shouldRedirectStdout() const {
return false;
}
virtual void StartTesting() {
m_testingSpan = SpanInfo();
}
virtual void Aborted() {
m_aborted = true;
}
virtual void EndTesting( const Totals& totals ) {
// Output the overall test results even if "Started Testing" was not emitted
if( m_aborted ) {
m_config.stream << "\n[Testing aborted. ";
ReportCounts( totals, "The first " );
}
else {
m_config.stream << "\n[Testing completed. ";
ReportCounts( totals );
}
m_config.stream << "]\n" << std::endl;
}
virtual void StartGroup( const std::string& groupName ) {
m_groupSpan = groupName;
}
virtual void EndGroup( const std::string& groupName, const Totals& totals ) {
if( m_groupSpan.emitted && !groupName.empty() ) {
m_config.stream << "[End of group: '" << groupName << "'. ";
ReportCounts( totals );
m_config.stream << "]\n" << std::endl;
m_groupSpan = SpanInfo();
}
}
virtual void StartTestCase( const TestCaseInfo& testInfo ) {
m_testSpan = testInfo.getName();
}
virtual void StartSection( const std::string& sectionName, const std::string& ) {
m_sectionSpans.push_back( SpanInfo( sectionName ) );
}
virtual void NoAssertionsInSection( const std::string& sectionName ) {
startSpansLazily();
TextColour colour( TextColour::ResultError );
m_config.stream << "\nNo assertions in section, '" << sectionName << "'\n" << std::endl;
}
virtual void NoAssertionsInTestCase( const std::string& testName ) {
startSpansLazily();
TextColour colour( TextColour::ResultError );
m_config.stream << "\nNo assertions in test case, '" << testName << "'\n" << std::endl;
}
virtual void EndSection( const std::string& sectionName, const Counts& assertions ) {
SpanInfo& sectionSpan = m_sectionSpans.back();
if( sectionSpan.emitted && !sectionSpan.name.empty() ) {
m_config.stream << "[End of section: '" << sectionName << "' ";
if( assertions.failed ) {
TextColour colour( TextColour::ResultError );
ReportCounts( "assertion", assertions);
}
else {
TextColour colour( TextColour::ResultSuccess );
m_config.stream << ( assertions.passed > 1 ? "All " : "" )
<< pluralise( assertions.passed, "assertion" ) << " passed" ;
}
m_config.stream << "]\n" << std::endl;
}
m_sectionSpans.pop_back();
}
virtual void Result( const ResultInfo& resultInfo ) {
if( !m_config.includeSuccessfulResults && resultInfo.getResultType() == ResultWas::Ok )
return;
startSpansLazily();
if( !resultInfo.getFilename().empty() ) {
TextColour colour( TextColour::FileName );
m_config.stream << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() );
}
if( resultInfo.hasExpression() ) {
TextColour colour( TextColour::OriginalExpression );
m_config.stream << resultInfo.getExpression();
if( resultInfo.ok() ) {
TextColour successColour( TextColour::Success );
m_config.stream << " succeeded";
}
else {
TextColour errorColour( TextColour::Error );
m_config.stream << " failed";
}
}
switch( resultInfo.getResultType() ) {
case ResultWas::ThrewException:
{
TextColour colour( TextColour::Error );
if( resultInfo.hasExpression() )
m_config.stream << " with unexpected";
else
m_config.stream << "Unexpected";
m_config.stream << " exception with message: '" << resultInfo.getMessage() << "'";
}
break;
case ResultWas::DidntThrowException:
{
TextColour colour( TextColour::Error );
if( resultInfo.hasExpression() )
m_config.stream << " because no exception was thrown where one was expected";
else
m_config.stream << "No exception thrown where one was expected";
}
break;
case ResultWas::Info:
streamVariableLengthText( "info", resultInfo.getMessage() );
break;
case ResultWas::Warning:
m_config.stream << "warning:\n'" << resultInfo.getMessage() << "'";
break;
case ResultWas::ExplicitFailure:
{
TextColour colour( TextColour::Error );
m_config.stream << "failed with message: '" << resultInfo.getMessage() << "'";
}
break;
case ResultWas::Unknown: // These cases are here to prevent compiler warnings
case ResultWas::Ok:
case ResultWas::FailureBit:
case ResultWas::ExpressionFailed:
case ResultWas::Exception:
if( !resultInfo.hasExpression() ) {
if( resultInfo.ok() ) {
TextColour colour( TextColour::Success );
m_config.stream << " succeeded";
}
else {
TextColour colour( TextColour::Error );
m_config.stream << " failed";
}
}
break;
}
if( resultInfo.hasExpandedExpression() ) {
m_config.stream << " for: ";
if( resultInfo.getExpandedExpression().size() > 40 )
m_config.stream << "\n";
if( resultInfo.getExpandedExpression().size() < 70 )
m_config.stream << "\t";
TextColour colour( TextColour::ReconstructedExpression );
m_config.stream << resultInfo.getExpandedExpression();
}
m_config.stream << std::endl;
}
virtual void EndTestCase( const TestCaseInfo& testInfo,
const Totals& totals,
const std::string& stdOut,
const std::string& stdErr ) {
if( !stdOut.empty() ) {
startSpansLazily();
streamVariableLengthText( "stdout", stdOut );
}
if( !stdErr.empty() ) {
startSpansLazily();
streamVariableLengthText( "stderr", stdErr );
}
if( m_testSpan.emitted ) {
m_config.stream << "[Finished: '" << testInfo.getName() << "' ";
ReportCounts( totals );
m_config.stream << "]" << std::endl;
}
}
private: // helpers
void startSpansLazily() {
if( !m_testingSpan.emitted ) {
if( m_config.name.empty() )
m_config.stream << "[Started testing]" << std::endl;
else
m_config.stream << "[Started testing: " << m_config.name << "]" << std::endl;
m_testingSpan.emitted = true;
}
if( !m_groupSpan.emitted && !m_groupSpan.name.empty() ) {
m_config.stream << "[Started group: '" << m_groupSpan.name << "']" << std::endl;
m_groupSpan.emitted = true;
}
if( !m_testSpan.emitted ) {
m_config.stream << std::endl << "[Running: " << m_testSpan.name << "]" << std::endl;
m_testSpan.emitted = true;
}
if( !m_sectionSpans.empty() ) {
SpanInfo& sectionSpan = m_sectionSpans.back();
if( !sectionSpan.emitted && !sectionSpan.name.empty() ) {
if( m_firstSectionInTestCase ) {
m_config.stream << "\n";
m_firstSectionInTestCase = false;
}
std::vector<SpanInfo>::iterator it = m_sectionSpans.begin();
std::vector<SpanInfo>::iterator itEnd = m_sectionSpans.end();
for(; it != itEnd; ++it ) {
SpanInfo& prevSpan = *it;
if( !prevSpan.emitted && !prevSpan.name.empty() ) {
m_config.stream << "[Started section: '" << prevSpan.name << "']" << std::endl;
prevSpan.emitted = true;
}
}
}
}
}
void streamVariableLengthText( const std::string& prefix, const std::string& text ) {
std::string trimmed = trim( text );
if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) {
m_config.stream << "[" << prefix << ": " << trimmed << "]\n";
}
else {
m_config.stream << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed
<< "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n";
}
}
private:
ReporterConfig m_config;
bool m_firstSectionInTestCase;
SpanInfo m_testingSpan;
SpanInfo m_groupSpan;
SpanInfo m_testSpan;
std::vector<SpanInfo> m_sectionSpans;
bool m_aborted;
};
} // end namespace Catch
// #included from: ../reporters/catch_reporter_xml.hpp
#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
// #included from: ../internal/catch_xmlwriter.hpp
#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
#include <sstream>
#include <iostream>
#include <string>
#include <vector>
namespace Catch {
class XmlWriter {
public:
class ScopedElement {
public:
ScopedElement( XmlWriter* writer )
: m_writer( writer )
{}
ScopedElement( const ScopedElement& other )
: m_writer( other.m_writer ){
other.m_writer = NULL;
}
~ScopedElement() {
if( m_writer )
m_writer->endElement();
}
ScopedElement& writeText( const std::string& text ) {
m_writer->writeText( text );
return *this;
}
template<typename T>
ScopedElement& writeAttribute( const std::string& name, const T& attribute ) {
m_writer->writeAttribute( name, attribute );
return *this;
}
private:
mutable XmlWriter* m_writer;
};
XmlWriter()
: m_tagIsOpen( false ),
m_needsNewline( false ),
m_os( &std::cout )
{}
XmlWriter( std::ostream& os )
: m_tagIsOpen( false ),
m_needsNewline( false ),
m_os( &os )
{}
~XmlWriter() {
while( !m_tags.empty() )
endElement();
}
XmlWriter& operator = ( const XmlWriter& other ) {
XmlWriter temp( other );
swap( temp );
return *this;
}
void swap( XmlWriter& other ) {
std::swap( m_tagIsOpen, other.m_tagIsOpen );
std::swap( m_needsNewline, other.m_needsNewline );
std::swap( m_tags, other.m_tags );
std::swap( m_indent, other.m_indent );
std::swap( m_os, other.m_os );
}
XmlWriter& startElement( const std::string& name ) {
ensureTagClosed();
newlineIfNecessary();
stream() << m_indent << "<" << name;
m_tags.push_back( name );
m_indent += " ";
m_tagIsOpen = true;
return *this;
}
ScopedElement scopedElement( const std::string& name ) {
ScopedElement scoped( this );
startElement( name );
return scoped;
}
XmlWriter& endElement() {
newlineIfNecessary();
m_indent = m_indent.substr( 0, m_indent.size()-2 );
if( m_tagIsOpen ) {
stream() << "/>\n";
m_tagIsOpen = false;
}
else {
stream() << m_indent << "</" << m_tags.back() << ">\n";
}
m_tags.pop_back();
return *this;
}
XmlWriter& writeAttribute( const std::string& name, const std::string& attribute ) {
if( !name.empty() && !attribute.empty() ) {
stream() << " " << name << "=\"";
writeEncodedText( attribute );
stream() << "\"";
}
return *this;
}
XmlWriter& writeAttribute( const std::string& name, bool attribute ) {
stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
return *this;
}
template<typename T>
XmlWriter& writeAttribute( const std::string& name, const T& attribute ) {
if( !name.empty() )
stream() << " " << name << "=\"" << attribute << "\"";
return *this;
}
XmlWriter& writeText( const std::string& text ) {
if( !text.empty() ){
bool tagWasOpen = m_tagIsOpen;
ensureTagClosed();
if( tagWasOpen )
stream() << m_indent;
writeEncodedText( text );
m_needsNewline = true;
}
return *this;
}
XmlWriter& writeComment( const std::string& text ) {
ensureTagClosed();
stream() << m_indent << "<!--" << text << "-->";
m_needsNewline = true;
return *this;
}
XmlWriter& writeBlankLine() {
ensureTagClosed();
stream() << "\n";
return *this;
}
private:
std::ostream& stream() {
return *m_os;
}
void ensureTagClosed() {
if( m_tagIsOpen ) {
stream() << ">\n";
m_tagIsOpen = false;
}
}
void newlineIfNecessary() {
if( m_needsNewline ) {
stream() << "\n";
m_needsNewline = false;
}
}
void writeEncodedText( const std::string& text ) {
static const char* charsToEncode = "<&\"";
std::string mtext = text;
std::string::size_type pos = mtext.find_first_of( charsToEncode );
while( pos != std::string::npos ) {
stream() << mtext.substr( 0, pos );
switch( mtext[pos] ) {
case '<':
stream() << "&lt;";
break;
case '&':
stream() << "&amp;";
break;
case '\"':
stream() << "&quot;";
break;
}
mtext = mtext.substr( pos+1 );
pos = mtext.find_first_of( charsToEncode );
}
stream() << mtext;
}
bool m_tagIsOpen;
bool m_needsNewline;
std::vector<std::string> m_tags;
std::string m_indent;
std::ostream* m_os;
};
}
namespace Catch {
class XmlReporter : public SharedImpl<IReporter> {
public:
XmlReporter( const ReporterConfig& config ) : m_config( config ) {}
static std::string getDescription() {
return "Reports test results as an XML document";
}
virtual ~XmlReporter();
private: // IReporter
virtual bool shouldRedirectStdout() const {
return true;
}
virtual void StartTesting() {
m_xml = XmlWriter( m_config.stream );
m_xml.startElement( "Catch" );
if( !m_config.name.empty() )
m_xml.writeAttribute( "name", m_config.name );
}
virtual void EndTesting( const Totals& totals ) {
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", totals.assertions.passed )
.writeAttribute( "failures", totals.assertions.failed );
m_xml.endElement();
}
virtual void StartGroup( const std::string& groupName ) {
m_xml.startElement( "Group" )
.writeAttribute( "name", groupName );
}
virtual void EndGroup( const std::string&, const Totals& totals ) {
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", totals.assertions.passed )
.writeAttribute( "failures", totals.assertions.failed );
m_xml.endElement();
}
virtual void StartSection( const std::string& sectionName, const std::string& description ) {
m_xml.startElement( "Section" )
.writeAttribute( "name", sectionName )
.writeAttribute( "description", description );
}
virtual void NoAssertionsInSection( const std::string& ) {}
virtual void NoAssertionsInTestCase( const std::string& ) {}
virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", assertions.passed )
.writeAttribute( "failures", assertions.failed );
m_xml.endElement();
}
virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.getName() );
m_currentTestSuccess = true;
}
virtual void Result( const Catch::ResultInfo& resultInfo ) {
if( !m_config.includeSuccessfulResults && resultInfo.getResultType() == ResultWas::Ok )
return;
if( resultInfo.hasExpression() ) {
m_xml.startElement( "Expression" )
.writeAttribute( "success", resultInfo.ok() )
.writeAttribute( "filename", resultInfo.getFilename() )
.writeAttribute( "line", resultInfo.getLine() );
m_xml.scopedElement( "Original" )
.writeText( resultInfo.getExpression() );
m_xml.scopedElement( "Expanded" )
.writeText( resultInfo.getExpandedExpression() );
m_currentTestSuccess &= resultInfo.ok();
}
switch( resultInfo.getResultType() ) {
case ResultWas::ThrewException:
m_xml.scopedElement( "Exception" )
.writeAttribute( "filename", resultInfo.getFilename() )
.writeAttribute( "line", resultInfo.getLine() )
.writeText( resultInfo.getMessage() );
m_currentTestSuccess = false;
break;
case ResultWas::Info:
m_xml.scopedElement( "Info" )
.writeText( resultInfo.getMessage() );
break;
case ResultWas::Warning:
m_xml.scopedElement( "Warning" )
.writeText( resultInfo.getMessage() );
break;
case ResultWas::ExplicitFailure:
m_xml.scopedElement( "Failure" )
.writeText( resultInfo.getMessage() );
m_currentTestSuccess = false;
break;
case ResultWas::Unknown:
case ResultWas::Ok:
case ResultWas::FailureBit:
case ResultWas::ExpressionFailed:
case ResultWas::Exception:
case ResultWas::DidntThrowException:
break;
}
if( resultInfo.hasExpression() )
m_xml.endElement();
}
virtual void Aborted() {
// !TBD
}
virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
m_xml.endElement();
}
private:
ReporterConfig m_config;
bool m_currentTestSuccess;
XmlWriter m_xml;
};
} // end namespace Catch
// #included from: ../reporters/catch_reporter_junit.hpp
#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
namespace Catch {
class JunitReporter : public SharedImpl<IReporter> {
struct TestStats {
std::string m_element;
std::string m_resultType;
std::string m_message;
std::string m_content;
};
struct TestCaseStats {
TestCaseStats( const std::string& name = std::string() ) :m_name( name ){}
double m_timeInSeconds;
std::string m_status;
std::string m_className;
std::string m_name;
std::vector<TestStats> m_testStats;
};
struct Stats {
Stats( const std::string& name = std::string() )
: m_testsCount( 0 ),
m_failuresCount( 0 ),
m_disabledCount( 0 ),
m_errorsCount( 0 ),
m_timeInSeconds( 0 ),
m_name( name )
{}
std::size_t m_testsCount;
std::size_t m_failuresCount;
std::size_t m_disabledCount;
std::size_t m_errorsCount;
double m_timeInSeconds;
std::string m_name;
std::vector<TestCaseStats> m_testCaseStats;
};
public:
JunitReporter( const ReporterConfig& config )
: m_config( config ),
m_testSuiteStats( "AllTests" ),
m_currentStats( &m_testSuiteStats )
{}
virtual ~JunitReporter();
static std::string getDescription() {
return "Reports test results in an XML format that looks like Ant's junitreport target";
}
private: // IReporter
virtual bool shouldRedirectStdout() const {
return true;
}
virtual void StartTesting(){}
virtual void StartGroup( const std::string& groupName ) {
m_statsForSuites.push_back( Stats( groupName ) );
m_currentStats = &m_statsForSuites.back();
}
virtual void EndGroup( const std::string&, const Totals& totals ) {
m_currentStats->m_testsCount = totals.assertions.total();
m_currentStats = &m_testSuiteStats;
}
virtual void StartSection( const std::string&, const std::string& ){}
virtual void NoAssertionsInSection( const std::string& ) {}
virtual void NoAssertionsInTestCase( const std::string& ) {}
virtual void EndSection( const std::string&, const Counts& ) {}
virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
m_currentStats->m_testCaseStats.push_back( TestCaseStats( testInfo.getName() ) );
}
virtual void Result( const Catch::ResultInfo& resultInfo ) {
if( resultInfo.getResultType() != ResultWas::Ok || m_config.includeSuccessfulResults ) {
TestCaseStats& testCaseStats = m_currentStats->m_testCaseStats.back();
TestStats stats;
std::ostringstream oss;
if( !resultInfo.getMessage().empty() )
oss << resultInfo.getMessage() << " at ";
oss << SourceLineInfo( resultInfo.getFilename(), resultInfo.getLine() );
stats.m_content = oss.str();
stats.m_message = resultInfo.getExpandedExpression();
stats.m_resultType = resultInfo.getTestMacroName();
switch( resultInfo.getResultType() ) {
case ResultWas::ThrewException:
stats.m_element = "error";
m_currentStats->m_errorsCount++;
break;
case ResultWas::Info:
stats.m_element = "info"; // !TBD ?
break;
case ResultWas::Warning:
stats.m_element = "warning"; // !TBD ?
break;
case ResultWas::ExplicitFailure:
stats.m_element = "failure";
m_currentStats->m_failuresCount++;
break;
case ResultWas::ExpressionFailed:
stats.m_element = "failure";
m_currentStats->m_failuresCount++;
break;
case ResultWas::Ok:
stats.m_element = "success";
break;
case ResultWas::Unknown:
case ResultWas::FailureBit:
case ResultWas::Exception:
case ResultWas::DidntThrowException:
break;
}
testCaseStats.m_testStats.push_back( stats );
}
}
virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string& stdOut, const std::string& stdErr ) {
if( !stdOut.empty() )
m_stdOut << stdOut << "\n";
if( !stdErr.empty() )
m_stdErr << stdErr << "\n";
}
virtual void Aborted() {
// !TBD
}
virtual void EndTesting( const Totals& ) {
std::ostream& str = m_config.stream;
{
XmlWriter xml( str );
if( m_statsForSuites.size() > 0 )
xml.startElement( "testsuites" );
std::vector<Stats>::const_iterator it = m_statsForSuites.begin();
std::vector<Stats>::const_iterator itEnd = m_statsForSuites.end();
for(; it != itEnd; ++it ) {
XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
xml.writeAttribute( "name", it->m_name );
xml.writeAttribute( "errors", it->m_errorsCount );
xml.writeAttribute( "failures", it->m_failuresCount );
xml.writeAttribute( "tests", it->m_testsCount );
xml.writeAttribute( "hostname", "tbd" );
xml.writeAttribute( "time", "tbd" );
xml.writeAttribute( "timestamp", "tbd" );
OutputTestCases( xml, *it );
}
xml.scopedElement( "system-out" ).writeText( trim( m_stdOut.str() ) );
xml.scopedElement( "system-err" ).writeText( trim( m_stdErr.str() ) );
}
}
void OutputTestCases( XmlWriter& xml, const Stats& stats ) {
std::vector<TestCaseStats>::const_iterator it = stats.m_testCaseStats.begin();
std::vector<TestCaseStats>::const_iterator itEnd = stats.m_testCaseStats.end();
for(; it != itEnd; ++it ) {
xml.writeBlankLine();
xml.writeComment( "Test case" );
XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
xml.writeAttribute( "classname", it->m_className );
xml.writeAttribute( "name", it->m_name );
xml.writeAttribute( "time", "tbd" );
OutputTestResult( xml, *it );
}
}
void OutputTestResult( XmlWriter& xml, const TestCaseStats& stats ) {
std::vector<TestStats>::const_iterator it = stats.m_testStats.begin();
std::vector<TestStats>::const_iterator itEnd = stats.m_testStats.end();
for(; it != itEnd; ++it ) {
if( it->m_element != "success" ) {
XmlWriter::ScopedElement e = xml.scopedElement( it->m_element );
xml.writeAttribute( "message", it->m_message );
xml.writeAttribute( "type", it->m_resultType );
if( !it->m_content.empty() )
xml.writeText( it->m_content );
}
}
}
private:
ReporterConfig m_config;
bool m_currentTestSuccess;
Stats m_testSuiteStats;
Stats* m_currentStats;
std::vector<Stats> m_statsForSuites;
std::ostringstream m_stdOut;
std::ostringstream m_stdErr;
};
} // end namespace Catch
namespace Catch {
NonCopyable::~NonCopyable() {}
IShared::~IShared() {}
StreamBufBase::~StreamBufBase() {}
IContext::~IContext() {}
IResultCapture::~IResultCapture() {}
ITestCase::~ITestCase() {}
ITestCaseRegistry::~ITestCaseRegistry() {}
IRegistryHub::~IRegistryHub() {}
IMutableRegistryHub::~IMutableRegistryHub() {}
IExceptionTranslator::~IExceptionTranslator() {}
IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
IReporter::~IReporter() {}
IReporterFactory::~IReporterFactory() {}
IReporterRegistry::~IReporterRegistry() {}
BasicReporter::~BasicReporter() {}
IRunner::~IRunner() {}
IMutableContext::~IMutableContext() {}
IConfig::~IConfig() {}
XmlReporter::~XmlReporter() {}
JunitReporter::~JunitReporter() {}
TestRegistry::~TestRegistry() {}
FreeFunctionTestCase::~FreeFunctionTestCase() {}
IGeneratorInfo::~IGeneratorInfo() {}
IGeneratorsForTest::~IGeneratorsForTest() {}
TagParser::~TagParser() {}
TagExtracter::~TagExtracter() {}
TagExpressionParser::~TagExpressionParser() {}
Matchers::Impl::StdString::Equals::~Equals() {}
Matchers::Impl::StdString::Contains::~Contains() {}
Matchers::Impl::StdString::StartsWith::~StartsWith() {}
Matchers::Impl::StdString::EndsWith::~EndsWith() {}
void Config::dummy() {}
INTERNAL_CATCH_REGISTER_REPORTER( "basic", BasicReporter )
INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif
#ifdef CATCH_CONFIG_MAIN
// #included from: internal/catch_default_main.hpp
#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
#ifndef __OBJC__
// Standard C/C++ main entry point
int main (int argc, char * const argv[]) {
return Catch::Main( argc, argv );
}
#else // __OBJC__
// Objective-C entry point
int main (int argc, char * const argv[]) {
#if !CATCH_ARC_ENABLED
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
#endif
Catch::registerTestMethods();
int result = Catch::Main( argc, (char* const*)argv );
#if !CATCH_ARC_ENABLED
[pool drain];
#endif
return result;
}
#endif // __OBJC__
#endif
//////
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
#ifdef CATCH_CONFIG_PREFIX_ALL
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, false, true, "CATCH_REQUIRE" )
#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, true, "CATCH_REQUIRE_FALSE" )
#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., true, "CATCH_REQUIRE_THROWS" )
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, true, "CATCH_REQUIRE_THROWS_AS" )
#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, true, "CATCH_REQUIRE_NOTHROW" )
#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, false, false, "CATCH_CHECK" )
#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, false, "CATCH_CHECK_FALSE" )
#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, false, false, "CATCH_CHECKED_IF" )
#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, false, false, "CATCH_CHECKED_ELSE" )
#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., false, "CATCH_CHECK_THROWS" )
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, false, "CATCH_CHECK_THROWS_AS" )
#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, false, "CATCH_CHECK_NOTHROW" )
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, false, "CATCH_CHECK_THAT" )
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, true, "CATCH_REQUIRE_THAT" )
#define CATCH_INFO( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Info, false, "CATCH_INFO" )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Warning, false, "CATCH_WARN" )
#define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::ExplicitFailure, true, "CATCH_FAIL" )
#define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Ok, false, "CATCH_SUCCEED" )
#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_SCOPED_INFO( msg )
#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_MSG( #msg " := " << msg, Catch::ResultWas::Info, false, "CATCH_CAPTURE" )
#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_SCOPED_INFO( #msg " := " << msg )
#define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
#define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
#define CATCH_TEST_CASE_NORETURN( name, description ) INTERNAL_CATCH_TESTCASE_NORETURN( name, description )
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "Anonymous test case" )
#define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
///////////////
// Still to be implemented
//#define CHECK_NOFAIL( expr ) // !TBD - reports violation, but doesn't fail Test
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, false, true, "REQUIRE" )
#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, true, "REQUIRE_FALSE" )
#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., true, "REQUIRE_THROWS" )
#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, true, "REQUIRE_THROWS_AS" )
#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, true, "REQUIRE_NOTHROW" )
#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, false, false, "CHECK" )
#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, true, false, "CHECK_FALSE" )
#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, false, false, "CHECKED_IF" )
#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, false, false, "CHECKED_ELSE" )
#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., false, "CHECK_THROWS" )
#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, false, "CHECK_THROWS_AS" )
#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, false, "CHECK_NOTHROW" )
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, false, "CHECK_THAT" )
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, true, "REQUIRE_THAT" )
#define INFO( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Info, false, "INFO" )
#define WARN( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Warning, false, "WARN" )
#define FAIL( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::ExplicitFailure, true, "FAIL" )
#define SUCCEED( msg ) INTERNAL_CATCH_MSG( msg, Catch::ResultWas::Ok, false, "SUCCEED" )
#define SCOPED_INFO( msg ) INTERNAL_CATCH_SCOPED_INFO( msg )
#define CAPTURE( msg ) INTERNAL_CATCH_MSG( #msg " := " << msg, Catch::ResultWas::Info, false, "CAPTURE" )
#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_SCOPED_INFO( #msg " := " << msg )
#define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
#define TEST_CASE_NORETURN( name, description ) INTERNAL_CATCH_TESTCASE_NORETURN( name, description )
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "Anonymous test case" )
#define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
#endif
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
using Catch::Detail::Approx;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED