/* * Generated: 2012-09-29 20:53:48.580228 * ---------------------------------------------------------- * 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 #include #include 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 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 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 inline void forEach( ContainerT& container, Function function ) { std::for_each( container.begin(), container.end(), function ); } template 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( __LINE__ ) ) #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); #include 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 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 #include #include 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 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 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 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& getAllTests() const = 0; virtual std::vector getMatchingTestCases( const std::string& rawTestSpec ) const = 0; }; } namespace Catch { template class MethodTestCase : public SharedImpl { 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 AutoReg( void (C::*method)(), const char* name, const char* description, const SourceLineInfo& lineInfo ) { registerTestCase( new MethodTestCase( 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 #ifdef __OBJC__ // #included from: catch_objc_arc.hpp #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED #import #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 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 inline std::string makeString( const T& value ) { std::ostringstream oss; oss << value; return oss.str(); } template inline std::string makeString( T* p ) { if( !p ) return INTERNAL_CATCH_STRINGIFY( NULL ); std::ostringstream oss; oss << p; return oss.str(); } template 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 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( 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( 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( 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( 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 // #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 }; }; 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 { class ResultInfo { public: ResultInfo(); ResultInfo( const char* expr, ResultWas::OfType result, bool isNot, const SourceLineInfo& lineInfo, const char* macroName, const char* message ); ~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: std::string getExpandedExpressionInternal() const; bool isNotExpression( const char* expr ); protected: std::string m_macroName; SourceLineInfo m_lineInfo; std::string m_expr, m_lhs, m_rhs, m_op; std::string m_message; ResultWas::OfType m_result; bool m_isNot; }; } // 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 struct OperatorTraits { static const char* getName(){ return "*error*"; } }; template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; template<> struct OperatorTraits{ 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 class Evaluator{}; template struct Evaluator { static bool evaluate( const T1& lhs, const T2& rhs) { return const_cast( lhs ) == const_cast( rhs ); } }; template struct Evaluator { static bool evaluate( const T1& lhs, const T2& rhs ) { return const_cast( lhs ) != const_cast( rhs ); } }; template struct Evaluator { static bool evaluate( const T1& lhs, const T2& rhs ) { return const_cast( lhs ) < const_cast( rhs ); } }; template struct Evaluator { static bool evaluate( const T1& lhs, const T2& rhs ) { return const_cast( lhs ) > const_cast( rhs ); } }; template struct Evaluator { static bool evaluate( const T1& lhs, const T2& rhs ) { return const_cast( lhs ) >= const_cast( rhs ); } }; template struct Evaluator { static bool evaluate( const T1& lhs, const T2& rhs ) { return const_cast( lhs ) <= const_cast( rhs ); } }; template bool applyEvaluator( const T1& lhs, const T2& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // "base" overload template bool compare( const T1& lhs, const T2& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // unsigned X to int template bool compare( unsigned int lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // unsigned X to long template bool compare( unsigned int lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // int to unsigned X template bool compare( int lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // long to unsigned X template bool compare( long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // pointer to long (when comparing against NULL) template bool compare( long lhs, const T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( const T* lhs, long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } template bool compare( T* lhs, long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } // pointer to int (when comparing against NULL) template bool compare( int lhs, const T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( int lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( const T* lhs, int rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } template bool compare( T* lhs, int rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( 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 ResultInfo { public: ResultInfoBuilder(); ResultInfoBuilder( const char* expr, bool isNot, const SourceLineInfo& lineInfo, const char* macroName, const char* message = "" ); void setResultType( ResultWas::OfType result ); void setMessage( const std::string& message ); void setLineInfo( const SourceLineInfo& lineInfo ); void setLhs( const std::string& lhs ); void setRhs( const std::string& rhs ); void setOp( const std::string& op ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( const RhsT& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( const RhsT& ); private: friend class ExpressionBuilder; template friend class Expression; template friend class PtrExpression; ResultInfoBuilder& captureBoolExpression( bool result ); template ResultInfoBuilder& captureExpression( const T1& lhs, const T2& rhs ) { setResultType( Internal::compare( lhs, rhs ) ? ResultWas::Ok : ResultWas::ExpressionFailed ); m_lhs = Catch::toString( lhs ); m_rhs = Catch::toString( rhs ); m_op = Internal::OperatorTraits::getName(); return *this; } template ResultInfoBuilder& captureExpression( const T* lhs, int rhs ) { return captureExpression( lhs, reinterpret_cast( rhs ) ); } }; } // end namespace Catch namespace Catch { template class Expression { void operator = ( const Expression& ); public: Expression( ResultInfoBuilder& result, T lhs ) : m_result( result ), m_lhs( lhs ) {} template ResultInfoBuilder& operator == ( const RhsT& rhs ) { return m_result.captureExpression( m_lhs, rhs ); } template ResultInfoBuilder& operator != ( const RhsT& rhs ) { return m_result.captureExpression( m_lhs, rhs ); } template ResultInfoBuilder& operator < ( const RhsT& rhs ) { return m_result.captureExpression( m_lhs, rhs ); } template ResultInfoBuilder& operator > ( const RhsT& rhs ) { return m_result.captureExpression( m_lhs, rhs ); } template ResultInfoBuilder& operator <= ( const RhsT& rhs ) { return m_result.captureExpression( m_lhs, rhs ); } template ResultInfoBuilder& operator >= ( const RhsT& rhs ) { return m_result.captureExpression( m_lhs, rhs ); } ResultInfoBuilder& operator == ( bool rhs ) { return m_result.captureExpression( m_lhs, rhs ); } ResultInfoBuilder& operator != ( bool rhs ) { return m_result.captureExpression( m_lhs, rhs ); } operator ResultInfoBuilder& () { return m_result.captureBoolExpression( m_lhs ); } template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( const RhsT& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( const RhsT& ); private: ResultInfoBuilder& m_result; T m_lhs; }; } // end namespace Catch #include namespace Catch { class ExpressionBuilder { public: ExpressionBuilder( const SourceLineInfo& lineInfo, const char* macroName, const char* expr = "", bool isNot = false ) : m_result( expr, isNot, lineInfo, macroName ), m_messageStream() {} template Expression operator->* ( const T & operand ) { Expression expr( m_result, operand ); return expr; } Expression operator->* ( bool value ) { Expression expr( m_result, value ); return expr; } template ExpressionBuilder& operator << ( const T & value ) { m_messageStream << Catch::toString( value ); return *this; } template ExpressionBuilder& acceptMatcher( const MatcherT& matcher, const ArgT& arg, const std::string& matcherCallAsString ) { std::string matcherAsString = Catch::toString( matcher ); if( matcherAsString == "{?}" ) matcherAsString = matcherCallAsString; m_result.setLhs( Catch::toString( arg ) ); m_result.setRhs( matcherAsString ); m_result.setOp( "matches" ); m_result.setResultType( matcher( arg ) ? ResultWas::Ok : ResultWas::ExpressionFailed ); return *this; } template ExpressionBuilder& acceptMatcher( const MatcherT& matcher, ArgT* arg, const std::string& matcherCallAsString ) { std::string matcherAsString = Catch::toString( matcher ); if( matcherAsString == "{?}" ) matcherAsString = matcherCallAsString; m_result.setLhs( Catch::toString( arg ) ); m_result.setRhs( matcherAsString ); m_result.setOp( "matches" ); m_result.setResultType( matcher( 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 // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED #include 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 #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 #include #include #include #include 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 namespace Catch { struct TestFailureException{}; class ScopedInfo { public: ScopedInfo() : m_oss() { getCurrentContext().getResultCapture().pushScopedInfo( this ); } ~ScopedInfo() { getCurrentContext().getResultCapture().popScopedInfo( this ); } template ScopedInfo& operator << ( const T& value ) { m_oss << value; return *this; } ResultInfo getInfo () const { return ResultInfo( "", ResultWas::Info, false, SourceLineInfo(), "SCOPED_INFO", m_oss.str().c_str() ); } 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, isNot, stopOnFailure, macroName ) \ do { try { \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr, isNot )->*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, isNot, stopOnFailure, macroName ) \ INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \ if( Catch::getCurrentContext().getResultCapture().getLastResult()->ok() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( expr, isNot, stopOnFailure, macroName ) \ INTERNAL_CATCH_TEST( expr, isNot, 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 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 #include #include #include namespace Catch { template struct IGenerator { virtual ~IGenerator() {} virtual T getValue( std::size_t index ) const = 0; virtual std::size_t size () const = 0; }; template class BetweenGenerator : public IGenerator { 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( index ); } virtual std::size_t size() const { return static_cast( 1+m_to-m_from ); } private: T m_from; T m_to; }; template class ValuesGenerator : public IGenerator { 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 m_values; }; template 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_iterator it = m_composed.begin(); typename std::vector*>::const_iterator itEnd = m_composed.end(); for( size_t index = 0; it != itEnd; ++it ) { const IGenerator* 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* generator ) { m_totalSize += generator->size(); m_composed.push_back( generator ); } CompositeGenerator& then( CompositeGenerator& other ) { move( other ); return *this; } CompositeGenerator& then( T value ) { ValuesGenerator* valuesGen = new ValuesGenerator(); 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*> m_composed; std::string m_fileInfo; size_t m_totalSize; }; namespace Generators { template CompositeGenerator between( T from, T to ) { CompositeGenerator generators; generators.add( new BetweenGenerator( from, to ) ); return generators; } template CompositeGenerator values( T val1, T val2 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3 ){ CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3, T val4 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); 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 // #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 #include 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& 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 m_test; std::string m_name; std::string m_description; std::set m_tags; SourceLineInfo m_lineInfo; bool m_isHidden; }; } // #included from: catch_tags.hpp #define TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED #include #include #include #include #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& 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; } std::set& 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 TagMap; public: void add( const Tag& tag ) { m_tags.insert( std::make_pair( tag.getName(), tag ) ); } // needed? Tag find( const std::string& name ) const { TagMap::const_iterator it = m_tags.find( name ); if( it == m_tags.end() ) return Tag(); else return it->second; } bool empty() const { return m_tags.empty(); } bool matches( const std::set& 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& tags ) const { std::vector::const_iterator it = m_tagSets.begin(); std::vector::const_iterator itEnd = m_tagSets.end(); for(; it != itEnd; ++it ) if( it->matches( tags ) ) return true; return false; } private: friend class TagExpressionParser; std::vector 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 ); } bool m_isNegated; TagSet m_currentTagSet; TagExpression& m_exp; }; } // end namespace Catch #include #include 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::const_iterator it = m_tagExpressions.begin(); std::vector::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::const_iterator it = m_inclusionFilters.begin(); std::vector::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::const_iterator it = m_exclusionFilters.begin(); std::vector::const_iterator itEnd = m_exclusionFilters.end(); for(; it != itEnd; ++it ) if( !it->shouldInclude( testCase ) ) return false; return true; } private: std::vector m_tagExpressions; std::vector m_inclusionFilters; std::vector 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 namespace Catch { class StreamBufBase : public std::streambuf { public: virtual ~StreamBufBase(); }; } #include #include namespace Catch { template 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( c ) ) ); else sputc( static_cast( c ) ); } return 0; } int sync() { if( pbase() != pptr() ) { m_writer( std::string( pbase(), static_cast( 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 #include #include #include 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 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( m_data.listSpec & List::WhatMask ); } List::What listAs() const { return static_cast( 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 #include #include 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 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 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 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 ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { getMutableRegistryHub().registerTranslator ( new ExceptionTranslator( 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 #include namespace Catch { namespace Detail { class Approx { public: explicit Approx ( double value ) : m_epsilon( std::numeric_limits::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( 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 { namespace StdString { struct Equals { Equals( const std::string& str ) : m_str( str ){} bool operator()( const std::string& str ) const { return str == m_str; } friend std::ostream& operator<<( std::ostream& os, const Equals& matcher ) { os << "equals: \"" << matcher.m_str << "\""; return os; } std::string m_str; }; struct Contains { Contains( const std::string& substr ) : m_substr( substr ){} bool operator()( const std::string& str ) const { return str.find( m_substr ) != std::string::npos; } friend std::ostream& operator<<( std::ostream& os, const Contains& matcher ) { os << "contains: \"" << matcher.m_substr << "\""; return os; } std::string m_substr; }; struct StartsWith { StartsWith( const std::string& substr ) : m_substr( substr ){} bool operator()( const std::string& str ) const { return str.find( m_substr ) == 0; } friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher ) { os << "starts with: \"" << matcher.m_substr << "\""; return os; } std::string m_substr; }; struct EndsWith { EndsWith( const std::string& substr ) : m_substr( substr ){} bool operator()( const std::string& str ) const { return str.find( m_substr ) == str.size() - m_substr.size(); } friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher ) { os << "ends with: \"" << matcher.m_substr << "\""; return os; } std::string m_substr; }; } // namespace StdString } // namespace Impl 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 namespace Catch { class TestCaseInfo; struct IRunner { virtual ~IRunner(); }; } #ifdef __OBJC__ // #included from: internal/catch_objc.hpp #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED #import #include // 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 { 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 m_args; }; class CommandParser { public: CommandParser( int argc, char const * const * argv ) : m_argc( static_cast( 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 { 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::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( m_minArgs ), "argument" ); else if( m_minArgs == m_maxArgs ) oss <<"Expected " << pluralise( static_cast( 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::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( m_minArgs ); } bool tooManyArgs( const Command& args ) const { return m_maxArgs >= 0 && args.argsCount() > static_cast( m_maxArgs ); } std::vector 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 "[