jamie@264: /* jamie@264: * CATCH v1.0 build 53 (master branch) jamie@264: * Generated: 2014-08-20 08:08:19.533804 jamie@264: * ---------------------------------------------------------- jamie@264: * This file has been merged from multiple headers. Please don't edit it directly jamie@264: * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. jamie@264: * jamie@264: * Distributed under the Boost Software License, Version 1.0. (See accompanying jamie@264: * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) jamie@264: */ jamie@264: #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED jamie@264: #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED jamie@264: jamie@264: #define TWOBLUECUBES_CATCH_HPP_INCLUDED jamie@264: jamie@264: // #included from: internal/catch_suppress_warnings.h jamie@264: jamie@264: #define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic ignored "-Wglobal-constructors" jamie@264: #pragma clang diagnostic ignored "-Wvariadic-macros" jamie@264: #pragma clang diagnostic ignored "-Wc99-extensions" jamie@264: #pragma clang diagnostic ignored "-Wunused-variable" jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Wpadded" jamie@264: #pragma clang diagnostic ignored "-Wc++98-compat" jamie@264: #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" jamie@264: #elif defined __GNUC__ jamie@264: #pragma GCC diagnostic ignored "-Wvariadic-macros" jamie@264: #pragma GCC diagnostic ignored "-Wunused-variable" jamie@264: #pragma GCC diagnostic push jamie@264: #pragma GCC diagnostic ignored "-Wpadded" jamie@264: #endif jamie@264: jamie@264: #ifdef CATCH_CONFIG_MAIN jamie@264: # define CATCH_CONFIG_RUNNER jamie@264: #endif jamie@264: jamie@264: #ifdef CATCH_CONFIG_RUNNER jamie@264: # ifndef CLARA_CONFIG_MAIN jamie@264: # define CLARA_CONFIG_MAIN_NOT_DEFINED jamie@264: # define CLARA_CONFIG_MAIN jamie@264: # endif jamie@264: #endif jamie@264: jamie@264: // #included from: internal/catch_notimplemented_exception.h jamie@264: #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED jamie@264: jamie@264: // #included from: catch_common.h jamie@264: #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED jamie@264: jamie@264: #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line jamie@264: #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) jamie@264: #define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) jamie@264: jamie@264: #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr jamie@264: #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: // #included from: catch_compiler_capabilities.h jamie@264: #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED jamie@264: jamie@264: // Much of the following code is based on Boost (1.53) jamie@264: jamie@264: #ifdef __clang__ jamie@264: jamie@264: # if __has_feature(cxx_nullptr) jamie@264: # define CATCH_CONFIG_CPP11_NULLPTR jamie@264: # endif jamie@264: jamie@264: # if __has_feature(cxx_noexcept) jamie@264: # define CATCH_CONFIG_CPP11_NOEXCEPT jamie@264: # endif jamie@264: jamie@264: #endif // __clang__ jamie@264: jamie@264: //////////////////////////////////////////////////////////////////////////////// jamie@264: // Borland jamie@264: #ifdef __BORLANDC__ jamie@264: jamie@264: #if (__BORLANDC__ > 0x582 ) jamie@264: //#define CATCH_CONFIG_SFINAE // Not confirmed jamie@264: #endif jamie@264: jamie@264: #endif // __BORLANDC__ jamie@264: jamie@264: //////////////////////////////////////////////////////////////////////////////// jamie@264: // EDG jamie@264: #ifdef __EDG_VERSION__ jamie@264: jamie@264: #if (__EDG_VERSION__ > 238 ) jamie@264: //#define CATCH_CONFIG_SFINAE // Not confirmed jamie@264: #endif jamie@264: jamie@264: #endif // __EDG_VERSION__ jamie@264: jamie@264: //////////////////////////////////////////////////////////////////////////////// jamie@264: // Digital Mars jamie@264: #ifdef __DMC__ jamie@264: jamie@264: #if (__DMC__ > 0x840 ) jamie@264: //#define CATCH_CONFIG_SFINAE // Not confirmed jamie@264: #endif jamie@264: jamie@264: #endif // __DMC__ jamie@264: jamie@264: //////////////////////////////////////////////////////////////////////////////// jamie@264: // GCC jamie@264: #ifdef __GNUC__ jamie@264: jamie@264: #if __GNUC__ < 3 jamie@264: jamie@264: #if (__GNUC_MINOR__ >= 96 ) jamie@264: //#define CATCH_CONFIG_SFINAE jamie@264: #endif jamie@264: jamie@264: #elif __GNUC__ >= 3 jamie@264: jamie@264: // #define CATCH_CONFIG_SFINAE // Taking this out completely for now jamie@264: jamie@264: #endif // __GNUC__ < 3 jamie@264: jamie@264: #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) jamie@264: jamie@264: #define CATCH_CONFIG_CPP11_NULLPTR jamie@264: #endif jamie@264: jamie@264: #endif // __GNUC__ jamie@264: jamie@264: //////////////////////////////////////////////////////////////////////////////// jamie@264: // Visual C++ jamie@264: #ifdef _MSC_VER jamie@264: jamie@264: #if (_MSC_VER >= 1310 ) // (VC++ 7.0+) jamie@264: //#define CATCH_CONFIG_SFINAE // Not confirmed jamie@264: #endif jamie@264: jamie@264: #endif // _MSC_VER jamie@264: jamie@264: // Use variadic macros if the compiler supports them jamie@264: #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ jamie@264: ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ jamie@264: ( defined __GNUC__ && __GNUC__ >= 3 ) || \ jamie@264: ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) jamie@264: jamie@264: #ifndef CATCH_CONFIG_NO_VARIADIC_MACROS jamie@264: #define CATCH_CONFIG_VARIADIC_MACROS jamie@264: #endif jamie@264: jamie@264: #endif jamie@264: jamie@264: //////////////////////////////////////////////////////////////////////////////// jamie@264: // C++ language feature support jamie@264: jamie@264: // detect language version: jamie@264: #if (__cplusplus == 201103L) jamie@264: # define CATCH_CPP11 jamie@264: # define CATCH_CPP11_OR_GREATER jamie@264: #elif (__cplusplus >= 201103L) jamie@264: # define CATCH_CPP11_OR_GREATER jamie@264: #endif jamie@264: jamie@264: // noexcept support: jamie@264: #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) jamie@264: # define CATCH_NOEXCEPT noexcept jamie@264: # define CATCH_NOEXCEPT_IS(x) noexcept(x) jamie@264: #else jamie@264: # define CATCH_NOEXCEPT throw() jamie@264: # define CATCH_NOEXCEPT_IS(x) jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class NonCopyable { jamie@264: NonCopyable( NonCopyable const& ); jamie@264: void operator = ( NonCopyable const& ); jamie@264: protected: jamie@264: NonCopyable() {} jamie@264: virtual ~NonCopyable(); jamie@264: }; jamie@264: jamie@264: class SafeBool { jamie@264: public: jamie@264: typedef void (SafeBool::*type)() const; jamie@264: jamie@264: static type makeSafe( bool value ) { jamie@264: return value ? &SafeBool::trueValue : 0; jamie@264: } jamie@264: private: jamie@264: void trueValue() const {} jamie@264: }; jamie@264: jamie@264: template jamie@264: inline void deleteAll( ContainerT& container ) { jamie@264: typename ContainerT::const_iterator it = container.begin(); jamie@264: typename ContainerT::const_iterator itEnd = container.end(); jamie@264: for(; it != itEnd; ++it ) jamie@264: delete *it; jamie@264: } jamie@264: template jamie@264: inline void deleteAllValues( AssociativeContainerT& container ) { jamie@264: typename AssociativeContainerT::const_iterator it = container.begin(); jamie@264: typename AssociativeContainerT::const_iterator itEnd = container.end(); jamie@264: for(; it != itEnd; ++it ) jamie@264: delete it->second; jamie@264: } jamie@264: jamie@264: bool startsWith( std::string const& s, std::string const& prefix ); jamie@264: bool endsWith( std::string const& s, std::string const& suffix ); jamie@264: bool contains( std::string const& s, std::string const& infix ); jamie@264: void toLowerInPlace( std::string& s ); jamie@264: std::string toLower( std::string const& s ); jamie@264: std::string trim( std::string const& str ); jamie@264: jamie@264: struct pluralise { jamie@264: pluralise( std::size_t count, std::string const& label ); jamie@264: jamie@264: friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); jamie@264: jamie@264: std::size_t m_count; jamie@264: std::string m_label; jamie@264: }; jamie@264: jamie@264: struct SourceLineInfo { jamie@264: jamie@264: SourceLineInfo(); jamie@264: SourceLineInfo( char const* _file, std::size_t _line ); jamie@264: SourceLineInfo( SourceLineInfo const& other ); jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: SourceLineInfo( SourceLineInfo && ) = default; jamie@264: SourceLineInfo& operator = ( SourceLineInfo const& ) = default; jamie@264: SourceLineInfo& operator = ( SourceLineInfo && ) = default; jamie@264: # endif jamie@264: bool empty() const; jamie@264: bool operator == ( SourceLineInfo const& other ) const; jamie@264: jamie@264: std::string file; jamie@264: std::size_t line; jamie@264: }; jamie@264: jamie@264: std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); jamie@264: jamie@264: // This is just here to avoid compiler warnings with macro constants and boolean literals jamie@264: inline bool isTrue( bool value ){ return value; } jamie@264: inline bool alwaysTrue() { return true; } jamie@264: inline bool alwaysFalse() { return false; } jamie@264: jamie@264: void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); jamie@264: jamie@264: // Use this in variadic streaming macros to allow jamie@264: // >> +StreamEndStop jamie@264: // as well as jamie@264: // >> stuff +StreamEndStop jamie@264: struct StreamEndStop { jamie@264: std::string operator+() { jamie@264: return std::string(); jamie@264: } jamie@264: }; jamie@264: template jamie@264: T const& operator + ( T const& value, StreamEndStop ) { jamie@264: return value; jamie@264: } jamie@264: } jamie@264: jamie@264: #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) jamie@264: #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class NotImplementedException : public std::exception jamie@264: { jamie@264: public: jamie@264: NotImplementedException( SourceLineInfo const& lineInfo ); jamie@264: NotImplementedException( NotImplementedException const& ) {} jamie@264: jamie@264: virtual ~NotImplementedException() CATCH_NOEXCEPT {} jamie@264: jamie@264: virtual const char* what() const CATCH_NOEXCEPT; jamie@264: jamie@264: private: jamie@264: std::string m_what; jamie@264: SourceLineInfo m_lineInfo; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) jamie@264: jamie@264: // #included from: internal/catch_context.h jamie@264: #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED jamie@264: jamie@264: // #included from: catch_interfaces_generators.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct IGeneratorInfo { jamie@264: virtual ~IGeneratorInfo(); jamie@264: virtual bool moveNext() = 0; jamie@264: virtual std::size_t getCurrentIndex() const = 0; jamie@264: }; jamie@264: jamie@264: struct IGeneratorsForTest { jamie@264: virtual ~IGeneratorsForTest(); jamie@264: jamie@264: virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; jamie@264: virtual bool moveNext() = 0; jamie@264: }; jamie@264: jamie@264: IGeneratorsForTest* createGeneratorsForTest(); jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_ptr.hpp jamie@264: #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Wpadded" jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: // An intrusive reference counting smart pointer. jamie@264: // T must implement addRef() and release() methods jamie@264: // typically implementing the IShared interface jamie@264: template jamie@264: class Ptr { jamie@264: public: jamie@264: Ptr() : m_p( NULL ){} jamie@264: Ptr( T* p ) : m_p( p ){ jamie@264: if( m_p ) jamie@264: m_p->addRef(); jamie@264: } jamie@264: Ptr( Ptr const& other ) : m_p( other.m_p ){ jamie@264: if( m_p ) jamie@264: m_p->addRef(); jamie@264: } jamie@264: ~Ptr(){ jamie@264: if( m_p ) jamie@264: m_p->release(); jamie@264: } jamie@264: void reset() { jamie@264: if( m_p ) jamie@264: m_p->release(); jamie@264: m_p = NULL; jamie@264: } jamie@264: Ptr& operator = ( T* p ){ jamie@264: Ptr temp( p ); jamie@264: swap( temp ); jamie@264: return *this; jamie@264: } jamie@264: Ptr& operator = ( Ptr const& other ){ jamie@264: Ptr temp( other ); jamie@264: swap( temp ); jamie@264: return *this; jamie@264: } jamie@264: void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } jamie@264: T* get() { return m_p; } jamie@264: const T* get() const{ return m_p; } jamie@264: T& operator*() const { return *m_p; } jamie@264: T* operator->() const { return m_p; } jamie@264: bool operator !() const { return m_p == NULL; } jamie@264: operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } jamie@264: jamie@264: private: jamie@264: T* m_p; jamie@264: }; jamie@264: jamie@264: struct IShared : NonCopyable { jamie@264: virtual ~IShared(); jamie@264: virtual void addRef() const = 0; jamie@264: virtual void release() const = 0; jamie@264: }; jamie@264: jamie@264: template jamie@264: struct SharedImpl : T { jamie@264: jamie@264: SharedImpl() : m_rc( 0 ){} jamie@264: jamie@264: virtual void addRef() const { jamie@264: ++m_rc; jamie@264: } jamie@264: virtual void release() const { jamie@264: if( --m_rc == 0 ) jamie@264: delete this; jamie@264: } jamie@264: jamie@264: mutable unsigned int m_rc; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #endif jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class TestCase; jamie@264: class Stream; jamie@264: struct IResultCapture; jamie@264: struct IRunner; jamie@264: struct IGeneratorsForTest; jamie@264: struct IConfig; jamie@264: jamie@264: struct IContext jamie@264: { jamie@264: virtual ~IContext(); jamie@264: jamie@264: virtual IResultCapture* getResultCapture() = 0; jamie@264: virtual IRunner* getRunner() = 0; jamie@264: virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; jamie@264: virtual bool advanceGeneratorsForCurrentTest() = 0; jamie@264: virtual Ptr getConfig() const = 0; jamie@264: }; jamie@264: jamie@264: struct IMutableContext : IContext jamie@264: { jamie@264: virtual ~IMutableContext(); jamie@264: virtual void setResultCapture( IResultCapture* resultCapture ) = 0; jamie@264: virtual void setRunner( IRunner* runner ) = 0; jamie@264: virtual void setConfig( Ptr const& config ) = 0; jamie@264: }; jamie@264: jamie@264: IContext& getCurrentContext(); jamie@264: IMutableContext& getCurrentMutableContext(); jamie@264: void cleanUpContext(); jamie@264: Stream createStream( std::string const& streamName ); jamie@264: jamie@264: } jamie@264: jamie@264: // #included from: internal/catch_test_registry.hpp jamie@264: #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_interfaces_testcase.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class TestSpec; jamie@264: jamie@264: struct ITestCase : IShared { jamie@264: virtual void invoke () const = 0; jamie@264: protected: jamie@264: virtual ~ITestCase(); jamie@264: }; jamie@264: jamie@264: class TestCase; jamie@264: struct IConfig; jamie@264: jamie@264: struct ITestCaseRegistry { jamie@264: virtual ~ITestCaseRegistry(); jamie@264: virtual std::vector const& getAllTests() const = 0; jamie@264: virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases ) const = 0; jamie@264: jamie@264: }; jamie@264: } jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: template jamie@264: class MethodTestCase : public SharedImpl { jamie@264: jamie@264: public: jamie@264: MethodTestCase( void (C::*method)() ) : m_method( method ) {} jamie@264: jamie@264: virtual void invoke() const { jamie@264: C obj; jamie@264: (obj.*m_method)(); jamie@264: } jamie@264: jamie@264: private: jamie@264: virtual ~MethodTestCase() {} jamie@264: jamie@264: void (C::*m_method)(); jamie@264: }; jamie@264: jamie@264: typedef void(*TestFunction)(); jamie@264: jamie@264: struct NameAndDesc { jamie@264: NameAndDesc( const char* _name = "", const char* _description= "" ) jamie@264: : name( _name ), description( _description ) jamie@264: {} jamie@264: jamie@264: const char* name; jamie@264: const char* description; jamie@264: }; jamie@264: jamie@264: struct AutoReg { jamie@264: jamie@264: AutoReg( TestFunction function, jamie@264: SourceLineInfo const& lineInfo, jamie@264: NameAndDesc const& nameAndDesc ); jamie@264: jamie@264: template jamie@264: AutoReg( void (C::*method)(), jamie@264: char const* className, jamie@264: NameAndDesc const& nameAndDesc, jamie@264: SourceLineInfo const& lineInfo ) { jamie@264: registerTestCase( new MethodTestCase( method ), jamie@264: className, jamie@264: nameAndDesc, jamie@264: lineInfo ); jamie@264: } jamie@264: jamie@264: void registerTestCase( ITestCase* testCase, jamie@264: char const* className, jamie@264: NameAndDesc const& nameAndDesc, jamie@264: SourceLineInfo const& lineInfo ); jamie@264: jamie@264: ~AutoReg(); jamie@264: jamie@264: private: jamie@264: AutoReg( AutoReg const& ); jamie@264: void operator= ( AutoReg const& ); jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: #ifdef CATCH_CONFIG_VARIADIC_MACROS jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_TESTCASE( ... ) \ jamie@264: static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ jamie@264: namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ jamie@264: static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ jamie@264: namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ jamie@264: namespace{ \ jamie@264: struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ jamie@264: void test(); \ jamie@264: }; \ jamie@264: Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ jamie@264: } \ jamie@264: void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() jamie@264: jamie@264: #else jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ jamie@264: static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ jamie@264: namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ jamie@264: static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ jamie@264: namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ jamie@264: namespace{ \ jamie@264: struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ jamie@264: void test(); \ jamie@264: }; \ jamie@264: Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ jamie@264: } \ jamie@264: void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() jamie@264: jamie@264: #endif jamie@264: jamie@264: // #included from: internal/catch_capture.hpp jamie@264: #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_result_builder.h jamie@264: #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED jamie@264: jamie@264: // #included from: catch_result_type.h jamie@264: #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: // ResultWas::OfType enum jamie@264: struct ResultWas { enum OfType { jamie@264: Unknown = -1, jamie@264: Ok = 0, jamie@264: Info = 1, jamie@264: Warning = 2, jamie@264: jamie@264: FailureBit = 0x10, jamie@264: jamie@264: ExpressionFailed = FailureBit | 1, jamie@264: ExplicitFailure = FailureBit | 2, jamie@264: jamie@264: Exception = 0x100 | FailureBit, jamie@264: jamie@264: ThrewException = Exception | 1, jamie@264: DidntThrowException = Exception | 2 jamie@264: jamie@264: }; }; jamie@264: jamie@264: inline bool isOk( ResultWas::OfType resultType ) { jamie@264: return ( resultType & ResultWas::FailureBit ) == 0; jamie@264: } jamie@264: inline bool isJustInfo( int flags ) { jamie@264: return flags == ResultWas::Info; jamie@264: } jamie@264: jamie@264: // ResultDisposition::Flags enum jamie@264: struct ResultDisposition { enum Flags { jamie@264: Normal = 0x00, jamie@264: jamie@264: ContinueOnFailure = 0x01, // Failures fail test, but execution continues jamie@264: FalseTest = 0x02, // Prefix expression with ! jamie@264: SuppressFail = 0x04 // Failures are reported but do not fail the test jamie@264: }; }; jamie@264: jamie@264: inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { jamie@264: return static_cast( static_cast( lhs ) | static_cast( rhs ) ); jamie@264: } jamie@264: jamie@264: inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } jamie@264: inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } jamie@264: inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_assertionresult.h jamie@264: #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct AssertionInfo jamie@264: { jamie@264: AssertionInfo() {} jamie@264: AssertionInfo( std::string const& _macroName, jamie@264: SourceLineInfo const& _lineInfo, jamie@264: std::string const& _capturedExpression, jamie@264: ResultDisposition::Flags _resultDisposition ); jamie@264: jamie@264: std::string macroName; jamie@264: SourceLineInfo lineInfo; jamie@264: std::string capturedExpression; jamie@264: ResultDisposition::Flags resultDisposition; jamie@264: }; jamie@264: jamie@264: struct AssertionResultData jamie@264: { jamie@264: AssertionResultData() : resultType( ResultWas::Unknown ) {} jamie@264: jamie@264: std::string reconstructedExpression; jamie@264: std::string message; jamie@264: ResultWas::OfType resultType; jamie@264: }; jamie@264: jamie@264: class AssertionResult { jamie@264: public: jamie@264: AssertionResult(); jamie@264: AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); jamie@264: ~AssertionResult(); jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: AssertionResult( AssertionResult const& ) = default; jamie@264: AssertionResult( AssertionResult && ) = default; jamie@264: AssertionResult& operator = ( AssertionResult const& ) = default; jamie@264: AssertionResult& operator = ( AssertionResult && ) = default; jamie@264: # endif jamie@264: jamie@264: bool isOk() const; jamie@264: bool succeeded() const; jamie@264: ResultWas::OfType getResultType() const; jamie@264: bool hasExpression() const; jamie@264: bool hasMessage() const; jamie@264: std::string getExpression() const; jamie@264: std::string getExpressionInMacro() const; jamie@264: bool hasExpandedExpression() const; jamie@264: std::string getExpandedExpression() const; jamie@264: std::string getMessage() const; jamie@264: SourceLineInfo getSourceInfo() const; jamie@264: std::string getTestMacroName() const; jamie@264: jamie@264: protected: jamie@264: AssertionInfo m_info; jamie@264: AssertionResultData m_resultData; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct TestFailureException{}; jamie@264: jamie@264: template class ExpressionLhs; jamie@264: jamie@264: struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; jamie@264: jamie@264: struct CopyableStream { jamie@264: CopyableStream() {} jamie@264: CopyableStream( CopyableStream const& other ) { jamie@264: oss << other.oss.str(); jamie@264: } jamie@264: CopyableStream& operator=( CopyableStream const& other ) { jamie@264: oss.str(""); jamie@264: oss << other.oss.str(); jamie@264: return *this; jamie@264: } jamie@264: std::ostringstream oss; jamie@264: }; jamie@264: jamie@264: class ResultBuilder { jamie@264: public: jamie@264: ResultBuilder( char const* macroName, jamie@264: SourceLineInfo const& lineInfo, jamie@264: char const* capturedExpression, jamie@264: ResultDisposition::Flags resultDisposition ); jamie@264: jamie@264: template jamie@264: ExpressionLhs operator->* ( T const& operand ); jamie@264: ExpressionLhs operator->* ( bool value ); jamie@264: jamie@264: template jamie@264: ResultBuilder& operator << ( T const& value ) { jamie@264: m_stream.oss << value; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); jamie@264: template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); jamie@264: jamie@264: ResultBuilder& setResultType( ResultWas::OfType result ); jamie@264: ResultBuilder& setResultType( bool result ); jamie@264: ResultBuilder& setLhs( std::string const& lhs ); jamie@264: ResultBuilder& setRhs( std::string const& rhs ); jamie@264: ResultBuilder& setOp( std::string const& op ); jamie@264: jamie@264: void endExpression(); jamie@264: jamie@264: std::string reconstructExpression() const; jamie@264: AssertionResult build() const; jamie@264: jamie@264: void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); jamie@264: void captureResult( ResultWas::OfType resultType ); jamie@264: void captureExpression(); jamie@264: void react(); jamie@264: bool shouldDebugBreak() const; jamie@264: bool allowThrows() const; jamie@264: jamie@264: private: jamie@264: AssertionInfo m_assertionInfo; jamie@264: AssertionResultData m_data; jamie@264: struct ExprComponents { jamie@264: ExprComponents() : testFalse( false ) {} jamie@264: bool testFalse; jamie@264: std::string lhs, rhs, op; jamie@264: } m_exprComponents; jamie@264: CopyableStream m_stream; jamie@264: jamie@264: bool m_shouldDebugBreak; jamie@264: bool m_shouldThrow; jamie@264: }; jamie@264: jamie@264: } // namespace Catch jamie@264: jamie@264: // Include after due to circular dependency: jamie@264: // #included from: catch_expression_lhs.hpp jamie@264: #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_evaluate.hpp jamie@264: #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED jamie@264: jamie@264: #ifdef _MSC_VER jamie@264: #pragma warning(push) jamie@264: #pragma warning(disable:4389) // '==' : signed/unsigned mismatch jamie@264: #endif jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: namespace Internal { jamie@264: jamie@264: enum Operator { jamie@264: IsEqualTo, jamie@264: IsNotEqualTo, jamie@264: IsLessThan, jamie@264: IsGreaterThan, jamie@264: IsLessThanOrEqualTo, jamie@264: IsGreaterThanOrEqualTo jamie@264: }; jamie@264: jamie@264: template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; jamie@264: template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; jamie@264: template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; jamie@264: template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; jamie@264: template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; jamie@264: template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; jamie@264: template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; jamie@264: jamie@264: template jamie@264: inline T& opCast(T const& t) { return const_cast(t); } jamie@264: jamie@264: // nullptr_t support based on pull request #154 from Konstantin Baumann jamie@264: #ifdef CATCH_CONFIG_CPP11_NULLPTR jamie@264: inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } jamie@264: #endif // CATCH_CONFIG_CPP11_NULLPTR jamie@264: jamie@264: // So the compare overloads can be operator agnostic we convey the operator as a template jamie@264: // enum, which is used to specialise an Evaluator for doing the comparison. jamie@264: template jamie@264: class Evaluator{}; jamie@264: jamie@264: template jamie@264: struct Evaluator { jamie@264: static bool evaluate( T1 const& lhs, T2 const& rhs) { jamie@264: return opCast( lhs ) == opCast( rhs ); jamie@264: } jamie@264: }; jamie@264: template jamie@264: struct Evaluator { jamie@264: static bool evaluate( T1 const& lhs, T2 const& rhs ) { jamie@264: return opCast( lhs ) != opCast( rhs ); jamie@264: } jamie@264: }; jamie@264: template jamie@264: struct Evaluator { jamie@264: static bool evaluate( T1 const& lhs, T2 const& rhs ) { jamie@264: return opCast( lhs ) < opCast( rhs ); jamie@264: } jamie@264: }; jamie@264: template jamie@264: struct Evaluator { jamie@264: static bool evaluate( T1 const& lhs, T2 const& rhs ) { jamie@264: return opCast( lhs ) > opCast( rhs ); jamie@264: } jamie@264: }; jamie@264: template jamie@264: struct Evaluator { jamie@264: static bool evaluate( T1 const& lhs, T2 const& rhs ) { jamie@264: return opCast( lhs ) >= opCast( rhs ); jamie@264: } jamie@264: }; jamie@264: template jamie@264: struct Evaluator { jamie@264: static bool evaluate( T1 const& lhs, T2 const& rhs ) { jamie@264: return opCast( lhs ) <= opCast( rhs ); jamie@264: } jamie@264: }; jamie@264: jamie@264: template jamie@264: bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { jamie@264: return Evaluator::evaluate( lhs, rhs ); jamie@264: } jamie@264: jamie@264: // This level of indirection allows us to specialise for integer types jamie@264: // to avoid signed/ unsigned warnings jamie@264: jamie@264: // "base" overload jamie@264: template jamie@264: bool compare( T1 const& lhs, T2 const& rhs ) { jamie@264: return Evaluator::evaluate( lhs, rhs ); jamie@264: } jamie@264: jamie@264: // unsigned X to int jamie@264: template bool compare( unsigned int lhs, int rhs ) { jamie@264: return applyEvaluator( lhs, static_cast( rhs ) ); jamie@264: } jamie@264: template bool compare( unsigned long lhs, int rhs ) { jamie@264: return applyEvaluator( lhs, static_cast( rhs ) ); jamie@264: } jamie@264: template bool compare( unsigned char lhs, int rhs ) { jamie@264: return applyEvaluator( lhs, static_cast( rhs ) ); jamie@264: } jamie@264: jamie@264: // unsigned X to long jamie@264: template bool compare( unsigned int lhs, long rhs ) { jamie@264: return applyEvaluator( lhs, static_cast( rhs ) ); jamie@264: } jamie@264: template bool compare( unsigned long lhs, long rhs ) { jamie@264: return applyEvaluator( lhs, static_cast( rhs ) ); jamie@264: } jamie@264: template bool compare( unsigned char lhs, long rhs ) { jamie@264: return applyEvaluator( lhs, static_cast( rhs ) ); jamie@264: } jamie@264: jamie@264: // int to unsigned X jamie@264: template bool compare( int lhs, unsigned int rhs ) { jamie@264: return applyEvaluator( static_cast( lhs ), rhs ); jamie@264: } jamie@264: template bool compare( int lhs, unsigned long rhs ) { jamie@264: return applyEvaluator( static_cast( lhs ), rhs ); jamie@264: } jamie@264: template bool compare( int lhs, unsigned char rhs ) { jamie@264: return applyEvaluator( static_cast( lhs ), rhs ); jamie@264: } jamie@264: jamie@264: // long to unsigned X jamie@264: template bool compare( long lhs, unsigned int rhs ) { jamie@264: return applyEvaluator( static_cast( lhs ), rhs ); jamie@264: } jamie@264: template bool compare( long lhs, unsigned long rhs ) { jamie@264: return applyEvaluator( static_cast( lhs ), rhs ); jamie@264: } jamie@264: template bool compare( long lhs, unsigned char rhs ) { jamie@264: return applyEvaluator( static_cast( lhs ), rhs ); jamie@264: } jamie@264: jamie@264: // pointer to long (when comparing against NULL) jamie@264: template bool compare( long lhs, T* rhs ) { jamie@264: return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); jamie@264: } jamie@264: template bool compare( T* lhs, long rhs ) { jamie@264: return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); jamie@264: } jamie@264: jamie@264: // pointer to int (when comparing against NULL) jamie@264: template bool compare( int lhs, T* rhs ) { jamie@264: return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); jamie@264: } jamie@264: template bool compare( T* lhs, int rhs ) { jamie@264: return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); jamie@264: } jamie@264: jamie@264: #ifdef CATCH_CONFIG_CPP11_NULLPTR jamie@264: // pointer to nullptr_t (when comparing against nullptr) jamie@264: template bool compare( std::nullptr_t, T* rhs ) { jamie@264: return Evaluator::evaluate( NULL, rhs ); jamie@264: } jamie@264: template bool compare( T* lhs, std::nullptr_t ) { jamie@264: return Evaluator::evaluate( lhs, NULL ); jamie@264: } jamie@264: #endif // CATCH_CONFIG_CPP11_NULLPTR jamie@264: jamie@264: } // end of namespace Internal jamie@264: } // end of namespace Catch jamie@264: jamie@264: #ifdef _MSC_VER jamie@264: #pragma warning(pop) jamie@264: #endif jamie@264: jamie@264: // #included from: catch_tostring.h jamie@264: #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED jamie@264: jamie@264: // #included from: catch_sfinae.hpp jamie@264: #define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED jamie@264: jamie@264: // Try to detect if the current compiler supports SFINAE jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct TrueType { jamie@264: static const bool value = true; jamie@264: typedef void Enable; jamie@264: char sizer[1]; jamie@264: }; jamie@264: struct FalseType { jamie@264: static const bool value = false; jamie@264: typedef void Disable; jamie@264: char sizer[2]; jamie@264: }; jamie@264: jamie@264: #ifdef CATCH_CONFIG_SFINAE jamie@264: jamie@264: template struct NotABooleanExpression; jamie@264: jamie@264: template struct If : NotABooleanExpression {}; jamie@264: template<> struct If : TrueType {}; jamie@264: template<> struct If : FalseType {}; jamie@264: jamie@264: template struct SizedIf; jamie@264: template<> struct SizedIf : TrueType {}; jamie@264: template<> struct SizedIf : FalseType {}; jamie@264: jamie@264: #endif // CATCH_CONFIG_SFINAE jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: #ifdef __OBJC__ jamie@264: // #included from: catch_objc_arc.hpp jamie@264: #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED jamie@264: jamie@264: #import jamie@264: jamie@264: #ifdef __has_feature jamie@264: #define CATCH_ARC_ENABLED __has_feature(objc_arc) jamie@264: #else jamie@264: #define CATCH_ARC_ENABLED 0 jamie@264: #endif jamie@264: jamie@264: void arcSafeRelease( NSObject* obj ); jamie@264: id performOptionalSelector( id obj, SEL sel ); jamie@264: jamie@264: #if !CATCH_ARC_ENABLED jamie@264: inline void arcSafeRelease( NSObject* obj ) { jamie@264: [obj release]; jamie@264: } jamie@264: inline id performOptionalSelector( id obj, SEL sel ) { jamie@264: if( [obj respondsToSelector: sel] ) jamie@264: return [obj performSelector: sel]; jamie@264: return nil; jamie@264: } jamie@264: #define CATCH_UNSAFE_UNRETAINED jamie@264: #define CATCH_ARC_STRONG jamie@264: #else jamie@264: inline void arcSafeRelease( NSObject* ){} jamie@264: inline id performOptionalSelector( id obj, SEL sel ) { jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Warc-performSelector-leaks" jamie@264: #endif jamie@264: if( [obj respondsToSelector: sel] ) jamie@264: return [obj performSelector: sel]; jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #endif jamie@264: return nil; jamie@264: } jamie@264: #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained jamie@264: #define CATCH_ARC_STRONG __strong jamie@264: #endif jamie@264: jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: namespace Detail { jamie@264: jamie@264: // SFINAE is currently disabled by default for all compilers. jamie@264: // If the non SFINAE version of IsStreamInsertable is ambiguous for you jamie@264: // and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE jamie@264: #ifdef CATCH_CONFIG_SFINAE jamie@264: jamie@264: template jamie@264: class IsStreamInsertableHelper { jamie@264: template struct TrueIfSizeable : TrueType {}; jamie@264: jamie@264: template jamie@264: static TrueIfSizeable dummy(T2*); jamie@264: static FalseType dummy(...); jamie@264: jamie@264: public: jamie@264: typedef SizedIf type; jamie@264: }; jamie@264: jamie@264: template jamie@264: struct IsStreamInsertable : IsStreamInsertableHelper::type {}; jamie@264: jamie@264: #else jamie@264: jamie@264: struct BorgType { jamie@264: template BorgType( T const& ); jamie@264: }; jamie@264: jamie@264: TrueType& testStreamable( std::ostream& ); jamie@264: FalseType testStreamable( FalseType ); jamie@264: jamie@264: FalseType operator<<( std::ostream const&, BorgType const& ); jamie@264: jamie@264: template jamie@264: struct IsStreamInsertable { jamie@264: static std::ostream &s; jamie@264: static T const&t; jamie@264: enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; jamie@264: }; jamie@264: jamie@264: #endif jamie@264: jamie@264: template jamie@264: struct StringMakerBase { jamie@264: template jamie@264: static std::string convert( T const& ) { return "{?}"; } jamie@264: }; jamie@264: jamie@264: template<> jamie@264: struct StringMakerBase { jamie@264: template jamie@264: static std::string convert( T const& _value ) { jamie@264: std::ostringstream oss; jamie@264: oss << _value; jamie@264: return oss.str(); jamie@264: } jamie@264: }; jamie@264: jamie@264: std::string rawMemoryToString( const void *object, std::size_t size ); jamie@264: jamie@264: template jamie@264: inline std::string rawMemoryToString( const T& object ) { jamie@264: return rawMemoryToString( &object, sizeof(object) ); jamie@264: } jamie@264: jamie@264: } // end namespace Detail jamie@264: jamie@264: template jamie@264: std::string toString( T const& value ); jamie@264: jamie@264: template jamie@264: struct StringMaker : jamie@264: Detail::StringMakerBase::value> {}; jamie@264: jamie@264: template jamie@264: struct StringMaker { jamie@264: template jamie@264: static std::string convert( U* p ) { jamie@264: if( !p ) jamie@264: return INTERNAL_CATCH_STRINGIFY( NULL ); jamie@264: else jamie@264: return Detail::rawMemoryToString( p ); jamie@264: } jamie@264: }; jamie@264: jamie@264: template jamie@264: struct StringMaker { jamie@264: static std::string convert( R C::* p ) { jamie@264: if( !p ) jamie@264: return INTERNAL_CATCH_STRINGIFY( NULL ); jamie@264: else jamie@264: return Detail::rawMemoryToString( p ); jamie@264: } jamie@264: }; jamie@264: jamie@264: namespace Detail { jamie@264: template jamie@264: std::string rangeToString( InputIterator first, InputIterator last ); jamie@264: } jamie@264: jamie@264: template jamie@264: struct StringMaker > { jamie@264: static std::string convert( std::vector const& v ) { jamie@264: return Detail::rangeToString( v.begin(), v.end() ); jamie@264: } jamie@264: }; jamie@264: jamie@264: namespace Detail { jamie@264: template jamie@264: std::string makeString( T const& value ) { jamie@264: return StringMaker::convert( value ); jamie@264: } jamie@264: } // end namespace Detail jamie@264: jamie@264: /// \brief converts any type to a string jamie@264: /// jamie@264: /// The default template forwards on to ostringstream - except when an jamie@264: /// ostringstream overload does not exist - in which case it attempts to detect jamie@264: /// that and writes {?}. jamie@264: /// Overload (not specialise) this template for custom typs that you don't want jamie@264: /// to provide an ostream overload for. jamie@264: template jamie@264: std::string toString( T const& value ) { jamie@264: return StringMaker::convert( value ); jamie@264: } jamie@264: jamie@264: // Built in overloads jamie@264: jamie@264: std::string toString( std::string const& value ); jamie@264: std::string toString( std::wstring const& value ); jamie@264: std::string toString( const char* const value ); jamie@264: std::string toString( char* const value ); jamie@264: std::string toString( const wchar_t* const value ); jamie@264: std::string toString( wchar_t* const value ); jamie@264: std::string toString( int value ); jamie@264: std::string toString( unsigned long value ); jamie@264: std::string toString( unsigned int value ); jamie@264: std::string toString( const double value ); jamie@264: std::string toString( const float value ); jamie@264: std::string toString( bool value ); jamie@264: std::string toString( char value ); jamie@264: std::string toString( signed char value ); jamie@264: std::string toString( unsigned char value ); jamie@264: jamie@264: #ifdef CATCH_CONFIG_CPP11_NULLPTR jamie@264: std::string toString( std::nullptr_t ); jamie@264: #endif jamie@264: jamie@264: #ifdef __OBJC__ jamie@264: std::string toString( NSString const * const& nsstring ); jamie@264: std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); jamie@264: std::string toString( NSObject* const& nsObject ); jamie@264: #endif jamie@264: jamie@264: namespace Detail { jamie@264: template jamie@264: std::string rangeToString( InputIterator first, InputIterator last ) { jamie@264: std::ostringstream oss; jamie@264: oss << "{ "; jamie@264: if( first != last ) { jamie@264: oss << toString( *first ); jamie@264: for( ++first ; first != last ; ++first ) { jamie@264: oss << ", " << toString( *first ); jamie@264: } jamie@264: } jamie@264: oss << " }"; jamie@264: return oss.str(); jamie@264: } jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: // Wraps the LHS of an expression and captures the operator and RHS (if any) - jamie@264: // wrapping them all in a ResultBuilder object jamie@264: template jamie@264: class ExpressionLhs { jamie@264: ExpressionLhs& operator = ( ExpressionLhs const& ); jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: ExpressionLhs& operator = ( ExpressionLhs && ) = delete; jamie@264: # endif jamie@264: jamie@264: public: jamie@264: ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: ExpressionLhs( ExpressionLhs const& ) = default; jamie@264: ExpressionLhs( ExpressionLhs && ) = default; jamie@264: # endif jamie@264: jamie@264: template jamie@264: ResultBuilder& operator == ( RhsT const& rhs ) { jamie@264: return captureExpression( rhs ); jamie@264: } jamie@264: jamie@264: template jamie@264: ResultBuilder& operator != ( RhsT const& rhs ) { jamie@264: return captureExpression( rhs ); jamie@264: } jamie@264: jamie@264: template jamie@264: ResultBuilder& operator < ( RhsT const& rhs ) { jamie@264: return captureExpression( rhs ); jamie@264: } jamie@264: jamie@264: template jamie@264: ResultBuilder& operator > ( RhsT const& rhs ) { jamie@264: return captureExpression( rhs ); jamie@264: } jamie@264: jamie@264: template jamie@264: ResultBuilder& operator <= ( RhsT const& rhs ) { jamie@264: return captureExpression( rhs ); jamie@264: } jamie@264: jamie@264: template jamie@264: ResultBuilder& operator >= ( RhsT const& rhs ) { jamie@264: return captureExpression( rhs ); jamie@264: } jamie@264: jamie@264: ResultBuilder& operator == ( bool rhs ) { jamie@264: return captureExpression( rhs ); jamie@264: } jamie@264: jamie@264: ResultBuilder& operator != ( bool rhs ) { jamie@264: return captureExpression( rhs ); jamie@264: } jamie@264: jamie@264: void endExpression() { jamie@264: bool value = m_lhs ? true : false; jamie@264: m_rb jamie@264: .setLhs( Catch::toString( value ) ) jamie@264: .setResultType( value ) jamie@264: .endExpression(); jamie@264: } jamie@264: jamie@264: // Only simple binary expressions are allowed on the LHS. jamie@264: // If more complex compositions are required then place the sub expression in parentheses jamie@264: template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); jamie@264: template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); jamie@264: template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); jamie@264: template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); jamie@264: template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); jamie@264: template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); jamie@264: jamie@264: private: jamie@264: template jamie@264: ResultBuilder& captureExpression( RhsT const& rhs ) { jamie@264: return m_rb jamie@264: .setResultType( Internal::compare( m_lhs, rhs ) ) jamie@264: .setLhs( Catch::toString( m_lhs ) ) jamie@264: .setRhs( Catch::toString( rhs ) ) jamie@264: .setOp( Internal::OperatorTraits::getName() ); jamie@264: } jamie@264: jamie@264: private: jamie@264: ResultBuilder& m_rb; jamie@264: T m_lhs; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: template jamie@264: inline ExpressionLhs ResultBuilder::operator->* ( T const& operand ) { jamie@264: return ExpressionLhs( *this, operand ); jamie@264: } jamie@264: jamie@264: inline ExpressionLhs ResultBuilder::operator->* ( bool value ) { jamie@264: return ExpressionLhs( *this, value ); jamie@264: } jamie@264: jamie@264: } // namespace Catch jamie@264: jamie@264: // #included from: catch_message.h jamie@264: #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct MessageInfo { jamie@264: MessageInfo( std::string const& _macroName, jamie@264: SourceLineInfo const& _lineInfo, jamie@264: ResultWas::OfType _type ); jamie@264: jamie@264: std::string macroName; jamie@264: SourceLineInfo lineInfo; jamie@264: ResultWas::OfType type; jamie@264: std::string message; jamie@264: unsigned int sequence; jamie@264: jamie@264: bool operator == ( MessageInfo const& other ) const { jamie@264: return sequence == other.sequence; jamie@264: } jamie@264: bool operator < ( MessageInfo const& other ) const { jamie@264: return sequence < other.sequence; jamie@264: } jamie@264: private: jamie@264: static unsigned int globalCount; jamie@264: }; jamie@264: jamie@264: struct MessageBuilder { jamie@264: MessageBuilder( std::string const& macroName, jamie@264: SourceLineInfo const& lineInfo, jamie@264: ResultWas::OfType type ) jamie@264: : m_info( macroName, lineInfo, type ) jamie@264: {} jamie@264: jamie@264: template jamie@264: MessageBuilder& operator << ( T const& value ) { jamie@264: m_stream << value; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: MessageInfo m_info; jamie@264: std::ostringstream m_stream; jamie@264: }; jamie@264: jamie@264: class ScopedMessage { jamie@264: public: jamie@264: ScopedMessage( MessageBuilder const& builder ); jamie@264: ScopedMessage( ScopedMessage const& other ); jamie@264: ~ScopedMessage(); jamie@264: jamie@264: MessageInfo m_info; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_interfaces_capture.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class TestCase; jamie@264: class AssertionResult; jamie@264: struct AssertionInfo; jamie@264: struct SectionInfo; jamie@264: struct MessageInfo; jamie@264: class ScopedMessageBuilder; jamie@264: struct Counts; jamie@264: jamie@264: struct IResultCapture { jamie@264: jamie@264: virtual ~IResultCapture(); jamie@264: jamie@264: virtual void assertionEnded( AssertionResult const& result ) = 0; jamie@264: virtual bool sectionStarted( SectionInfo const& sectionInfo, jamie@264: Counts& assertions ) = 0; jamie@264: virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; jamie@264: virtual void pushScopedMessage( MessageInfo const& message ) = 0; jamie@264: virtual void popScopedMessage( MessageInfo const& message ) = 0; jamie@264: jamie@264: virtual std::string getCurrentTestName() const = 0; jamie@264: virtual const AssertionResult* getLastResult() const = 0; jamie@264: }; jamie@264: jamie@264: IResultCapture& getResultCapture(); jamie@264: } jamie@264: jamie@264: // #included from: catch_debugger.h jamie@264: #define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED jamie@264: jamie@264: // #included from: catch_platform.h jamie@264: #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED jamie@264: jamie@264: #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) jamie@264: #define CATCH_PLATFORM_MAC jamie@264: #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) jamie@264: #define CATCH_PLATFORM_IPHONE jamie@264: #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) jamie@264: #define CATCH_PLATFORM_WINDOWS jamie@264: #endif jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch{ jamie@264: jamie@264: bool isDebuggerActive(); jamie@264: void writeToDebugConsole( std::string const& text ); jamie@264: } jamie@264: jamie@264: #ifdef CATCH_PLATFORM_MAC jamie@264: jamie@264: // The following code snippet based on: jamie@264: // http://cocoawithlove.com/2008/03/break-into-debugger.html jamie@264: #ifdef DEBUG jamie@264: #if defined(__ppc64__) || defined(__ppc__) jamie@264: #define CATCH_BREAK_INTO_DEBUGGER() \ jamie@264: if( Catch::isDebuggerActive() ) { \ jamie@264: __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ jamie@264: : : : "memory","r0","r3","r4" ); \ jamie@264: } jamie@264: #else jamie@264: #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} jamie@264: #endif jamie@264: #endif jamie@264: jamie@264: #elif defined(_MSC_VER) jamie@264: #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } jamie@264: #elif defined(__MINGW32__) jamie@264: extern "C" __declspec(dllimport) void __stdcall DebugBreak(); jamie@264: #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } jamie@264: #endif jamie@264: jamie@264: #ifndef CATCH_BREAK_INTO_DEBUGGER jamie@264: #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); jamie@264: #endif jamie@264: jamie@264: // #included from: catch_interfaces_runner.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: class TestCase; jamie@264: jamie@264: struct IRunner { jamie@264: virtual ~IRunner(); jamie@264: virtual bool aborting() const = 0; jamie@264: }; jamie@264: } jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: // In the event of a failure works out if the debugger needs to be invoked jamie@264: // and/or an exception thrown and takes appropriate action. jamie@264: // This needs to be done as a macro so the debugger will stop in the user jamie@264: // source code rather than in Catch library code jamie@264: #define INTERNAL_CATCH_REACT( resultBuilder ) \ jamie@264: if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ jamie@264: resultBuilder.react(); jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ jamie@264: do { \ jamie@264: Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ jamie@264: try { \ jamie@264: ( __catchResult->*expr ).endExpression(); \ jamie@264: } \ jamie@264: catch( ... ) { \ jamie@264: __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ jamie@264: } \ jamie@264: INTERNAL_CATCH_REACT( __catchResult ) \ jamie@264: } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ jamie@264: INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ jamie@264: if( Catch::getResultCapture().getLastResult()->succeeded() ) jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ jamie@264: INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ jamie@264: if( !Catch::getResultCapture().getLastResult()->succeeded() ) jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ jamie@264: do { \ jamie@264: Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ jamie@264: try { \ jamie@264: expr; \ jamie@264: __catchResult.captureResult( Catch::ResultWas::Ok ); \ jamie@264: } \ jamie@264: catch( ... ) { \ jamie@264: __catchResult.useActiveException( resultDisposition ); \ jamie@264: } \ jamie@264: INTERNAL_CATCH_REACT( __catchResult ) \ jamie@264: } while( Catch::alwaysFalse() ) jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ jamie@264: do { \ jamie@264: Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ jamie@264: if( __catchResult.allowThrows() ) \ jamie@264: try { \ jamie@264: expr; \ jamie@264: __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ jamie@264: } \ jamie@264: catch( ... ) { \ jamie@264: __catchResult.captureResult( Catch::ResultWas::Ok ); \ jamie@264: } \ jamie@264: else \ jamie@264: __catchResult.captureResult( Catch::ResultWas::Ok ); \ jamie@264: INTERNAL_CATCH_REACT( __catchResult ) \ jamie@264: } while( Catch::alwaysFalse() ) jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ jamie@264: do { \ jamie@264: Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ jamie@264: if( __catchResult.allowThrows() ) \ jamie@264: try { \ jamie@264: expr; \ jamie@264: __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ jamie@264: } \ jamie@264: catch( exceptionType ) { \ jamie@264: __catchResult.captureResult( Catch::ResultWas::Ok ); \ jamie@264: } \ jamie@264: catch( ... ) { \ jamie@264: __catchResult.useActiveException( resultDisposition ); \ jamie@264: } \ jamie@264: else \ jamie@264: __catchResult.captureResult( Catch::ResultWas::Ok ); \ jamie@264: INTERNAL_CATCH_REACT( __catchResult ) \ jamie@264: } while( Catch::alwaysFalse() ) jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #ifdef CATCH_CONFIG_VARIADIC_MACROS jamie@264: #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ jamie@264: do { \ jamie@264: Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ jamie@264: __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ jamie@264: __catchResult.captureResult( messageType ); \ jamie@264: INTERNAL_CATCH_REACT( __catchResult ) \ jamie@264: } while( Catch::alwaysFalse() ) jamie@264: #else jamie@264: #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ jamie@264: do { \ jamie@264: Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ jamie@264: __catchResult << log + ::Catch::StreamEndStop(); \ jamie@264: __catchResult.captureResult( messageType ); \ jamie@264: INTERNAL_CATCH_REACT( __catchResult ) \ jamie@264: } while( Catch::alwaysFalse() ) jamie@264: #endif jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_INFO( log, macroName ) \ jamie@264: Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ jamie@264: do { \ jamie@264: Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ jamie@264: try { \ jamie@264: std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ jamie@264: __catchResult \ jamie@264: .setLhs( Catch::toString( arg ) ) \ jamie@264: .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \ jamie@264: .setOp( "matches" ) \ jamie@264: .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ jamie@264: __catchResult.captureExpression(); \ jamie@264: } catch( ... ) { \ jamie@264: __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ jamie@264: } \ jamie@264: INTERNAL_CATCH_REACT( __catchResult ) \ jamie@264: } while( Catch::alwaysFalse() ) jamie@264: jamie@264: // #included from: internal/catch_section.h jamie@264: #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED jamie@264: jamie@264: // #included from: catch_section_info.h jamie@264: #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct SectionInfo { jamie@264: SectionInfo jamie@264: ( SourceLineInfo const& _lineInfo, jamie@264: std::string const& _name, jamie@264: std::string const& _description = std::string() ); jamie@264: jamie@264: std::string name; jamie@264: std::string description; jamie@264: SourceLineInfo lineInfo; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_totals.hpp jamie@264: #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct Counts { jamie@264: Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} jamie@264: jamie@264: Counts operator - ( Counts const& other ) const { jamie@264: Counts diff; jamie@264: diff.passed = passed - other.passed; jamie@264: diff.failed = failed - other.failed; jamie@264: diff.failedButOk = failedButOk - other.failedButOk; jamie@264: return diff; jamie@264: } jamie@264: Counts& operator += ( Counts const& other ) { jamie@264: passed += other.passed; jamie@264: failed += other.failed; jamie@264: failedButOk += other.failedButOk; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: std::size_t total() const { jamie@264: return passed + failed + failedButOk; jamie@264: } jamie@264: bool allPassed() const { jamie@264: return failed == 0 && failedButOk == 0; jamie@264: } jamie@264: jamie@264: std::size_t passed; jamie@264: std::size_t failed; jamie@264: std::size_t failedButOk; jamie@264: }; jamie@264: jamie@264: struct Totals { jamie@264: jamie@264: Totals operator - ( Totals const& other ) const { jamie@264: Totals diff; jamie@264: diff.assertions = assertions - other.assertions; jamie@264: diff.testCases = testCases - other.testCases; jamie@264: return diff; jamie@264: } jamie@264: jamie@264: Totals delta( Totals const& prevTotals ) const { jamie@264: Totals diff = *this - prevTotals; jamie@264: if( diff.assertions.failed > 0 ) jamie@264: ++diff.testCases.failed; jamie@264: else if( diff.assertions.failedButOk > 0 ) jamie@264: ++diff.testCases.failedButOk; jamie@264: else jamie@264: ++diff.testCases.passed; jamie@264: return diff; jamie@264: } jamie@264: jamie@264: Totals& operator += ( Totals const& other ) { jamie@264: assertions += other.assertions; jamie@264: testCases += other.testCases; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: Counts assertions; jamie@264: Counts testCases; jamie@264: }; jamie@264: } jamie@264: jamie@264: // #included from: catch_timer.h jamie@264: #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED jamie@264: jamie@264: #ifdef CATCH_PLATFORM_WINDOWS jamie@264: typedef unsigned long long uint64_t; jamie@264: #else jamie@264: #include jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class Timer { jamie@264: public: jamie@264: Timer() : m_ticks( 0 ) {} jamie@264: void start(); jamie@264: unsigned int getElapsedNanoseconds() const; jamie@264: unsigned int getElapsedMilliseconds() const; jamie@264: double getElapsedSeconds() const; jamie@264: jamie@264: private: jamie@264: uint64_t m_ticks; jamie@264: }; jamie@264: jamie@264: } // namespace Catch jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class Section { jamie@264: public: jamie@264: Section( SectionInfo const& info ); jamie@264: ~Section(); jamie@264: jamie@264: // This indicates whether the section should be executed or not jamie@264: operator bool() const; jamie@264: jamie@264: private: jamie@264: #ifdef CATCH_CPP11_OR_GREATER jamie@264: Section( Section const& ) = delete; jamie@264: Section( Section && ) = delete; jamie@264: Section& operator = ( Section const& ) = delete; jamie@264: Section& operator = ( Section && ) = delete; jamie@264: #else jamie@264: Section( Section const& info ); jamie@264: Section& operator = ( Section const& ); jamie@264: #endif jamie@264: SectionInfo m_info; jamie@264: jamie@264: std::string m_name; jamie@264: Counts m_assertions; jamie@264: bool m_sectionIncluded; jamie@264: Timer m_timer; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: #ifdef CATCH_CONFIG_VARIADIC_MACROS jamie@264: #define INTERNAL_CATCH_SECTION( ... ) \ jamie@264: if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) jamie@264: #else jamie@264: #define INTERNAL_CATCH_SECTION( name, desc ) \ jamie@264: if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) jamie@264: #endif jamie@264: jamie@264: // #included from: internal/catch_generators.hpp jamie@264: #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: template jamie@264: struct IGenerator { jamie@264: virtual ~IGenerator() {} jamie@264: virtual T getValue( std::size_t index ) const = 0; jamie@264: virtual std::size_t size () const = 0; jamie@264: }; jamie@264: jamie@264: template jamie@264: class BetweenGenerator : public IGenerator { jamie@264: public: jamie@264: BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} jamie@264: jamie@264: virtual T getValue( std::size_t index ) const { jamie@264: return m_from+static_cast( index ); jamie@264: } jamie@264: jamie@264: virtual std::size_t size() const { jamie@264: return static_cast( 1+m_to-m_from ); jamie@264: } jamie@264: jamie@264: private: jamie@264: jamie@264: T m_from; jamie@264: T m_to; jamie@264: }; jamie@264: jamie@264: template jamie@264: class ValuesGenerator : public IGenerator { jamie@264: public: jamie@264: ValuesGenerator(){} jamie@264: jamie@264: void add( T value ) { jamie@264: m_values.push_back( value ); jamie@264: } jamie@264: jamie@264: virtual T getValue( std::size_t index ) const { jamie@264: return m_values[index]; jamie@264: } jamie@264: jamie@264: virtual std::size_t size() const { jamie@264: return m_values.size(); jamie@264: } jamie@264: jamie@264: private: jamie@264: std::vector m_values; jamie@264: }; jamie@264: jamie@264: template jamie@264: class CompositeGenerator { jamie@264: public: jamie@264: CompositeGenerator() : m_totalSize( 0 ) {} jamie@264: jamie@264: // *** Move semantics, similar to auto_ptr *** jamie@264: CompositeGenerator( CompositeGenerator& other ) jamie@264: : m_fileInfo( other.m_fileInfo ), jamie@264: m_totalSize( 0 ) jamie@264: { jamie@264: move( other ); jamie@264: } jamie@264: jamie@264: CompositeGenerator& setFileInfo( const char* fileInfo ) { jamie@264: m_fileInfo = fileInfo; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: ~CompositeGenerator() { jamie@264: deleteAll( m_composed ); jamie@264: } jamie@264: jamie@264: operator T () const { jamie@264: size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); jamie@264: jamie@264: typename std::vector*>::const_iterator it = m_composed.begin(); jamie@264: typename std::vector*>::const_iterator itEnd = m_composed.end(); jamie@264: for( size_t index = 0; it != itEnd; ++it ) jamie@264: { jamie@264: const IGenerator* generator = *it; jamie@264: if( overallIndex >= index && overallIndex < index + generator->size() ) jamie@264: { jamie@264: return generator->getValue( overallIndex-index ); jamie@264: } jamie@264: index += generator->size(); jamie@264: } jamie@264: CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); jamie@264: 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 jamie@264: } jamie@264: jamie@264: void add( const IGenerator* generator ) { jamie@264: m_totalSize += generator->size(); jamie@264: m_composed.push_back( generator ); jamie@264: } jamie@264: jamie@264: CompositeGenerator& then( CompositeGenerator& other ) { jamie@264: move( other ); jamie@264: return *this; jamie@264: } jamie@264: jamie@264: CompositeGenerator& then( T value ) { jamie@264: ValuesGenerator* valuesGen = new ValuesGenerator(); jamie@264: valuesGen->add( value ); jamie@264: add( valuesGen ); jamie@264: return *this; jamie@264: } jamie@264: jamie@264: private: jamie@264: jamie@264: void move( CompositeGenerator& other ) { jamie@264: std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); jamie@264: m_totalSize += other.m_totalSize; jamie@264: other.m_composed.clear(); jamie@264: } jamie@264: jamie@264: std::vector*> m_composed; jamie@264: std::string m_fileInfo; jamie@264: size_t m_totalSize; jamie@264: }; jamie@264: jamie@264: namespace Generators jamie@264: { jamie@264: template jamie@264: CompositeGenerator between( T from, T to ) { jamie@264: CompositeGenerator generators; jamie@264: generators.add( new BetweenGenerator( from, to ) ); jamie@264: return generators; jamie@264: } jamie@264: jamie@264: template jamie@264: CompositeGenerator values( T val1, T val2 ) { jamie@264: CompositeGenerator generators; jamie@264: ValuesGenerator* valuesGen = new ValuesGenerator(); jamie@264: valuesGen->add( val1 ); jamie@264: valuesGen->add( val2 ); jamie@264: generators.add( valuesGen ); jamie@264: return generators; jamie@264: } jamie@264: jamie@264: template jamie@264: CompositeGenerator values( T val1, T val2, T val3 ){ jamie@264: CompositeGenerator generators; jamie@264: ValuesGenerator* valuesGen = new ValuesGenerator(); jamie@264: valuesGen->add( val1 ); jamie@264: valuesGen->add( val2 ); jamie@264: valuesGen->add( val3 ); jamie@264: generators.add( valuesGen ); jamie@264: return generators; jamie@264: } jamie@264: jamie@264: template jamie@264: CompositeGenerator values( T val1, T val2, T val3, T val4 ) { jamie@264: CompositeGenerator generators; jamie@264: ValuesGenerator* valuesGen = new ValuesGenerator(); jamie@264: valuesGen->add( val1 ); jamie@264: valuesGen->add( val2 ); jamie@264: valuesGen->add( val3 ); jamie@264: valuesGen->add( val4 ); jamie@264: generators.add( valuesGen ); jamie@264: return generators; jamie@264: } jamie@264: jamie@264: } // end namespace Generators jamie@264: jamie@264: using namespace Generators; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: #define INTERNAL_CATCH_LINESTR2( line ) #line jamie@264: #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) jamie@264: jamie@264: #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) jamie@264: jamie@264: // #included from: internal/catch_interfaces_exception.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED jamie@264: jamie@264: #include jamie@264: // #included from: catch_interfaces_registry_hub.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class TestCase; jamie@264: struct ITestCaseRegistry; jamie@264: struct IExceptionTranslatorRegistry; jamie@264: struct IExceptionTranslator; jamie@264: struct IReporterRegistry; jamie@264: struct IReporterFactory; jamie@264: jamie@264: struct IRegistryHub { jamie@264: virtual ~IRegistryHub(); jamie@264: jamie@264: virtual IReporterRegistry const& getReporterRegistry() const = 0; jamie@264: virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; jamie@264: virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; jamie@264: }; jamie@264: jamie@264: struct IMutableRegistryHub { jamie@264: virtual ~IMutableRegistryHub(); jamie@264: virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; jamie@264: virtual void registerTest( TestCase const& testInfo ) = 0; jamie@264: virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; jamie@264: }; jamie@264: jamie@264: IRegistryHub& getRegistryHub(); jamie@264: IMutableRegistryHub& getMutableRegistryHub(); jamie@264: void cleanUp(); jamie@264: std::string translateActiveException(); jamie@264: jamie@264: } jamie@264: jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: typedef std::string(*exceptionTranslateFunction)(); jamie@264: jamie@264: struct IExceptionTranslator { jamie@264: virtual ~IExceptionTranslator(); jamie@264: virtual std::string translate() const = 0; jamie@264: }; jamie@264: jamie@264: struct IExceptionTranslatorRegistry { jamie@264: virtual ~IExceptionTranslatorRegistry(); jamie@264: jamie@264: virtual std::string translateActiveException() const = 0; jamie@264: }; jamie@264: jamie@264: class ExceptionTranslatorRegistrar { jamie@264: template jamie@264: class ExceptionTranslator : public IExceptionTranslator { jamie@264: public: jamie@264: jamie@264: ExceptionTranslator( std::string(*translateFunction)( T& ) ) jamie@264: : m_translateFunction( translateFunction ) jamie@264: {} jamie@264: jamie@264: virtual std::string translate() const { jamie@264: try { jamie@264: throw; jamie@264: } jamie@264: catch( T& ex ) { jamie@264: return m_translateFunction( ex ); jamie@264: } jamie@264: } jamie@264: jamie@264: protected: jamie@264: std::string(*m_translateFunction)( T& ); jamie@264: }; jamie@264: jamie@264: public: jamie@264: template jamie@264: ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { jamie@264: getMutableRegistryHub().registerTranslator jamie@264: ( new ExceptionTranslator( translateFunction ) ); jamie@264: } jamie@264: }; jamie@264: } jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ jamie@264: static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ jamie@264: namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ jamie@264: static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) jamie@264: jamie@264: // #included from: internal/catch_approx.hpp jamie@264: #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: namespace Detail { jamie@264: jamie@264: class Approx { jamie@264: public: jamie@264: explicit Approx ( double value ) jamie@264: : m_epsilon( std::numeric_limits::epsilon()*100 ), jamie@264: m_scale( 1.0 ), jamie@264: m_value( value ) jamie@264: {} jamie@264: jamie@264: Approx( Approx const& other ) jamie@264: : m_epsilon( other.m_epsilon ), jamie@264: m_scale( other.m_scale ), jamie@264: m_value( other.m_value ) jamie@264: {} jamie@264: jamie@264: static Approx custom() { jamie@264: return Approx( 0 ); jamie@264: } jamie@264: jamie@264: Approx operator()( double value ) { jamie@264: Approx approx( value ); jamie@264: approx.epsilon( m_epsilon ); jamie@264: approx.scale( m_scale ); jamie@264: return approx; jamie@264: } jamie@264: jamie@264: friend bool operator == ( double lhs, Approx const& rhs ) { jamie@264: // Thanks to Richard Harris for his help refining this formula jamie@264: return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); jamie@264: } jamie@264: jamie@264: friend bool operator == ( Approx const& lhs, double rhs ) { jamie@264: return operator==( rhs, lhs ); jamie@264: } jamie@264: jamie@264: friend bool operator != ( double lhs, Approx const& rhs ) { jamie@264: return !operator==( lhs, rhs ); jamie@264: } jamie@264: jamie@264: friend bool operator != ( Approx const& lhs, double rhs ) { jamie@264: return !operator==( rhs, lhs ); jamie@264: } jamie@264: jamie@264: Approx& epsilon( double newEpsilon ) { jamie@264: m_epsilon = newEpsilon; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: Approx& scale( double newScale ) { jamie@264: m_scale = newScale; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: std::string toString() const { jamie@264: std::ostringstream oss; jamie@264: oss << "Approx( " << Catch::toString( m_value ) << " )"; jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: private: jamie@264: double m_epsilon; jamie@264: double m_scale; jamie@264: double m_value; jamie@264: }; jamie@264: } jamie@264: jamie@264: template<> jamie@264: inline std::string toString( Detail::Approx const& value ) { jamie@264: return value.toString(); jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: internal/catch_matchers.hpp jamie@264: #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: namespace Matchers { jamie@264: namespace Impl { jamie@264: jamie@264: template jamie@264: struct Matcher : SharedImpl jamie@264: { jamie@264: typedef ExpressionT ExpressionType; jamie@264: jamie@264: virtual ~Matcher() {} jamie@264: virtual Ptr clone() const = 0; jamie@264: virtual bool match( ExpressionT const& expr ) const = 0; jamie@264: virtual std::string toString() const = 0; jamie@264: }; jamie@264: jamie@264: template jamie@264: struct MatcherImpl : Matcher { jamie@264: jamie@264: virtual Ptr > clone() const { jamie@264: return Ptr >( new DerivedT( static_cast( *this ) ) ); jamie@264: } jamie@264: }; jamie@264: jamie@264: namespace Generic { jamie@264: jamie@264: template jamie@264: class AllOf : public MatcherImpl, ExpressionT> { jamie@264: public: jamie@264: jamie@264: AllOf() {} jamie@264: AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} jamie@264: jamie@264: AllOf& add( Matcher const& matcher ) { jamie@264: m_matchers.push_back( matcher.clone() ); jamie@264: return *this; jamie@264: } jamie@264: virtual bool match( ExpressionT const& expr ) const jamie@264: { jamie@264: for( std::size_t i = 0; i < m_matchers.size(); ++i ) jamie@264: if( !m_matchers[i]->match( expr ) ) jamie@264: return false; jamie@264: return true; jamie@264: } jamie@264: virtual std::string toString() const { jamie@264: std::ostringstream oss; jamie@264: oss << "( "; jamie@264: for( std::size_t i = 0; i < m_matchers.size(); ++i ) { jamie@264: if( i != 0 ) jamie@264: oss << " and "; jamie@264: oss << m_matchers[i]->toString(); jamie@264: } jamie@264: oss << " )"; jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: private: jamie@264: std::vector > > m_matchers; jamie@264: }; jamie@264: jamie@264: template jamie@264: class AnyOf : public MatcherImpl, ExpressionT> { jamie@264: public: jamie@264: jamie@264: AnyOf() {} jamie@264: AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} jamie@264: jamie@264: AnyOf& add( Matcher const& matcher ) { jamie@264: m_matchers.push_back( matcher.clone() ); jamie@264: return *this; jamie@264: } jamie@264: virtual bool match( ExpressionT const& expr ) const jamie@264: { jamie@264: for( std::size_t i = 0; i < m_matchers.size(); ++i ) jamie@264: if( m_matchers[i]->match( expr ) ) jamie@264: return true; jamie@264: return false; jamie@264: } jamie@264: virtual std::string toString() const { jamie@264: std::ostringstream oss; jamie@264: oss << "( "; jamie@264: for( std::size_t i = 0; i < m_matchers.size(); ++i ) { jamie@264: if( i != 0 ) jamie@264: oss << " or "; jamie@264: oss << m_matchers[i]->toString(); jamie@264: } jamie@264: oss << " )"; jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: private: jamie@264: std::vector > > m_matchers; jamie@264: }; jamie@264: jamie@264: } jamie@264: jamie@264: namespace StdString { jamie@264: jamie@264: inline std::string makeString( std::string const& str ) { return str; } jamie@264: inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } jamie@264: jamie@264: struct Equals : MatcherImpl { jamie@264: Equals( std::string const& str ) : m_str( str ){} jamie@264: Equals( Equals const& other ) : m_str( other.m_str ){} jamie@264: jamie@264: virtual ~Equals(); jamie@264: jamie@264: virtual bool match( std::string const& expr ) const { jamie@264: return m_str == expr; jamie@264: } jamie@264: virtual std::string toString() const { jamie@264: return "equals: \"" + m_str + "\""; jamie@264: } jamie@264: jamie@264: std::string m_str; jamie@264: }; jamie@264: jamie@264: struct Contains : MatcherImpl { jamie@264: Contains( std::string const& substr ) : m_substr( substr ){} jamie@264: Contains( Contains const& other ) : m_substr( other.m_substr ){} jamie@264: jamie@264: virtual ~Contains(); jamie@264: jamie@264: virtual bool match( std::string const& expr ) const { jamie@264: return expr.find( m_substr ) != std::string::npos; jamie@264: } jamie@264: virtual std::string toString() const { jamie@264: return "contains: \"" + m_substr + "\""; jamie@264: } jamie@264: jamie@264: std::string m_substr; jamie@264: }; jamie@264: jamie@264: struct StartsWith : MatcherImpl { jamie@264: StartsWith( std::string const& substr ) : m_substr( substr ){} jamie@264: StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} jamie@264: jamie@264: virtual ~StartsWith(); jamie@264: jamie@264: virtual bool match( std::string const& expr ) const { jamie@264: return expr.find( m_substr ) == 0; jamie@264: } jamie@264: virtual std::string toString() const { jamie@264: return "starts with: \"" + m_substr + "\""; jamie@264: } jamie@264: jamie@264: std::string m_substr; jamie@264: }; jamie@264: jamie@264: struct EndsWith : MatcherImpl { jamie@264: EndsWith( std::string const& substr ) : m_substr( substr ){} jamie@264: EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} jamie@264: jamie@264: virtual ~EndsWith(); jamie@264: jamie@264: virtual bool match( std::string const& expr ) const { jamie@264: return expr.find( m_substr ) == expr.size() - m_substr.size(); jamie@264: } jamie@264: virtual std::string toString() const { jamie@264: return "ends with: \"" + m_substr + "\""; jamie@264: } jamie@264: jamie@264: std::string m_substr; jamie@264: }; jamie@264: } // namespace StdString jamie@264: } // namespace Impl jamie@264: jamie@264: // The following functions create the actual matcher objects. jamie@264: // This allows the types to be inferred jamie@264: template jamie@264: inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, jamie@264: Impl::Matcher const& m2 ) { jamie@264: return Impl::Generic::AllOf().add( m1 ).add( m2 ); jamie@264: } jamie@264: template jamie@264: inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, jamie@264: Impl::Matcher const& m2, jamie@264: Impl::Matcher const& m3 ) { jamie@264: return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); jamie@264: } jamie@264: template jamie@264: inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, jamie@264: Impl::Matcher const& m2 ) { jamie@264: return Impl::Generic::AnyOf().add( m1 ).add( m2 ); jamie@264: } jamie@264: template jamie@264: inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, jamie@264: Impl::Matcher const& m2, jamie@264: Impl::Matcher const& m3 ) { jamie@264: return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); jamie@264: } jamie@264: jamie@264: inline Impl::StdString::Equals Equals( std::string const& str ) { jamie@264: return Impl::StdString::Equals( str ); jamie@264: } jamie@264: inline Impl::StdString::Equals Equals( const char* str ) { jamie@264: return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); jamie@264: } jamie@264: inline Impl::StdString::Contains Contains( std::string const& substr ) { jamie@264: return Impl::StdString::Contains( substr ); jamie@264: } jamie@264: inline Impl::StdString::Contains Contains( const char* substr ) { jamie@264: return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); jamie@264: } jamie@264: inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { jamie@264: return Impl::StdString::StartsWith( substr ); jamie@264: } jamie@264: inline Impl::StdString::StartsWith StartsWith( const char* substr ) { jamie@264: return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); jamie@264: } jamie@264: inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { jamie@264: return Impl::StdString::EndsWith( substr ); jamie@264: } jamie@264: inline Impl::StdString::EndsWith EndsWith( const char* substr ) { jamie@264: return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); jamie@264: } jamie@264: jamie@264: } // namespace Matchers jamie@264: jamie@264: using namespace Matchers; jamie@264: jamie@264: } // namespace Catch jamie@264: jamie@264: // #included from: internal/catch_interfaces_tag_alias_registry.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED jamie@264: jamie@264: // #included from: catch_tag_alias.h jamie@264: #define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct TagAlias { jamie@264: TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} jamie@264: jamie@264: std::string tag; jamie@264: SourceLineInfo lineInfo; jamie@264: }; jamie@264: jamie@264: struct RegistrarForTagAliases { jamie@264: RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } jamie@264: // #included from: catch_option.hpp jamie@264: #define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: // An optional type jamie@264: template jamie@264: class Option { jamie@264: public: jamie@264: Option() : nullableValue( NULL ) {} jamie@264: Option( T const& _value ) jamie@264: : nullableValue( new( storage ) T( _value ) ) jamie@264: {} jamie@264: Option( Option const& _other ) jamie@264: : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) jamie@264: {} jamie@264: jamie@264: ~Option() { jamie@264: reset(); jamie@264: } jamie@264: jamie@264: Option& operator= ( Option const& _other ) { jamie@264: if( &_other != this ) { jamie@264: reset(); jamie@264: if( _other ) jamie@264: nullableValue = new( storage ) T( *_other ); jamie@264: } jamie@264: return *this; jamie@264: } jamie@264: Option& operator = ( T const& _value ) { jamie@264: reset(); jamie@264: nullableValue = new( storage ) T( _value ); jamie@264: return *this; jamie@264: } jamie@264: jamie@264: void reset() { jamie@264: if( nullableValue ) jamie@264: nullableValue->~T(); jamie@264: nullableValue = NULL; jamie@264: } jamie@264: jamie@264: T& operator*() { return *nullableValue; } jamie@264: T const& operator*() const { return *nullableValue; } jamie@264: T* operator->() { return nullableValue; } jamie@264: const T* operator->() const { return nullableValue; } jamie@264: jamie@264: T valueOr( T const& defaultValue ) const { jamie@264: return nullableValue ? *nullableValue : defaultValue; jamie@264: } jamie@264: jamie@264: bool some() const { return nullableValue != NULL; } jamie@264: bool none() const { return nullableValue == NULL; } jamie@264: jamie@264: bool operator !() const { return nullableValue == NULL; } jamie@264: operator SafeBool::type() const { jamie@264: return SafeBool::makeSafe( some() ); jamie@264: } jamie@264: jamie@264: private: jamie@264: T* nullableValue; jamie@264: char storage[sizeof(T)]; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct ITagAliasRegistry { jamie@264: virtual ~ITagAliasRegistry(); jamie@264: virtual Option find( std::string const& alias ) const = 0; jamie@264: virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; jamie@264: jamie@264: static ITagAliasRegistry const& get(); jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // These files are included here so the single_include script doesn't put them jamie@264: // in the conditionally compiled sections jamie@264: // #included from: internal/catch_test_case_info.h jamie@264: #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Wpadded" jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct ITestCase; jamie@264: jamie@264: struct TestCaseInfo { jamie@264: enum SpecialProperties{ jamie@264: None = 0, jamie@264: IsHidden = 1 << 1, jamie@264: ShouldFail = 1 << 2, jamie@264: MayFail = 1 << 3, jamie@264: Throws = 1 << 4 jamie@264: }; jamie@264: jamie@264: TestCaseInfo( std::string const& _name, jamie@264: std::string const& _className, jamie@264: std::string const& _description, jamie@264: std::set const& _tags, jamie@264: SourceLineInfo const& _lineInfo ); jamie@264: jamie@264: TestCaseInfo( TestCaseInfo const& other ); jamie@264: jamie@264: bool isHidden() const; jamie@264: bool throws() const; jamie@264: bool okToFail() const; jamie@264: bool expectedToFail() const; jamie@264: jamie@264: std::string name; jamie@264: std::string className; jamie@264: std::string description; jamie@264: std::set tags; jamie@264: std::set lcaseTags; jamie@264: std::string tagsAsString; jamie@264: SourceLineInfo lineInfo; jamie@264: SpecialProperties properties; jamie@264: }; jamie@264: jamie@264: class TestCase : public TestCaseInfo { jamie@264: public: jamie@264: jamie@264: TestCase( ITestCase* testCase, TestCaseInfo const& info ); jamie@264: TestCase( TestCase const& other ); jamie@264: jamie@264: TestCase withName( std::string const& _newName ) const; jamie@264: jamie@264: void invoke() const; jamie@264: jamie@264: TestCaseInfo const& getTestCaseInfo() const; jamie@264: jamie@264: void swap( TestCase& other ); jamie@264: bool operator == ( TestCase const& other ) const; jamie@264: bool operator < ( TestCase const& other ) const; jamie@264: TestCase& operator = ( TestCase const& other ); jamie@264: jamie@264: private: jamie@264: Ptr test; jamie@264: }; jamie@264: jamie@264: TestCase makeTestCase( ITestCase* testCase, jamie@264: std::string const& className, jamie@264: std::string const& name, jamie@264: std::string const& description, jamie@264: SourceLineInfo const& lineInfo ); jamie@264: } jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #endif jamie@264: jamie@264: jamie@264: #ifdef __OBJC__ jamie@264: // #included from: internal/catch_objc.hpp jamie@264: #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED jamie@264: jamie@264: #import jamie@264: jamie@264: #include jamie@264: jamie@264: // NB. Any general catch headers included here must be included jamie@264: // in catch.hpp first to make sure they are included by the single jamie@264: // header for non obj-usage jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: // This protocol is really only here for (self) documenting purposes, since jamie@264: // all its methods are optional. jamie@264: @protocol OcFixture jamie@264: jamie@264: @optional jamie@264: jamie@264: -(void) setUp; jamie@264: -(void) tearDown; jamie@264: jamie@264: @end jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class OcMethod : public SharedImpl { jamie@264: jamie@264: public: jamie@264: OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} jamie@264: jamie@264: virtual void invoke() const { jamie@264: id obj = [[m_cls alloc] init]; jamie@264: jamie@264: performOptionalSelector( obj, @selector(setUp) ); jamie@264: performOptionalSelector( obj, m_sel ); jamie@264: performOptionalSelector( obj, @selector(tearDown) ); jamie@264: jamie@264: arcSafeRelease( obj ); jamie@264: } jamie@264: private: jamie@264: virtual ~OcMethod() {} jamie@264: jamie@264: Class m_cls; jamie@264: SEL m_sel; jamie@264: }; jamie@264: jamie@264: namespace Detail{ jamie@264: jamie@264: inline std::string getAnnotation( Class cls, jamie@264: std::string const& annotationName, jamie@264: std::string const& testCaseName ) { jamie@264: NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; jamie@264: SEL sel = NSSelectorFromString( selStr ); jamie@264: arcSafeRelease( selStr ); jamie@264: id value = performOptionalSelector( cls, sel ); jamie@264: if( value ) jamie@264: return [(NSString*)value UTF8String]; jamie@264: return ""; jamie@264: } jamie@264: } jamie@264: jamie@264: inline size_t registerTestMethods() { jamie@264: size_t noTestMethods = 0; jamie@264: int noClasses = objc_getClassList( NULL, 0 ); jamie@264: jamie@264: Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); jamie@264: objc_getClassList( classes, noClasses ); jamie@264: jamie@264: for( int c = 0; c < noClasses; c++ ) { jamie@264: Class cls = classes[c]; jamie@264: { jamie@264: u_int count; jamie@264: Method* methods = class_copyMethodList( cls, &count ); jamie@264: for( u_int m = 0; m < count ; m++ ) { jamie@264: SEL selector = method_getName(methods[m]); jamie@264: std::string methodName = sel_getName(selector); jamie@264: if( startsWith( methodName, "Catch_TestCase_" ) ) { jamie@264: std::string testCaseName = methodName.substr( 15 ); jamie@264: std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); jamie@264: std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); jamie@264: const char* className = class_getName( cls ); jamie@264: jamie@264: getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); jamie@264: noTestMethods++; jamie@264: } jamie@264: } jamie@264: free(methods); jamie@264: } jamie@264: } jamie@264: return noTestMethods; jamie@264: } jamie@264: jamie@264: namespace Matchers { jamie@264: namespace Impl { jamie@264: namespace NSStringMatchers { jamie@264: jamie@264: template jamie@264: struct StringHolder : MatcherImpl{ jamie@264: StringHolder( NSString* substr ) : m_substr( [substr copy] ){} jamie@264: StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} jamie@264: StringHolder() { jamie@264: arcSafeRelease( m_substr ); jamie@264: } jamie@264: jamie@264: NSString* m_substr; jamie@264: }; jamie@264: jamie@264: struct Equals : StringHolder { jamie@264: Equals( NSString* substr ) : StringHolder( substr ){} jamie@264: jamie@264: virtual bool match( ExpressionType const& str ) const { jamie@264: return (str != nil || m_substr == nil ) && jamie@264: [str isEqualToString:m_substr]; jamie@264: } jamie@264: jamie@264: virtual std::string toString() const { jamie@264: return "equals string: " + Catch::toString( m_substr ); jamie@264: } jamie@264: }; jamie@264: jamie@264: struct Contains : StringHolder { jamie@264: Contains( NSString* substr ) : StringHolder( substr ){} jamie@264: jamie@264: virtual bool match( ExpressionType const& str ) const { jamie@264: return (str != nil || m_substr == nil ) && jamie@264: [str rangeOfString:m_substr].location != NSNotFound; jamie@264: } jamie@264: jamie@264: virtual std::string toString() const { jamie@264: return "contains string: " + Catch::toString( m_substr ); jamie@264: } jamie@264: }; jamie@264: jamie@264: struct StartsWith : StringHolder { jamie@264: StartsWith( NSString* substr ) : StringHolder( substr ){} jamie@264: jamie@264: virtual bool match( ExpressionType const& str ) const { jamie@264: return (str != nil || m_substr == nil ) && jamie@264: [str rangeOfString:m_substr].location == 0; jamie@264: } jamie@264: jamie@264: virtual std::string toString() const { jamie@264: return "starts with: " + Catch::toString( m_substr ); jamie@264: } jamie@264: }; jamie@264: struct EndsWith : StringHolder { jamie@264: EndsWith( NSString* substr ) : StringHolder( substr ){} jamie@264: jamie@264: virtual bool match( ExpressionType const& str ) const { jamie@264: return (str != nil || m_substr == nil ) && jamie@264: [str rangeOfString:m_substr].location == [str length] - [m_substr length]; jamie@264: } jamie@264: jamie@264: virtual std::string toString() const { jamie@264: return "ends with: " + Catch::toString( m_substr ); jamie@264: } jamie@264: }; jamie@264: jamie@264: } // namespace NSStringMatchers jamie@264: } // namespace Impl jamie@264: jamie@264: inline Impl::NSStringMatchers::Equals jamie@264: Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } jamie@264: jamie@264: inline Impl::NSStringMatchers::Contains jamie@264: Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } jamie@264: jamie@264: inline Impl::NSStringMatchers::StartsWith jamie@264: StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } jamie@264: jamie@264: inline Impl::NSStringMatchers::EndsWith jamie@264: EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } jamie@264: jamie@264: } // namespace Matchers jamie@264: jamie@264: using namespace Matchers; jamie@264: jamie@264: } // namespace Catch jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////////// jamie@264: #define OC_TEST_CASE( name, desc )\ jamie@264: +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ jamie@264: {\ jamie@264: return @ name; \ jamie@264: }\ jamie@264: +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ jamie@264: { \ jamie@264: return @ desc; \ jamie@264: } \ jamie@264: -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) jamie@264: jamie@264: #endif jamie@264: jamie@264: #ifdef CATCH_CONFIG_RUNNER jamie@264: // #included from: internal/catch_impl.hpp jamie@264: #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED jamie@264: jamie@264: // Collect all the implementation files together here jamie@264: // These are the equivalent of what would usually be cpp files jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Wweak-vtables" jamie@264: #endif jamie@264: jamie@264: // #included from: catch_runner.hpp jamie@264: #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED jamie@264: jamie@264: // #included from: internal/catch_commandline.hpp jamie@264: #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_config.hpp jamie@264: #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_test_spec_parser.hpp jamie@264: #define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Wpadded" jamie@264: #endif jamie@264: jamie@264: // #included from: catch_test_spec.hpp jamie@264: #define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Wpadded" jamie@264: #endif jamie@264: jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class TestSpec { jamie@264: struct Pattern : SharedImpl<> { jamie@264: virtual ~Pattern(); jamie@264: virtual bool matches( TestCaseInfo const& testCase ) const = 0; jamie@264: }; jamie@264: class NamePattern : public Pattern { jamie@264: enum WildcardPosition { jamie@264: NoWildcard = 0, jamie@264: WildcardAtStart = 1, jamie@264: WildcardAtEnd = 2, jamie@264: WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd jamie@264: }; jamie@264: jamie@264: public: jamie@264: NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { jamie@264: if( startsWith( m_name, "*" ) ) { jamie@264: m_name = m_name.substr( 1 ); jamie@264: m_wildcard = WildcardAtStart; jamie@264: } jamie@264: if( endsWith( m_name, "*" ) ) { jamie@264: m_name = m_name.substr( 0, m_name.size()-1 ); jamie@264: m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); jamie@264: } jamie@264: } jamie@264: virtual ~NamePattern(); jamie@264: virtual bool matches( TestCaseInfo const& testCase ) const { jamie@264: switch( m_wildcard ) { jamie@264: case NoWildcard: jamie@264: return m_name == toLower( testCase.name ); jamie@264: case WildcardAtStart: jamie@264: return endsWith( toLower( testCase.name ), m_name ); jamie@264: case WildcardAtEnd: jamie@264: return startsWith( toLower( testCase.name ), m_name ); jamie@264: case WildcardAtBothEnds: jamie@264: return contains( toLower( testCase.name ), m_name ); jamie@264: } jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Wunreachable-code" jamie@264: #endif jamie@264: throw std::logic_error( "Unknown enum" ); jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #endif jamie@264: } jamie@264: private: jamie@264: std::string m_name; jamie@264: WildcardPosition m_wildcard; jamie@264: }; jamie@264: class TagPattern : public Pattern { jamie@264: public: jamie@264: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} jamie@264: virtual ~TagPattern(); jamie@264: virtual bool matches( TestCaseInfo const& testCase ) const { jamie@264: return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); jamie@264: } jamie@264: private: jamie@264: std::string m_tag; jamie@264: }; jamie@264: class ExcludedPattern : public Pattern { jamie@264: public: jamie@264: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} jamie@264: virtual ~ExcludedPattern(); jamie@264: virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } jamie@264: private: jamie@264: Ptr m_underlyingPattern; jamie@264: }; jamie@264: jamie@264: struct Filter { jamie@264: std::vector > m_patterns; jamie@264: jamie@264: bool matches( TestCaseInfo const& testCase ) const { jamie@264: // All patterns in a filter must match for the filter to be a match jamie@264: for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) jamie@264: if( !(*it)->matches( testCase ) ) jamie@264: return false; jamie@264: return true; jamie@264: } jamie@264: }; jamie@264: jamie@264: public: jamie@264: bool hasFilters() const { jamie@264: return !m_filters.empty(); jamie@264: } jamie@264: bool matches( TestCaseInfo const& testCase ) const { jamie@264: // A TestSpec matches if any filter matches jamie@264: for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) jamie@264: if( it->matches( testCase ) ) jamie@264: return true; jamie@264: return false; jamie@264: } jamie@264: jamie@264: private: jamie@264: std::vector m_filters; jamie@264: jamie@264: friend class TestSpecParser; jamie@264: }; jamie@264: } jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class TestSpecParser { jamie@264: enum Mode{ None, Name, QuotedName, Tag }; jamie@264: Mode m_mode; jamie@264: bool m_exclusion; jamie@264: std::size_t m_start, m_pos; jamie@264: std::string m_arg; jamie@264: TestSpec::Filter m_currentFilter; jamie@264: TestSpec m_testSpec; jamie@264: ITagAliasRegistry const* m_tagAliases; jamie@264: jamie@264: public: jamie@264: TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} jamie@264: jamie@264: TestSpecParser& parse( std::string const& arg ) { jamie@264: m_mode = None; jamie@264: m_exclusion = false; jamie@264: m_start = std::string::npos; jamie@264: m_arg = m_tagAliases->expandAliases( arg ); jamie@264: for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) jamie@264: visitChar( m_arg[m_pos] ); jamie@264: if( m_mode == Name ) jamie@264: addPattern(); jamie@264: return *this; jamie@264: } jamie@264: TestSpec testSpec() { jamie@264: addFilter(); jamie@264: return m_testSpec; jamie@264: } jamie@264: private: jamie@264: void visitChar( char c ) { jamie@264: if( m_mode == None ) { jamie@264: switch( c ) { jamie@264: case ' ': return; jamie@264: case '~': m_exclusion = true; return; jamie@264: case '[': return startNewMode( Tag, ++m_pos ); jamie@264: case '"': return startNewMode( QuotedName, ++m_pos ); jamie@264: default: startNewMode( Name, m_pos ); break; jamie@264: } jamie@264: } jamie@264: if( m_mode == Name ) { jamie@264: if( c == ',' ) { jamie@264: addPattern(); jamie@264: addFilter(); jamie@264: } jamie@264: else if( c == '[' ) { jamie@264: if( subString() == "exclude:" ) jamie@264: m_exclusion = true; jamie@264: else jamie@264: addPattern(); jamie@264: startNewMode( Tag, ++m_pos ); jamie@264: } jamie@264: } jamie@264: else if( m_mode == QuotedName && c == '"' ) jamie@264: addPattern(); jamie@264: else if( m_mode == Tag && c == ']' ) jamie@264: addPattern(); jamie@264: } jamie@264: void startNewMode( Mode mode, std::size_t start ) { jamie@264: m_mode = mode; jamie@264: m_start = start; jamie@264: } jamie@264: std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } jamie@264: template jamie@264: void addPattern() { jamie@264: std::string token = subString(); jamie@264: if( startsWith( token, "exclude:" ) ) { jamie@264: m_exclusion = true; jamie@264: token = token.substr( 8 ); jamie@264: } jamie@264: if( !token.empty() ) { jamie@264: Ptr pattern = new T( token ); jamie@264: if( m_exclusion ) jamie@264: pattern = new TestSpec::ExcludedPattern( pattern ); jamie@264: m_currentFilter.m_patterns.push_back( pattern ); jamie@264: } jamie@264: m_exclusion = false; jamie@264: m_mode = None; jamie@264: } jamie@264: void addFilter() { jamie@264: if( !m_currentFilter.m_patterns.empty() ) { jamie@264: m_testSpec.m_filters.push_back( m_currentFilter ); jamie@264: m_currentFilter = TestSpec::Filter(); jamie@264: } jamie@264: } jamie@264: }; jamie@264: inline TestSpec parseTestSpec( std::string const& arg ) { jamie@264: return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); jamie@264: } jamie@264: jamie@264: } // namespace Catch jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #endif jamie@264: jamie@264: // #included from: catch_interfaces_config.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct Verbosity { enum Level { jamie@264: NoOutput = 0, jamie@264: Quiet, jamie@264: Normal jamie@264: }; }; jamie@264: jamie@264: struct WarnAbout { enum What { jamie@264: Nothing = 0x00, jamie@264: NoAssertions = 0x01 jamie@264: }; }; jamie@264: jamie@264: struct ShowDurations { enum OrNot { jamie@264: DefaultForReporter, jamie@264: Always, jamie@264: Never jamie@264: }; }; jamie@264: jamie@264: class TestSpec; jamie@264: jamie@264: struct IConfig : IShared { jamie@264: jamie@264: virtual ~IConfig(); jamie@264: jamie@264: virtual bool allowThrows() const = 0; jamie@264: virtual std::ostream& stream() const = 0; jamie@264: virtual std::string name() const = 0; jamie@264: virtual bool includeSuccessfulResults() const = 0; jamie@264: virtual bool shouldDebugBreak() const = 0; jamie@264: virtual bool warnAboutMissingAssertions() const = 0; jamie@264: virtual int abortAfter() const = 0; jamie@264: virtual bool showInvisibles() const = 0; jamie@264: virtual ShowDurations::OrNot showDurations() const = 0; jamie@264: virtual TestSpec const& testSpec() const = 0; jamie@264: }; jamie@264: } jamie@264: jamie@264: // #included from: catch_stream.h jamie@264: #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic ignored "-Wpadded" jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class Stream { jamie@264: public: jamie@264: Stream(); jamie@264: Stream( std::streambuf* _streamBuf, bool _isOwned ); jamie@264: void release(); jamie@264: jamie@264: std::streambuf* streamBuf; jamie@264: jamie@264: private: jamie@264: bool isOwned; jamie@264: }; jamie@264: } jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: #ifndef CATCH_CONFIG_CONSOLE_WIDTH jamie@264: #define CATCH_CONFIG_CONSOLE_WIDTH 80 jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct ConfigData { jamie@264: jamie@264: ConfigData() jamie@264: : listTests( false ), jamie@264: listTags( false ), jamie@264: listReporters( false ), jamie@264: listTestNamesOnly( false ), jamie@264: showSuccessfulTests( false ), jamie@264: shouldDebugBreak( false ), jamie@264: noThrow( false ), jamie@264: showHelp( false ), jamie@264: showInvisibles( false ), jamie@264: abortAfter( -1 ), jamie@264: verbosity( Verbosity::Normal ), jamie@264: warnings( WarnAbout::Nothing ), jamie@264: showDurations( ShowDurations::DefaultForReporter ) jamie@264: {} jamie@264: jamie@264: bool listTests; jamie@264: bool listTags; jamie@264: bool listReporters; jamie@264: bool listTestNamesOnly; jamie@264: jamie@264: bool showSuccessfulTests; jamie@264: bool shouldDebugBreak; jamie@264: bool noThrow; jamie@264: bool showHelp; jamie@264: bool showInvisibles; jamie@264: jamie@264: int abortAfter; jamie@264: jamie@264: Verbosity::Level verbosity; jamie@264: WarnAbout::What warnings; jamie@264: ShowDurations::OrNot showDurations; jamie@264: jamie@264: std::string reporterName; jamie@264: std::string outputFilename; jamie@264: std::string name; jamie@264: std::string processName; jamie@264: jamie@264: std::vector testsOrTags; jamie@264: }; jamie@264: jamie@264: class Config : public SharedImpl { jamie@264: private: jamie@264: Config( Config const& other ); jamie@264: Config& operator = ( Config const& other ); jamie@264: virtual void dummy(); jamie@264: public: jamie@264: jamie@264: Config() jamie@264: : m_os( std::cout.rdbuf() ) jamie@264: {} jamie@264: jamie@264: Config( ConfigData const& data ) jamie@264: : m_data( data ), jamie@264: m_os( std::cout.rdbuf() ) jamie@264: { jamie@264: if( !data.testsOrTags.empty() ) { jamie@264: TestSpecParser parser( ITagAliasRegistry::get() ); jamie@264: for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) jamie@264: parser.parse( data.testsOrTags[i] ); jamie@264: m_testSpec = parser.testSpec(); jamie@264: } jamie@264: } jamie@264: jamie@264: virtual ~Config() { jamie@264: m_os.rdbuf( std::cout.rdbuf() ); jamie@264: m_stream.release(); jamie@264: } jamie@264: jamie@264: void setFilename( std::string const& filename ) { jamie@264: m_data.outputFilename = filename; jamie@264: } jamie@264: jamie@264: std::string const& getFilename() const { jamie@264: return m_data.outputFilename ; jamie@264: } jamie@264: jamie@264: bool listTests() const { return m_data.listTests; } jamie@264: bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } jamie@264: bool listTags() const { return m_data.listTags; } jamie@264: bool listReporters() const { return m_data.listReporters; } jamie@264: jamie@264: std::string getProcessName() const { return m_data.processName; } jamie@264: jamie@264: bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } jamie@264: jamie@264: void setStreamBuf( std::streambuf* buf ) { jamie@264: m_os.rdbuf( buf ? buf : std::cout.rdbuf() ); jamie@264: } jamie@264: jamie@264: void useStream( std::string const& streamName ) { jamie@264: Stream stream = createStream( streamName ); jamie@264: setStreamBuf( stream.streamBuf ); jamie@264: m_stream.release(); jamie@264: m_stream = stream; jamie@264: } jamie@264: jamie@264: std::string getReporterName() const { return m_data.reporterName; } jamie@264: jamie@264: int abortAfter() const { return m_data.abortAfter; } jamie@264: jamie@264: TestSpec const& testSpec() const { return m_testSpec; } jamie@264: jamie@264: bool showHelp() const { return m_data.showHelp; } jamie@264: bool showInvisibles() const { return m_data.showInvisibles; } jamie@264: jamie@264: // IConfig interface jamie@264: virtual bool allowThrows() const { return !m_data.noThrow; } jamie@264: virtual std::ostream& stream() const { return m_os; } jamie@264: virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } jamie@264: virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } jamie@264: virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } jamie@264: virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } jamie@264: jamie@264: private: jamie@264: ConfigData m_data; jamie@264: jamie@264: Stream m_stream; jamie@264: mutable std::ostream m_os; jamie@264: TestSpec m_testSpec; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_clara.h jamie@264: #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED jamie@264: jamie@264: // Use Catch's value for console width (store Clara's off to the side, if present) jamie@264: #ifdef CLARA_CONFIG_CONSOLE_WIDTH jamie@264: #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH jamie@264: #undef CLARA_CONFIG_CONSOLE_WIDTH jamie@264: #endif jamie@264: #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH jamie@264: jamie@264: // Declare Clara inside the Catch namespace jamie@264: #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { jamie@264: // #included from: ../external/clara.h jamie@264: jamie@264: // Only use header guard if we are not using an outer namespace jamie@264: #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) jamie@264: jamie@264: #ifndef STITCH_CLARA_OPEN_NAMESPACE jamie@264: #define TWOBLUECUBES_CLARA_H_INCLUDED jamie@264: #define STITCH_CLARA_OPEN_NAMESPACE jamie@264: #define STITCH_CLARA_CLOSE_NAMESPACE jamie@264: #else jamie@264: #define STITCH_CLARA_CLOSE_NAMESPACE } jamie@264: #endif jamie@264: jamie@264: #define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE jamie@264: jamie@264: // ----------- #included from tbc_text_format.h ----------- jamie@264: jamie@264: // Only use header guard if we are not using an outer namespace jamie@264: #if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) jamie@264: #ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE jamie@264: #define TBC_TEXT_FORMAT_H_INCLUDED jamie@264: #endif jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: // Use optional outer namespace jamie@264: #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE jamie@264: namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { jamie@264: #endif jamie@264: jamie@264: namespace Tbc { jamie@264: jamie@264: #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH jamie@264: const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; jamie@264: #else jamie@264: const unsigned int consoleWidth = 80; jamie@264: #endif jamie@264: jamie@264: struct TextAttributes { jamie@264: TextAttributes() jamie@264: : initialIndent( std::string::npos ), jamie@264: indent( 0 ), jamie@264: width( consoleWidth-1 ), jamie@264: tabChar( '\t' ) jamie@264: {} jamie@264: jamie@264: TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } jamie@264: TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } jamie@264: TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } jamie@264: TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } jamie@264: jamie@264: std::size_t initialIndent; // indent of first line, or npos jamie@264: std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos jamie@264: std::size_t width; // maximum width of text, including indent. Longer text will wrap jamie@264: char tabChar; // If this char is seen the indent is changed to current pos jamie@264: }; jamie@264: jamie@264: class Text { jamie@264: public: jamie@264: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) jamie@264: : attr( _attr ) jamie@264: { jamie@264: std::string wrappableChars = " [({.,/|\\-"; jamie@264: std::size_t indent = _attr.initialIndent != std::string::npos jamie@264: ? _attr.initialIndent jamie@264: : _attr.indent; jamie@264: std::string remainder = _str; jamie@264: jamie@264: while( !remainder.empty() ) { jamie@264: if( lines.size() >= 1000 ) { jamie@264: lines.push_back( "... message truncated due to excessive size" ); jamie@264: return; jamie@264: } jamie@264: std::size_t tabPos = std::string::npos; jamie@264: std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); jamie@264: std::size_t pos = remainder.find_first_of( '\n' ); jamie@264: if( pos <= width ) { jamie@264: width = pos; jamie@264: } jamie@264: pos = remainder.find_last_of( _attr.tabChar, width ); jamie@264: if( pos != std::string::npos ) { jamie@264: tabPos = pos; jamie@264: if( remainder[width] == '\n' ) jamie@264: width--; jamie@264: remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); jamie@264: } jamie@264: jamie@264: if( width == remainder.size() ) { jamie@264: spliceLine( indent, remainder, width ); jamie@264: } jamie@264: else if( remainder[width] == '\n' ) { jamie@264: spliceLine( indent, remainder, width ); jamie@264: if( width <= 1 || remainder.size() != 1 ) jamie@264: remainder = remainder.substr( 1 ); jamie@264: indent = _attr.indent; jamie@264: } jamie@264: else { jamie@264: pos = remainder.find_last_of( wrappableChars, width ); jamie@264: if( pos != std::string::npos && pos > 0 ) { jamie@264: spliceLine( indent, remainder, pos ); jamie@264: if( remainder[0] == ' ' ) jamie@264: remainder = remainder.substr( 1 ); jamie@264: } jamie@264: else { jamie@264: spliceLine( indent, remainder, width-1 ); jamie@264: lines.back() += "-"; jamie@264: } jamie@264: if( lines.size() == 1 ) jamie@264: indent = _attr.indent; jamie@264: if( tabPos != std::string::npos ) jamie@264: indent += tabPos; jamie@264: } jamie@264: } jamie@264: } jamie@264: jamie@264: void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { jamie@264: lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); jamie@264: _remainder = _remainder.substr( _pos ); jamie@264: } jamie@264: jamie@264: typedef std::vector::const_iterator const_iterator; jamie@264: jamie@264: const_iterator begin() const { return lines.begin(); } jamie@264: const_iterator end() const { return lines.end(); } jamie@264: std::string const& last() const { return lines.back(); } jamie@264: std::size_t size() const { return lines.size(); } jamie@264: std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } jamie@264: std::string toString() const { jamie@264: std::ostringstream oss; jamie@264: oss << *this; jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { jamie@264: for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); jamie@264: it != itEnd; ++it ) { jamie@264: if( it != _text.begin() ) jamie@264: _stream << "\n"; jamie@264: _stream << *it; jamie@264: } jamie@264: return _stream; jamie@264: } jamie@264: jamie@264: private: jamie@264: std::string str; jamie@264: TextAttributes attr; jamie@264: std::vector lines; jamie@264: }; jamie@264: jamie@264: } // end namespace Tbc jamie@264: jamie@264: #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE jamie@264: } // end outer namespace jamie@264: #endif jamie@264: jamie@264: #endif // TBC_TEXT_FORMAT_H_INCLUDED jamie@264: jamie@264: // ----------- end of #include from tbc_text_format.h ----------- jamie@264: // ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h jamie@264: jamie@264: #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: // Use optional outer namespace jamie@264: #ifdef STITCH_CLARA_OPEN_NAMESPACE jamie@264: STITCH_CLARA_OPEN_NAMESPACE jamie@264: #endif jamie@264: jamie@264: namespace Clara { jamie@264: jamie@264: struct UnpositionalTag {}; jamie@264: jamie@264: extern UnpositionalTag _; jamie@264: jamie@264: #ifdef CLARA_CONFIG_MAIN jamie@264: UnpositionalTag _; jamie@264: #endif jamie@264: jamie@264: namespace Detail { jamie@264: jamie@264: #ifdef CLARA_CONSOLE_WIDTH jamie@264: const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; jamie@264: #else jamie@264: const unsigned int consoleWidth = 80; jamie@264: #endif jamie@264: jamie@264: using namespace Tbc; jamie@264: jamie@264: inline bool startsWith( std::string const& str, std::string const& prefix ) { jamie@264: return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; jamie@264: } jamie@264: jamie@264: template struct RemoveConstRef{ typedef T type; }; jamie@264: template struct RemoveConstRef{ typedef T type; }; jamie@264: template struct RemoveConstRef{ typedef T type; }; jamie@264: template struct RemoveConstRef{ typedef T type; }; jamie@264: jamie@264: template struct IsBool { static const bool value = false; }; jamie@264: template<> struct IsBool { static const bool value = true; }; jamie@264: jamie@264: template jamie@264: void convertInto( std::string const& _source, T& _dest ) { jamie@264: std::stringstream ss; jamie@264: ss << _source; jamie@264: ss >> _dest; jamie@264: if( ss.fail() ) jamie@264: throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); jamie@264: } jamie@264: inline void convertInto( std::string const& _source, std::string& _dest ) { jamie@264: _dest = _source; jamie@264: } jamie@264: inline void convertInto( std::string const& _source, bool& _dest ) { jamie@264: std::string sourceLC = _source; jamie@264: std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); jamie@264: if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) jamie@264: _dest = true; jamie@264: else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) jamie@264: _dest = false; jamie@264: else jamie@264: throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); jamie@264: } jamie@264: inline void convertInto( bool _source, bool& _dest ) { jamie@264: _dest = _source; jamie@264: } jamie@264: template jamie@264: inline void convertInto( bool, T& ) { jamie@264: throw std::runtime_error( "Invalid conversion" ); jamie@264: } jamie@264: jamie@264: template jamie@264: struct IArgFunction { jamie@264: virtual ~IArgFunction() {} jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: IArgFunction() = default; jamie@264: IArgFunction( IArgFunction const& ) = default; jamie@264: # endif jamie@264: virtual void set( ConfigT& config, std::string const& value ) const = 0; jamie@264: virtual void setFlag( ConfigT& config ) const = 0; jamie@264: virtual bool takesArg() const = 0; jamie@264: virtual IArgFunction* clone() const = 0; jamie@264: }; jamie@264: jamie@264: template jamie@264: class BoundArgFunction { jamie@264: public: jamie@264: BoundArgFunction() : functionObj( NULL ) {} jamie@264: BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} jamie@264: BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} jamie@264: BoundArgFunction& operator = ( BoundArgFunction const& other ) { jamie@264: IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; jamie@264: delete functionObj; jamie@264: functionObj = newFunctionObj; jamie@264: return *this; jamie@264: } jamie@264: ~BoundArgFunction() { delete functionObj; } jamie@264: jamie@264: void set( ConfigT& config, std::string const& value ) const { jamie@264: functionObj->set( config, value ); jamie@264: } jamie@264: void setFlag( ConfigT& config ) const { jamie@264: functionObj->setFlag( config ); jamie@264: } jamie@264: bool takesArg() const { return functionObj->takesArg(); } jamie@264: jamie@264: bool isSet() const { jamie@264: return functionObj != NULL; jamie@264: } jamie@264: private: jamie@264: IArgFunction* functionObj; jamie@264: }; jamie@264: jamie@264: template jamie@264: struct NullBinder : IArgFunction{ jamie@264: virtual void set( C&, std::string const& ) const {} jamie@264: virtual void setFlag( C& ) const {} jamie@264: virtual bool takesArg() const { return true; } jamie@264: virtual IArgFunction* clone() const { return new NullBinder( *this ); } jamie@264: }; jamie@264: jamie@264: template jamie@264: struct BoundDataMember : IArgFunction{ jamie@264: BoundDataMember( M C::* _member ) : member( _member ) {} jamie@264: virtual void set( C& p, std::string const& stringValue ) const { jamie@264: convertInto( stringValue, p.*member ); jamie@264: } jamie@264: virtual void setFlag( C& p ) const { jamie@264: convertInto( true, p.*member ); jamie@264: } jamie@264: virtual bool takesArg() const { return !IsBool::value; } jamie@264: virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } jamie@264: M C::* member; jamie@264: }; jamie@264: template jamie@264: struct BoundUnaryMethod : IArgFunction{ jamie@264: BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} jamie@264: virtual void set( C& p, std::string const& stringValue ) const { jamie@264: typename RemoveConstRef::type value; jamie@264: convertInto( stringValue, value ); jamie@264: (p.*member)( value ); jamie@264: } jamie@264: virtual void setFlag( C& p ) const { jamie@264: typename RemoveConstRef::type value; jamie@264: convertInto( true, value ); jamie@264: (p.*member)( value ); jamie@264: } jamie@264: virtual bool takesArg() const { return !IsBool::value; } jamie@264: virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } jamie@264: void (C::*member)( M ); jamie@264: }; jamie@264: template jamie@264: struct BoundNullaryMethod : IArgFunction{ jamie@264: BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} jamie@264: virtual void set( C& p, std::string const& stringValue ) const { jamie@264: bool value; jamie@264: convertInto( stringValue, value ); jamie@264: if( value ) jamie@264: (p.*member)(); jamie@264: } jamie@264: virtual void setFlag( C& p ) const { jamie@264: (p.*member)(); jamie@264: } jamie@264: virtual bool takesArg() const { return false; } jamie@264: virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } jamie@264: void (C::*member)(); jamie@264: }; jamie@264: jamie@264: template jamie@264: struct BoundUnaryFunction : IArgFunction{ jamie@264: BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} jamie@264: virtual void set( C& obj, std::string const& stringValue ) const { jamie@264: bool value; jamie@264: convertInto( stringValue, value ); jamie@264: if( value ) jamie@264: function( obj ); jamie@264: } jamie@264: virtual void setFlag( C& p ) const { jamie@264: function( p ); jamie@264: } jamie@264: virtual bool takesArg() const { return false; } jamie@264: virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } jamie@264: void (*function)( C& ); jamie@264: }; jamie@264: jamie@264: template jamie@264: struct BoundBinaryFunction : IArgFunction{ jamie@264: BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} jamie@264: virtual void set( C& obj, std::string const& stringValue ) const { jamie@264: typename RemoveConstRef::type value; jamie@264: convertInto( stringValue, value ); jamie@264: function( obj, value ); jamie@264: } jamie@264: virtual void setFlag( C& obj ) const { jamie@264: typename RemoveConstRef::type value; jamie@264: convertInto( true, value ); jamie@264: function( obj, value ); jamie@264: } jamie@264: virtual bool takesArg() const { return !IsBool::value; } jamie@264: virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } jamie@264: void (*function)( C&, T ); jamie@264: }; jamie@264: jamie@264: } // namespace Detail jamie@264: jamie@264: struct Parser { jamie@264: Parser() : separators( " \t=:" ) {} jamie@264: jamie@264: struct Token { jamie@264: enum Type { Positional, ShortOpt, LongOpt }; jamie@264: Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} jamie@264: Type type; jamie@264: std::string data; jamie@264: }; jamie@264: jamie@264: void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { jamie@264: const std::string doubleDash = "--"; jamie@264: for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) jamie@264: parseIntoTokens( argv[i] , tokens); jamie@264: } jamie@264: void parseIntoTokens( std::string arg, std::vector& tokens ) const { jamie@264: while( !arg.empty() ) { jamie@264: Parser::Token token( Parser::Token::Positional, arg ); jamie@264: arg = ""; jamie@264: if( token.data[0] == '-' ) { jamie@264: if( token.data.size() > 1 && token.data[1] == '-' ) { jamie@264: token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); jamie@264: } jamie@264: else { jamie@264: token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); jamie@264: if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { jamie@264: arg = "-" + token.data.substr( 1 ); jamie@264: token.data = token.data.substr( 0, 1 ); jamie@264: } jamie@264: } jamie@264: } jamie@264: if( token.type != Parser::Token::Positional ) { jamie@264: std::size_t pos = token.data.find_first_of( separators ); jamie@264: if( pos != std::string::npos ) { jamie@264: arg = token.data.substr( pos+1 ); jamie@264: token.data = token.data.substr( 0, pos ); jamie@264: } jamie@264: } jamie@264: tokens.push_back( token ); jamie@264: } jamie@264: } jamie@264: std::string separators; jamie@264: }; jamie@264: jamie@264: template jamie@264: struct CommonArgProperties { jamie@264: CommonArgProperties() {} jamie@264: CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} jamie@264: jamie@264: Detail::BoundArgFunction boundField; jamie@264: std::string description; jamie@264: std::string detail; jamie@264: std::string placeholder; // Only value if boundField takes an arg jamie@264: jamie@264: bool takesArg() const { jamie@264: return !placeholder.empty(); jamie@264: } jamie@264: void validate() const { jamie@264: if( !boundField.isSet() ) jamie@264: throw std::logic_error( "option not bound" ); jamie@264: } jamie@264: }; jamie@264: struct OptionArgProperties { jamie@264: std::vector shortNames; jamie@264: std::string longName; jamie@264: jamie@264: bool hasShortName( std::string const& shortName ) const { jamie@264: return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); jamie@264: } jamie@264: bool hasLongName( std::string const& _longName ) const { jamie@264: return _longName == longName; jamie@264: } jamie@264: }; jamie@264: struct PositionalArgProperties { jamie@264: PositionalArgProperties() : position( -1 ) {} jamie@264: int position; // -1 means non-positional (floating) jamie@264: jamie@264: bool isFixedPositional() const { jamie@264: return position != -1; jamie@264: } jamie@264: }; jamie@264: jamie@264: template jamie@264: class CommandLine { jamie@264: jamie@264: struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { jamie@264: Arg() {} jamie@264: Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} jamie@264: jamie@264: using CommonArgProperties::placeholder; // !TBD jamie@264: jamie@264: std::string dbgName() const { jamie@264: if( !longName.empty() ) jamie@264: return "--" + longName; jamie@264: if( !shortNames.empty() ) jamie@264: return "-" + shortNames[0]; jamie@264: return "positional args"; jamie@264: } jamie@264: std::string commands() const { jamie@264: std::ostringstream oss; jamie@264: bool first = true; jamie@264: std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); jamie@264: for(; it != itEnd; ++it ) { jamie@264: if( first ) jamie@264: first = false; jamie@264: else jamie@264: oss << ", "; jamie@264: oss << "-" << *it; jamie@264: } jamie@264: if( !longName.empty() ) { jamie@264: if( !first ) jamie@264: oss << ", "; jamie@264: oss << "--" << longName; jamie@264: } jamie@264: if( !placeholder.empty() ) jamie@264: oss << " <" << placeholder << ">"; jamie@264: return oss.str(); jamie@264: } jamie@264: }; jamie@264: jamie@264: // NOTE: std::auto_ptr is deprecated in c++11/c++0x jamie@264: #if defined(__cplusplus) && __cplusplus > 199711L jamie@264: typedef std::unique_ptr ArgAutoPtr; jamie@264: #else jamie@264: typedef std::auto_ptr ArgAutoPtr; jamie@264: #endif jamie@264: jamie@264: friend void addOptName( Arg& arg, std::string const& optName ) jamie@264: { jamie@264: if( optName.empty() ) jamie@264: return; jamie@264: if( Detail::startsWith( optName, "--" ) ) { jamie@264: if( !arg.longName.empty() ) jamie@264: throw std::logic_error( "Only one long opt may be specified. '" jamie@264: + arg.longName jamie@264: + "' already specified, now attempting to add '" jamie@264: + optName + "'" ); jamie@264: arg.longName = optName.substr( 2 ); jamie@264: } jamie@264: else if( Detail::startsWith( optName, "-" ) ) jamie@264: arg.shortNames.push_back( optName.substr( 1 ) ); jamie@264: else jamie@264: throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); jamie@264: } jamie@264: friend void setPositionalArg( Arg& arg, int position ) jamie@264: { jamie@264: arg.position = position; jamie@264: } jamie@264: jamie@264: class ArgBuilder { jamie@264: public: jamie@264: ArgBuilder( Arg* arg ) : m_arg( arg ) {} jamie@264: jamie@264: // Bind a non-boolean data member (requires placeholder string) jamie@264: template jamie@264: void bind( M C::* field, std::string const& placeholder ) { jamie@264: m_arg->boundField = new Detail::BoundDataMember( field ); jamie@264: m_arg->placeholder = placeholder; jamie@264: } jamie@264: // Bind a boolean data member (no placeholder required) jamie@264: template jamie@264: void bind( bool C::* field ) { jamie@264: m_arg->boundField = new Detail::BoundDataMember( field ); jamie@264: } jamie@264: jamie@264: // Bind a method taking a single, non-boolean argument (requires a placeholder string) jamie@264: template jamie@264: void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { jamie@264: m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); jamie@264: m_arg->placeholder = placeholder; jamie@264: } jamie@264: jamie@264: // Bind a method taking a single, boolean argument (no placeholder string required) jamie@264: template jamie@264: void bind( void (C::* unaryMethod)( bool ) ) { jamie@264: m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); jamie@264: } jamie@264: jamie@264: // Bind a method that takes no arguments (will be called if opt is present) jamie@264: template jamie@264: void bind( void (C::* nullaryMethod)() ) { jamie@264: m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); jamie@264: } jamie@264: jamie@264: // Bind a free function taking a single argument - the object to operate on (no placeholder string required) jamie@264: template jamie@264: void bind( void (* unaryFunction)( C& ) ) { jamie@264: m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); jamie@264: } jamie@264: jamie@264: // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) jamie@264: template jamie@264: void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { jamie@264: m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); jamie@264: m_arg->placeholder = placeholder; jamie@264: } jamie@264: jamie@264: ArgBuilder& describe( std::string const& description ) { jamie@264: m_arg->description = description; jamie@264: return *this; jamie@264: } jamie@264: ArgBuilder& detail( std::string const& detail ) { jamie@264: m_arg->detail = detail; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: protected: jamie@264: Arg* m_arg; jamie@264: }; jamie@264: jamie@264: class OptBuilder : public ArgBuilder { jamie@264: public: jamie@264: OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} jamie@264: OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} jamie@264: jamie@264: OptBuilder& operator[]( std::string const& optName ) { jamie@264: addOptName( *ArgBuilder::m_arg, optName ); jamie@264: return *this; jamie@264: } jamie@264: }; jamie@264: jamie@264: public: jamie@264: jamie@264: CommandLine() jamie@264: : m_boundProcessName( new Detail::NullBinder() ), jamie@264: m_highestSpecifiedArgPosition( 0 ), jamie@264: m_throwOnUnrecognisedTokens( false ) jamie@264: {} jamie@264: CommandLine( CommandLine const& other ) jamie@264: : m_boundProcessName( other.m_boundProcessName ), jamie@264: m_options ( other.m_options ), jamie@264: m_positionalArgs( other.m_positionalArgs ), jamie@264: m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), jamie@264: m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) jamie@264: { jamie@264: if( other.m_floatingArg.get() ) jamie@264: m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) ); jamie@264: } jamie@264: jamie@264: CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { jamie@264: m_throwOnUnrecognisedTokens = shouldThrow; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: OptBuilder operator[]( std::string const& optName ) { jamie@264: m_options.push_back( Arg() ); jamie@264: addOptName( m_options.back(), optName ); jamie@264: OptBuilder builder( &m_options.back() ); jamie@264: return builder; jamie@264: } jamie@264: jamie@264: ArgBuilder operator[]( int position ) { jamie@264: m_positionalArgs.insert( std::make_pair( position, Arg() ) ); jamie@264: if( position > m_highestSpecifiedArgPosition ) jamie@264: m_highestSpecifiedArgPosition = position; jamie@264: setPositionalArg( m_positionalArgs[position], position ); jamie@264: ArgBuilder builder( &m_positionalArgs[position] ); jamie@264: return builder; jamie@264: } jamie@264: jamie@264: // Invoke this with the _ instance jamie@264: ArgBuilder operator[]( UnpositionalTag ) { jamie@264: if( m_floatingArg.get() ) jamie@264: throw std::logic_error( "Only one unpositional argument can be added" ); jamie@264: m_floatingArg = ArgAutoPtr( new Arg() ); jamie@264: ArgBuilder builder( m_floatingArg.get() ); jamie@264: return builder; jamie@264: } jamie@264: jamie@264: template jamie@264: void bindProcessName( M C::* field ) { jamie@264: m_boundProcessName = new Detail::BoundDataMember( field ); jamie@264: } jamie@264: template jamie@264: void bindProcessName( void (C::*_unaryMethod)( M ) ) { jamie@264: m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); jamie@264: } jamie@264: jamie@264: void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { jamie@264: typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; jamie@264: std::size_t maxWidth = 0; jamie@264: for( it = itBegin; it != itEnd; ++it ) jamie@264: maxWidth = (std::max)( maxWidth, it->commands().size() ); jamie@264: jamie@264: for( it = itBegin; it != itEnd; ++it ) { jamie@264: Detail::Text usage( it->commands(), Detail::TextAttributes() jamie@264: .setWidth( maxWidth+indent ) jamie@264: .setIndent( indent ) ); jamie@264: Detail::Text desc( it->description, Detail::TextAttributes() jamie@264: .setWidth( width - maxWidth - 3 ) ); jamie@264: jamie@264: for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { jamie@264: std::string usageCol = i < usage.size() ? usage[i] : ""; jamie@264: os << usageCol; jamie@264: jamie@264: if( i < desc.size() && !desc[i].empty() ) jamie@264: os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) jamie@264: << desc[i]; jamie@264: os << "\n"; jamie@264: } jamie@264: } jamie@264: } jamie@264: std::string optUsage() const { jamie@264: std::ostringstream oss; jamie@264: optUsage( oss ); jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: void argSynopsis( std::ostream& os ) const { jamie@264: for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { jamie@264: if( i > 1 ) jamie@264: os << " "; jamie@264: typename std::map::const_iterator it = m_positionalArgs.find( i ); jamie@264: if( it != m_positionalArgs.end() ) jamie@264: os << "<" << it->second.placeholder << ">"; jamie@264: else if( m_floatingArg.get() ) jamie@264: os << "<" << m_floatingArg->placeholder << ">"; jamie@264: else jamie@264: throw std::logic_error( "non consecutive positional arguments with no floating args" ); jamie@264: } jamie@264: // !TBD No indication of mandatory args jamie@264: if( m_floatingArg.get() ) { jamie@264: if( m_highestSpecifiedArgPosition > 1 ) jamie@264: os << " "; jamie@264: os << "[<" << m_floatingArg->placeholder << "> ...]"; jamie@264: } jamie@264: } jamie@264: std::string argSynopsis() const { jamie@264: std::ostringstream oss; jamie@264: argSynopsis( oss ); jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: void usage( std::ostream& os, std::string const& procName ) const { jamie@264: validate(); jamie@264: os << "usage:\n " << procName << " "; jamie@264: argSynopsis( os ); jamie@264: if( !m_options.empty() ) { jamie@264: os << " [options]\n\nwhere options are: \n"; jamie@264: optUsage( os, 2 ); jamie@264: } jamie@264: os << "\n"; jamie@264: } jamie@264: std::string usage( std::string const& procName ) const { jamie@264: std::ostringstream oss; jamie@264: usage( oss, procName ); jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: ConfigT parse( int argc, char const * const * argv ) const { jamie@264: ConfigT config; jamie@264: parseInto( argc, argv, config ); jamie@264: return config; jamie@264: } jamie@264: jamie@264: std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { jamie@264: std::string processName = argv[0]; jamie@264: std::size_t lastSlash = processName.find_last_of( "/\\" ); jamie@264: if( lastSlash != std::string::npos ) jamie@264: processName = processName.substr( lastSlash+1 ); jamie@264: m_boundProcessName.set( config, processName ); jamie@264: std::vector tokens; jamie@264: Parser parser; jamie@264: parser.parseIntoTokens( argc, argv, tokens ); jamie@264: return populate( tokens, config ); jamie@264: } jamie@264: jamie@264: std::vector populate( std::vector const& tokens, ConfigT& config ) const { jamie@264: validate(); jamie@264: std::vector unusedTokens = populateOptions( tokens, config ); jamie@264: unusedTokens = populateFixedArgs( unusedTokens, config ); jamie@264: unusedTokens = populateFloatingArgs( unusedTokens, config ); jamie@264: return unusedTokens; jamie@264: } jamie@264: jamie@264: std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { jamie@264: std::vector unusedTokens; jamie@264: std::vector errors; jamie@264: for( std::size_t i = 0; i < tokens.size(); ++i ) { jamie@264: Parser::Token const& token = tokens[i]; jamie@264: typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); jamie@264: for(; it != itEnd; ++it ) { jamie@264: Arg const& arg = *it; jamie@264: jamie@264: try { jamie@264: if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || jamie@264: ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { jamie@264: if( arg.takesArg() ) { jamie@264: if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) jamie@264: errors.push_back( "Expected argument to option: " + token.data ); jamie@264: else jamie@264: arg.boundField.set( config, tokens[++i].data ); jamie@264: } jamie@264: else { jamie@264: arg.boundField.setFlag( config ); jamie@264: } jamie@264: break; jamie@264: } jamie@264: } jamie@264: catch( std::exception& ex ) { jamie@264: errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); jamie@264: } jamie@264: } jamie@264: if( it == itEnd ) { jamie@264: if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) jamie@264: unusedTokens.push_back( token ); jamie@264: else if( m_throwOnUnrecognisedTokens ) jamie@264: errors.push_back( "unrecognised option: " + token.data ); jamie@264: } jamie@264: } jamie@264: if( !errors.empty() ) { jamie@264: std::ostringstream oss; jamie@264: for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: if( it != errors.begin() ) jamie@264: oss << "\n"; jamie@264: oss << *it; jamie@264: } jamie@264: throw std::runtime_error( oss.str() ); jamie@264: } jamie@264: return unusedTokens; jamie@264: } jamie@264: std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { jamie@264: std::vector unusedTokens; jamie@264: int position = 1; jamie@264: for( std::size_t i = 0; i < tokens.size(); ++i ) { jamie@264: Parser::Token const& token = tokens[i]; jamie@264: typename std::map::const_iterator it = m_positionalArgs.find( position ); jamie@264: if( it != m_positionalArgs.end() ) jamie@264: it->second.boundField.set( config, token.data ); jamie@264: else jamie@264: unusedTokens.push_back( token ); jamie@264: if( token.type == Parser::Token::Positional ) jamie@264: position++; jamie@264: } jamie@264: return unusedTokens; jamie@264: } jamie@264: std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { jamie@264: if( !m_floatingArg.get() ) jamie@264: return tokens; jamie@264: std::vector unusedTokens; jamie@264: for( std::size_t i = 0; i < tokens.size(); ++i ) { jamie@264: Parser::Token const& token = tokens[i]; jamie@264: if( token.type == Parser::Token::Positional ) jamie@264: m_floatingArg->boundField.set( config, token.data ); jamie@264: else jamie@264: unusedTokens.push_back( token ); jamie@264: } jamie@264: return unusedTokens; jamie@264: } jamie@264: jamie@264: void validate() const jamie@264: { jamie@264: if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) jamie@264: throw std::logic_error( "No options or arguments specified" ); jamie@264: jamie@264: for( typename std::vector::const_iterator it = m_options.begin(), jamie@264: itEnd = m_options.end(); jamie@264: it != itEnd; ++it ) jamie@264: it->validate(); jamie@264: } jamie@264: jamie@264: private: jamie@264: Detail::BoundArgFunction m_boundProcessName; jamie@264: std::vector m_options; jamie@264: std::map m_positionalArgs; jamie@264: ArgAutoPtr m_floatingArg; jamie@264: int m_highestSpecifiedArgPosition; jamie@264: bool m_throwOnUnrecognisedTokens; jamie@264: }; jamie@264: jamie@264: } // end namespace Clara jamie@264: jamie@264: STITCH_CLARA_CLOSE_NAMESPACE jamie@264: #undef STITCH_CLARA_OPEN_NAMESPACE jamie@264: #undef STITCH_CLARA_CLOSE_NAMESPACE jamie@264: jamie@264: #endif // TWOBLUECUBES_CLARA_H_INCLUDED jamie@264: #undef STITCH_CLARA_OPEN_NAMESPACE jamie@264: jamie@264: // Restore Clara's value for console width, if present jamie@264: #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH jamie@264: #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH jamie@264: #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH jamie@264: #endif jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } jamie@264: inline void abortAfterX( ConfigData& config, int x ) { jamie@264: if( x < 1 ) jamie@264: throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); jamie@264: config.abortAfter = x; jamie@264: } jamie@264: inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } jamie@264: jamie@264: inline void addWarning( ConfigData& config, std::string const& _warning ) { jamie@264: if( _warning == "NoAssertions" ) jamie@264: config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); jamie@264: else jamie@264: throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); jamie@264: jamie@264: } jamie@264: inline void setVerbosity( ConfigData& config, int level ) { jamie@264: // !TBD: accept strings? jamie@264: config.verbosity = static_cast( level ); jamie@264: } jamie@264: inline void setShowDurations( ConfigData& config, bool _showDurations ) { jamie@264: config.showDurations = _showDurations jamie@264: ? ShowDurations::Always jamie@264: : ShowDurations::Never; jamie@264: } jamie@264: inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { jamie@264: std::ifstream f( _filename.c_str() ); jamie@264: if( !f.is_open() ) jamie@264: throw std::domain_error( "Unable to load input file: " + _filename ); jamie@264: jamie@264: std::string line; jamie@264: while( std::getline( f, line ) ) { jamie@264: line = trim(line); jamie@264: if( !line.empty() && !startsWith( line, "#" ) ) jamie@264: addTestOrTags( config, "\"" + line + "\"," ); jamie@264: } jamie@264: } jamie@264: jamie@264: inline Clara::CommandLine makeCommandLineParser() { jamie@264: jamie@264: using namespace Clara; jamie@264: CommandLine cli; jamie@264: jamie@264: cli.bindProcessName( &ConfigData::processName ); jamie@264: jamie@264: cli["-?"]["-h"]["--help"] jamie@264: .describe( "display usage information" ) jamie@264: .bind( &ConfigData::showHelp ); jamie@264: jamie@264: cli["-l"]["--list-tests"] jamie@264: .describe( "list all/matching test cases" ) jamie@264: .bind( &ConfigData::listTests ); jamie@264: jamie@264: cli["-t"]["--list-tags"] jamie@264: .describe( "list all/matching tags" ) jamie@264: .bind( &ConfigData::listTags ); jamie@264: jamie@264: cli["-s"]["--success"] jamie@264: .describe( "include successful tests in output" ) jamie@264: .bind( &ConfigData::showSuccessfulTests ); jamie@264: jamie@264: cli["-b"]["--break"] jamie@264: .describe( "break into debugger on failure" ) jamie@264: .bind( &ConfigData::shouldDebugBreak ); jamie@264: jamie@264: cli["-e"]["--nothrow"] jamie@264: .describe( "skip exception tests" ) jamie@264: .bind( &ConfigData::noThrow ); jamie@264: jamie@264: cli["-i"]["--invisibles"] jamie@264: .describe( "show invisibles (tabs, newlines)" ) jamie@264: .bind( &ConfigData::showInvisibles ); jamie@264: jamie@264: cli["-o"]["--out"] jamie@264: .describe( "output filename" ) jamie@264: .bind( &ConfigData::outputFilename, "filename" ); jamie@264: jamie@264: cli["-r"]["--reporter"] jamie@264: // .placeholder( "name[:filename]" ) jamie@264: .describe( "reporter to use (defaults to console)" ) jamie@264: .bind( &ConfigData::reporterName, "name" ); jamie@264: jamie@264: cli["-n"]["--name"] jamie@264: .describe( "suite name" ) jamie@264: .bind( &ConfigData::name, "name" ); jamie@264: jamie@264: cli["-a"]["--abort"] jamie@264: .describe( "abort at first failure" ) jamie@264: .bind( &abortAfterFirst ); jamie@264: jamie@264: cli["-x"]["--abortx"] jamie@264: .describe( "abort after x failures" ) jamie@264: .bind( &abortAfterX, "no. failures" ); jamie@264: jamie@264: cli["-w"]["--warn"] jamie@264: .describe( "enable warnings" ) jamie@264: .bind( &addWarning, "warning name" ); jamie@264: jamie@264: // - needs updating if reinstated jamie@264: // cli.into( &setVerbosity ) jamie@264: // .describe( "level of verbosity (0=no output)" ) jamie@264: // .shortOpt( "v") jamie@264: // .longOpt( "verbosity" ) jamie@264: // .placeholder( "level" ); jamie@264: jamie@264: cli[_] jamie@264: .describe( "which test or tests to use" ) jamie@264: .bind( &addTestOrTags, "test name, pattern or tags" ); jamie@264: jamie@264: cli["-d"]["--durations"] jamie@264: .describe( "show test durations" ) jamie@264: .bind( &setShowDurations, "yes/no" ); jamie@264: jamie@264: cli["-f"]["--input-file"] jamie@264: .describe( "load test names to run from a file" ) jamie@264: .bind( &loadTestNamesFromFile, "filename" ); jamie@264: jamie@264: // Less common commands which don't have a short form jamie@264: cli["--list-test-names-only"] jamie@264: .describe( "list all/matching test cases names only" ) jamie@264: .bind( &ConfigData::listTestNamesOnly ); jamie@264: jamie@264: cli["--list-reporters"] jamie@264: .describe( "list all reporters" ) jamie@264: .bind( &ConfigData::listReporters ); jamie@264: jamie@264: return cli; jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: internal/catch_list.hpp jamie@264: #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_text.h jamie@264: #define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED jamie@264: jamie@264: #define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH jamie@264: jamie@264: #define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch jamie@264: // #included from: ../external/tbc_text_format.h jamie@264: // Only use header guard if we are not using an outer namespace jamie@264: #ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE jamie@264: # ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED jamie@264: # ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED jamie@264: # define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED jamie@264: # endif jamie@264: # else jamie@264: # define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED jamie@264: # endif jamie@264: #endif jamie@264: #ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: // Use optional outer namespace jamie@264: #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE jamie@264: namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { jamie@264: #endif jamie@264: jamie@264: namespace Tbc { jamie@264: jamie@264: #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH jamie@264: const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; jamie@264: #else jamie@264: const unsigned int consoleWidth = 80; jamie@264: #endif jamie@264: jamie@264: struct TextAttributes { jamie@264: TextAttributes() jamie@264: : initialIndent( std::string::npos ), jamie@264: indent( 0 ), jamie@264: width( consoleWidth-1 ), jamie@264: tabChar( '\t' ) jamie@264: {} jamie@264: jamie@264: TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } jamie@264: TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } jamie@264: TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } jamie@264: TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } jamie@264: jamie@264: std::size_t initialIndent; // indent of first line, or npos jamie@264: std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos jamie@264: std::size_t width; // maximum width of text, including indent. Longer text will wrap jamie@264: char tabChar; // If this char is seen the indent is changed to current pos jamie@264: }; jamie@264: jamie@264: class Text { jamie@264: public: jamie@264: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) jamie@264: : attr( _attr ) jamie@264: { jamie@264: std::string wrappableChars = " [({.,/|\\-"; jamie@264: std::size_t indent = _attr.initialIndent != std::string::npos jamie@264: ? _attr.initialIndent jamie@264: : _attr.indent; jamie@264: std::string remainder = _str; jamie@264: jamie@264: while( !remainder.empty() ) { jamie@264: if( lines.size() >= 1000 ) { jamie@264: lines.push_back( "... message truncated due to excessive size" ); jamie@264: return; jamie@264: } jamie@264: std::size_t tabPos = std::string::npos; jamie@264: std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); jamie@264: std::size_t pos = remainder.find_first_of( '\n' ); jamie@264: if( pos <= width ) { jamie@264: width = pos; jamie@264: } jamie@264: pos = remainder.find_last_of( _attr.tabChar, width ); jamie@264: if( pos != std::string::npos ) { jamie@264: tabPos = pos; jamie@264: if( remainder[width] == '\n' ) jamie@264: width--; jamie@264: remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); jamie@264: } jamie@264: jamie@264: if( width == remainder.size() ) { jamie@264: spliceLine( indent, remainder, width ); jamie@264: } jamie@264: else if( remainder[width] == '\n' ) { jamie@264: spliceLine( indent, remainder, width ); jamie@264: if( width <= 1 || remainder.size() != 1 ) jamie@264: remainder = remainder.substr( 1 ); jamie@264: indent = _attr.indent; jamie@264: } jamie@264: else { jamie@264: pos = remainder.find_last_of( wrappableChars, width ); jamie@264: if( pos != std::string::npos && pos > 0 ) { jamie@264: spliceLine( indent, remainder, pos ); jamie@264: if( remainder[0] == ' ' ) jamie@264: remainder = remainder.substr( 1 ); jamie@264: } jamie@264: else { jamie@264: spliceLine( indent, remainder, width-1 ); jamie@264: lines.back() += "-"; jamie@264: } jamie@264: if( lines.size() == 1 ) jamie@264: indent = _attr.indent; jamie@264: if( tabPos != std::string::npos ) jamie@264: indent += tabPos; jamie@264: } jamie@264: } jamie@264: } jamie@264: jamie@264: void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { jamie@264: lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); jamie@264: _remainder = _remainder.substr( _pos ); jamie@264: } jamie@264: jamie@264: typedef std::vector::const_iterator const_iterator; jamie@264: jamie@264: const_iterator begin() const { return lines.begin(); } jamie@264: const_iterator end() const { return lines.end(); } jamie@264: std::string const& last() const { return lines.back(); } jamie@264: std::size_t size() const { return lines.size(); } jamie@264: std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } jamie@264: std::string toString() const { jamie@264: std::ostringstream oss; jamie@264: oss << *this; jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { jamie@264: for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); jamie@264: it != itEnd; ++it ) { jamie@264: if( it != _text.begin() ) jamie@264: _stream << "\n"; jamie@264: _stream << *it; jamie@264: } jamie@264: return _stream; jamie@264: } jamie@264: jamie@264: private: jamie@264: std::string str; jamie@264: TextAttributes attr; jamie@264: std::vector lines; jamie@264: }; jamie@264: jamie@264: } // end namespace Tbc jamie@264: jamie@264: #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE jamie@264: } // end outer namespace jamie@264: #endif jamie@264: jamie@264: #endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED jamie@264: #undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE jamie@264: jamie@264: namespace Catch { jamie@264: using Tbc::Text; jamie@264: using Tbc::TextAttributes; jamie@264: } jamie@264: jamie@264: // #included from: catch_console_colour.hpp jamie@264: #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: namespace Detail { jamie@264: struct IColourImpl; jamie@264: } jamie@264: jamie@264: struct Colour { jamie@264: enum Code { jamie@264: None = 0, jamie@264: jamie@264: White, jamie@264: Red, jamie@264: Green, jamie@264: Blue, jamie@264: Cyan, jamie@264: Yellow, jamie@264: Grey, jamie@264: jamie@264: Bright = 0x10, jamie@264: jamie@264: BrightRed = Bright | Red, jamie@264: BrightGreen = Bright | Green, jamie@264: LightGrey = Bright | Grey, jamie@264: BrightWhite = Bright | White, jamie@264: jamie@264: // By intention jamie@264: FileName = LightGrey, jamie@264: Warning = Yellow, jamie@264: ResultError = BrightRed, jamie@264: ResultSuccess = BrightGreen, jamie@264: ResultExpectedFailure = Warning, jamie@264: jamie@264: Error = BrightRed, jamie@264: Success = Green, jamie@264: jamie@264: OriginalExpression = Cyan, jamie@264: ReconstructedExpression = Yellow, jamie@264: jamie@264: SecondaryText = LightGrey, jamie@264: Headers = White jamie@264: }; jamie@264: jamie@264: // Use constructed object for RAII guard jamie@264: Colour( Code _colourCode ); jamie@264: Colour( Colour const& other ); jamie@264: ~Colour(); jamie@264: jamie@264: // Use static method for one-shot changes jamie@264: static void use( Code _colourCode ); jamie@264: jamie@264: private: jamie@264: static Detail::IColourImpl* impl(); jamie@264: bool m_moved; jamie@264: }; jamie@264: jamie@264: inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_interfaces_reporter.h jamie@264: #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch jamie@264: { jamie@264: struct ReporterConfig { jamie@264: explicit ReporterConfig( Ptr const& _fullConfig ) jamie@264: : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} jamie@264: jamie@264: ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) jamie@264: : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} jamie@264: jamie@264: std::ostream& stream() const { return *m_stream; } jamie@264: Ptr fullConfig() const { return m_fullConfig; } jamie@264: jamie@264: private: jamie@264: std::ostream* m_stream; jamie@264: Ptr m_fullConfig; jamie@264: }; jamie@264: jamie@264: struct ReporterPreferences { jamie@264: ReporterPreferences() jamie@264: : shouldRedirectStdOut( false ) jamie@264: {} jamie@264: jamie@264: bool shouldRedirectStdOut; jamie@264: }; jamie@264: jamie@264: template jamie@264: struct LazyStat : Option { jamie@264: LazyStat() : used( false ) {} jamie@264: LazyStat& operator=( T const& _value ) { jamie@264: Option::operator=( _value ); jamie@264: used = false; jamie@264: return *this; jamie@264: } jamie@264: void reset() { jamie@264: Option::reset(); jamie@264: used = false; jamie@264: } jamie@264: bool used; jamie@264: }; jamie@264: jamie@264: struct TestRunInfo { jamie@264: TestRunInfo( std::string const& _name ) : name( _name ) {} jamie@264: std::string name; jamie@264: }; jamie@264: struct GroupInfo { jamie@264: GroupInfo( std::string const& _name, jamie@264: std::size_t _groupIndex, jamie@264: std::size_t _groupsCount ) jamie@264: : name( _name ), jamie@264: groupIndex( _groupIndex ), jamie@264: groupsCounts( _groupsCount ) jamie@264: {} jamie@264: jamie@264: std::string name; jamie@264: std::size_t groupIndex; jamie@264: std::size_t groupsCounts; jamie@264: }; jamie@264: jamie@264: struct AssertionStats { jamie@264: AssertionStats( AssertionResult const& _assertionResult, jamie@264: std::vector const& _infoMessages, jamie@264: Totals const& _totals ) jamie@264: : assertionResult( _assertionResult ), jamie@264: infoMessages( _infoMessages ), jamie@264: totals( _totals ) jamie@264: { jamie@264: if( assertionResult.hasMessage() ) { jamie@264: // Copy message into messages list. jamie@264: // !TBD This should have been done earlier, somewhere jamie@264: MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); jamie@264: builder << assertionResult.getMessage(); jamie@264: builder.m_info.message = builder.m_stream.str(); jamie@264: jamie@264: infoMessages.push_back( builder.m_info ); jamie@264: } jamie@264: } jamie@264: virtual ~AssertionStats(); jamie@264: jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: AssertionStats( AssertionStats const& ) = default; jamie@264: AssertionStats( AssertionStats && ) = default; jamie@264: AssertionStats& operator = ( AssertionStats const& ) = default; jamie@264: AssertionStats& operator = ( AssertionStats && ) = default; jamie@264: # endif jamie@264: jamie@264: AssertionResult assertionResult; jamie@264: std::vector infoMessages; jamie@264: Totals totals; jamie@264: }; jamie@264: jamie@264: struct SectionStats { jamie@264: SectionStats( SectionInfo const& _sectionInfo, jamie@264: Counts const& _assertions, jamie@264: double _durationInSeconds, jamie@264: bool _missingAssertions ) jamie@264: : sectionInfo( _sectionInfo ), jamie@264: assertions( _assertions ), jamie@264: durationInSeconds( _durationInSeconds ), jamie@264: missingAssertions( _missingAssertions ) jamie@264: {} jamie@264: virtual ~SectionStats(); jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: SectionStats( SectionStats const& ) = default; jamie@264: SectionStats( SectionStats && ) = default; jamie@264: SectionStats& operator = ( SectionStats const& ) = default; jamie@264: SectionStats& operator = ( SectionStats && ) = default; jamie@264: # endif jamie@264: jamie@264: SectionInfo sectionInfo; jamie@264: Counts assertions; jamie@264: double durationInSeconds; jamie@264: bool missingAssertions; jamie@264: }; jamie@264: jamie@264: struct TestCaseStats { jamie@264: TestCaseStats( TestCaseInfo const& _testInfo, jamie@264: Totals const& _totals, jamie@264: std::string const& _stdOut, jamie@264: std::string const& _stdErr, jamie@264: bool _aborting ) jamie@264: : testInfo( _testInfo ), jamie@264: totals( _totals ), jamie@264: stdOut( _stdOut ), jamie@264: stdErr( _stdErr ), jamie@264: aborting( _aborting ) jamie@264: {} jamie@264: virtual ~TestCaseStats(); jamie@264: jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: TestCaseStats( TestCaseStats const& ) = default; jamie@264: TestCaseStats( TestCaseStats && ) = default; jamie@264: TestCaseStats& operator = ( TestCaseStats const& ) = default; jamie@264: TestCaseStats& operator = ( TestCaseStats && ) = default; jamie@264: # endif jamie@264: jamie@264: TestCaseInfo testInfo; jamie@264: Totals totals; jamie@264: std::string stdOut; jamie@264: std::string stdErr; jamie@264: bool aborting; jamie@264: }; jamie@264: jamie@264: struct TestGroupStats { jamie@264: TestGroupStats( GroupInfo const& _groupInfo, jamie@264: Totals const& _totals, jamie@264: bool _aborting ) jamie@264: : groupInfo( _groupInfo ), jamie@264: totals( _totals ), jamie@264: aborting( _aborting ) jamie@264: {} jamie@264: TestGroupStats( GroupInfo const& _groupInfo ) jamie@264: : groupInfo( _groupInfo ), jamie@264: aborting( false ) jamie@264: {} jamie@264: virtual ~TestGroupStats(); jamie@264: jamie@264: # ifdef CATCH_CPP11_OR_GREATER jamie@264: TestGroupStats( TestGroupStats const& ) = default; jamie@264: TestGroupStats( TestGroupStats && ) = default; jamie@264: TestGroupStats& operator = ( TestGroupStats const& ) = default; jamie@264: TestGroupStats& operator = ( TestGroupStats && ) = default; jamie@264: # endif jamie@264: jamie@264: GroupInfo groupInfo; jamie@264: Totals totals; jamie@264: bool aborting; jamie@264: }; jamie@264: jamie@264: struct TestRunStats { jamie@264: TestRunStats( TestRunInfo const& _runInfo, jamie@264: Totals const& _totals, jamie@264: bool _aborting ) jamie@264: : runInfo( _runInfo ), jamie@264: totals( _totals ), jamie@264: aborting( _aborting ) jamie@264: {} jamie@264: virtual ~TestRunStats(); jamie@264: jamie@264: # ifndef CATCH_CPP11_OR_GREATER jamie@264: TestRunStats( TestRunStats const& _other ) jamie@264: : runInfo( _other.runInfo ), jamie@264: totals( _other.totals ), jamie@264: aborting( _other.aborting ) jamie@264: {} jamie@264: # else jamie@264: TestRunStats( TestRunStats const& ) = default; jamie@264: TestRunStats( TestRunStats && ) = default; jamie@264: TestRunStats& operator = ( TestRunStats const& ) = default; jamie@264: TestRunStats& operator = ( TestRunStats && ) = default; jamie@264: # endif jamie@264: jamie@264: TestRunInfo runInfo; jamie@264: Totals totals; jamie@264: bool aborting; jamie@264: }; jamie@264: jamie@264: struct IStreamingReporter : IShared { jamie@264: virtual ~IStreamingReporter(); jamie@264: jamie@264: // Implementing class must also provide the following static method: jamie@264: // static std::string getDescription(); jamie@264: jamie@264: virtual ReporterPreferences getPreferences() const = 0; jamie@264: jamie@264: virtual void noMatchingTestCases( std::string const& spec ) = 0; jamie@264: jamie@264: virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; jamie@264: virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; jamie@264: jamie@264: virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; jamie@264: virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; jamie@264: jamie@264: virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; jamie@264: jamie@264: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; jamie@264: virtual void sectionEnded( SectionStats const& sectionStats ) = 0; jamie@264: virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; jamie@264: virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; jamie@264: virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; jamie@264: }; jamie@264: jamie@264: struct IReporterFactory { jamie@264: virtual ~IReporterFactory(); jamie@264: virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; jamie@264: virtual std::string getDescription() const = 0; jamie@264: }; jamie@264: jamie@264: struct IReporterRegistry { jamie@264: typedef std::map FactoryMap; jamie@264: jamie@264: virtual ~IReporterRegistry(); jamie@264: virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; jamie@264: virtual FactoryMap const& getFactories() const = 0; jamie@264: }; jamie@264: jamie@264: } jamie@264: jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: inline std::size_t listTests( Config const& config ) { jamie@264: jamie@264: TestSpec testSpec = config.testSpec(); jamie@264: if( config.testSpec().hasFilters() ) jamie@264: std::cout << "Matching test cases:\n"; jamie@264: else { jamie@264: std::cout << "All available test cases:\n"; jamie@264: testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); jamie@264: } jamie@264: jamie@264: std::size_t matchedTests = 0; jamie@264: TextAttributes nameAttr, tagsAttr; jamie@264: nameAttr.setInitialIndent( 2 ).setIndent( 4 ); jamie@264: tagsAttr.setIndent( 6 ); jamie@264: jamie@264: std::vector matchedTestCases; jamie@264: getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); jamie@264: for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: matchedTests++; jamie@264: TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); jamie@264: Colour::Code colour = testCaseInfo.isHidden() jamie@264: ? Colour::SecondaryText jamie@264: : Colour::None; jamie@264: Colour colourGuard( colour ); jamie@264: jamie@264: std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl; jamie@264: if( !testCaseInfo.tags.empty() ) jamie@264: std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; jamie@264: } jamie@264: jamie@264: if( !config.testSpec().hasFilters() ) jamie@264: std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl; jamie@264: else jamie@264: std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; jamie@264: return matchedTests; jamie@264: } jamie@264: jamie@264: inline std::size_t listTestsNamesOnly( Config const& config ) { jamie@264: TestSpec testSpec = config.testSpec(); jamie@264: if( !config.testSpec().hasFilters() ) jamie@264: testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); jamie@264: std::size_t matchedTests = 0; jamie@264: std::vector matchedTestCases; jamie@264: getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); jamie@264: for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: matchedTests++; jamie@264: TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); jamie@264: std::cout << testCaseInfo.name << std::endl; jamie@264: } jamie@264: return matchedTests; jamie@264: } jamie@264: jamie@264: struct TagInfo { jamie@264: TagInfo() : count ( 0 ) {} jamie@264: void add( std::string const& spelling ) { jamie@264: ++count; jamie@264: spellings.insert( spelling ); jamie@264: } jamie@264: std::string all() const { jamie@264: std::string out; jamie@264: for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); jamie@264: it != itEnd; jamie@264: ++it ) jamie@264: out += "[" + *it + "]"; jamie@264: return out; jamie@264: } jamie@264: std::set spellings; jamie@264: std::size_t count; jamie@264: }; jamie@264: jamie@264: inline std::size_t listTags( Config const& config ) { jamie@264: TestSpec testSpec = config.testSpec(); jamie@264: if( config.testSpec().hasFilters() ) jamie@264: std::cout << "Tags for matching test cases:\n"; jamie@264: else { jamie@264: std::cout << "All available tags:\n"; jamie@264: testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); jamie@264: } jamie@264: jamie@264: std::map tagCounts; jamie@264: jamie@264: std::vector matchedTestCases; jamie@264: getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); jamie@264: for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), jamie@264: tagItEnd = it->getTestCaseInfo().tags.end(); jamie@264: tagIt != tagItEnd; jamie@264: ++tagIt ) { jamie@264: std::string tagName = *tagIt; jamie@264: std::string lcaseTagName = toLower( tagName ); jamie@264: std::map::iterator countIt = tagCounts.find( lcaseTagName ); jamie@264: if( countIt == tagCounts.end() ) jamie@264: countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; jamie@264: countIt->second.add( tagName ); jamie@264: } jamie@264: } jamie@264: jamie@264: for( std::map::const_iterator countIt = tagCounts.begin(), jamie@264: countItEnd = tagCounts.end(); jamie@264: countIt != countItEnd; jamie@264: ++countIt ) { jamie@264: std::ostringstream oss; jamie@264: oss << " " << std::setw(2) << countIt->second.count << " "; jamie@264: Text wrapper( countIt->second.all(), TextAttributes() jamie@264: .setInitialIndent( 0 ) jamie@264: .setIndent( oss.str().size() ) jamie@264: .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); jamie@264: std::cout << oss.str() << wrapper << "\n"; jamie@264: } jamie@264: std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; jamie@264: return tagCounts.size(); jamie@264: } jamie@264: jamie@264: inline std::size_t listReporters( Config const& /*config*/ ) { jamie@264: std::cout << "Available reports:\n"; jamie@264: IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); jamie@264: IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; jamie@264: std::size_t maxNameLen = 0; jamie@264: for(it = itBegin; it != itEnd; ++it ) jamie@264: maxNameLen = (std::max)( maxNameLen, it->first.size() ); jamie@264: jamie@264: for(it = itBegin; it != itEnd; ++it ) { jamie@264: Text wrapper( it->second->getDescription(), TextAttributes() jamie@264: .setInitialIndent( 0 ) jamie@264: .setIndent( 7+maxNameLen ) jamie@264: .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); jamie@264: std::cout << " " jamie@264: << it->first jamie@264: << ":" jamie@264: << std::string( maxNameLen - it->first.size() + 2, ' ' ) jamie@264: << wrapper << "\n"; jamie@264: } jamie@264: std::cout << std::endl; jamie@264: return factories.size(); jamie@264: } jamie@264: jamie@264: inline Option list( Config const& config ) { jamie@264: Option listedCount; jamie@264: if( config.listTests() ) jamie@264: listedCount = listedCount.valueOr(0) + listTests( config ); jamie@264: if( config.listTestNamesOnly() ) jamie@264: listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); jamie@264: if( config.listTags() ) jamie@264: listedCount = listedCount.valueOr(0) + listTags( config ); jamie@264: if( config.listReporters() ) jamie@264: listedCount = listedCount.valueOr(0) + listReporters( config ); jamie@264: return listedCount; jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: internal/catch_runner_impl.hpp jamie@264: #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_test_case_tracker.hpp jamie@264: #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: namespace SectionTracking { jamie@264: jamie@264: class TrackedSection { jamie@264: jamie@264: typedef std::map TrackedSections; jamie@264: jamie@264: public: jamie@264: enum RunState { jamie@264: NotStarted, jamie@264: Executing, jamie@264: ExecutingChildren, jamie@264: Completed jamie@264: }; jamie@264: jamie@264: TrackedSection( std::string const& name, TrackedSection* parent ) jamie@264: : m_name( name ), m_runState( NotStarted ), m_parent( parent ) jamie@264: {} jamie@264: jamie@264: RunState runState() const { return m_runState; } jamie@264: jamie@264: TrackedSection* findChild( std::string const& childName ) { jamie@264: TrackedSections::iterator it = m_children.find( childName ); jamie@264: return it != m_children.end() jamie@264: ? &it->second jamie@264: : NULL; jamie@264: } jamie@264: TrackedSection* acquireChild( std::string const& childName ) { jamie@264: if( TrackedSection* child = findChild( childName ) ) jamie@264: return child; jamie@264: m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); jamie@264: return findChild( childName ); jamie@264: } jamie@264: void enter() { jamie@264: if( m_runState == NotStarted ) jamie@264: m_runState = Executing; jamie@264: } jamie@264: void leave() { jamie@264: for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); jamie@264: it != itEnd; jamie@264: ++it ) jamie@264: if( it->second.runState() != Completed ) { jamie@264: m_runState = ExecutingChildren; jamie@264: return; jamie@264: } jamie@264: m_runState = Completed; jamie@264: } jamie@264: TrackedSection* getParent() { jamie@264: return m_parent; jamie@264: } jamie@264: bool hasChildren() const { jamie@264: return !m_children.empty(); jamie@264: } jamie@264: jamie@264: private: jamie@264: std::string m_name; jamie@264: RunState m_runState; jamie@264: TrackedSections m_children; jamie@264: TrackedSection* m_parent; jamie@264: jamie@264: }; jamie@264: jamie@264: class TestCaseTracker { jamie@264: public: jamie@264: TestCaseTracker( std::string const& testCaseName ) jamie@264: : m_testCase( testCaseName, NULL ), jamie@264: m_currentSection( &m_testCase ), jamie@264: m_completedASectionThisRun( false ) jamie@264: {} jamie@264: jamie@264: bool enterSection( std::string const& name ) { jamie@264: TrackedSection* child = m_currentSection->acquireChild( name ); jamie@264: if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) jamie@264: return false; jamie@264: jamie@264: m_currentSection = child; jamie@264: m_currentSection->enter(); jamie@264: return true; jamie@264: } jamie@264: void leaveSection() { jamie@264: m_currentSection->leave(); jamie@264: m_currentSection = m_currentSection->getParent(); jamie@264: assert( m_currentSection != NULL ); jamie@264: m_completedASectionThisRun = true; jamie@264: } jamie@264: jamie@264: bool currentSectionHasChildren() const { jamie@264: return m_currentSection->hasChildren(); jamie@264: } jamie@264: bool isCompleted() const { jamie@264: return m_testCase.runState() == TrackedSection::Completed; jamie@264: } jamie@264: jamie@264: class Guard { jamie@264: public: jamie@264: Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { jamie@264: m_tracker.enterTestCase(); jamie@264: } jamie@264: ~Guard() { jamie@264: m_tracker.leaveTestCase(); jamie@264: } jamie@264: private: jamie@264: Guard( Guard const& ); jamie@264: void operator = ( Guard const& ); jamie@264: TestCaseTracker& m_tracker; jamie@264: }; jamie@264: jamie@264: private: jamie@264: void enterTestCase() { jamie@264: m_currentSection = &m_testCase; jamie@264: m_completedASectionThisRun = false; jamie@264: m_testCase.enter(); jamie@264: } jamie@264: void leaveTestCase() { jamie@264: m_testCase.leave(); jamie@264: } jamie@264: jamie@264: TrackedSection m_testCase; jamie@264: TrackedSection* m_currentSection; jamie@264: bool m_completedASectionThisRun; jamie@264: }; jamie@264: jamie@264: } // namespace SectionTracking jamie@264: jamie@264: using SectionTracking::TestCaseTracker; jamie@264: jamie@264: } // namespace Catch jamie@264: jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class StreamRedirect { jamie@264: jamie@264: public: jamie@264: StreamRedirect( std::ostream& stream, std::string& targetString ) jamie@264: : m_stream( stream ), jamie@264: m_prevBuf( stream.rdbuf() ), jamie@264: m_targetString( targetString ) jamie@264: { jamie@264: stream.rdbuf( m_oss.rdbuf() ); jamie@264: } jamie@264: jamie@264: ~StreamRedirect() { jamie@264: m_targetString += m_oss.str(); jamie@264: m_stream.rdbuf( m_prevBuf ); jamie@264: } jamie@264: jamie@264: private: jamie@264: std::ostream& m_stream; jamie@264: std::streambuf* m_prevBuf; jamie@264: std::ostringstream m_oss; jamie@264: std::string& m_targetString; jamie@264: }; jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////// jamie@264: jamie@264: class RunContext : public IResultCapture, public IRunner { jamie@264: jamie@264: RunContext( RunContext const& ); jamie@264: void operator =( RunContext const& ); jamie@264: jamie@264: public: jamie@264: jamie@264: explicit RunContext( Ptr const& config, Ptr const& reporter ) jamie@264: : m_runInfo( config->name() ), jamie@264: m_context( getCurrentMutableContext() ), jamie@264: m_activeTestCase( NULL ), jamie@264: m_config( config ), jamie@264: m_reporter( reporter ), jamie@264: m_prevRunner( m_context.getRunner() ), jamie@264: m_prevResultCapture( m_context.getResultCapture() ), jamie@264: m_prevConfig( m_context.getConfig() ) jamie@264: { jamie@264: m_context.setRunner( this ); jamie@264: m_context.setConfig( m_config ); jamie@264: m_context.setResultCapture( this ); jamie@264: m_reporter->testRunStarting( m_runInfo ); jamie@264: } jamie@264: jamie@264: virtual ~RunContext() { jamie@264: m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); jamie@264: m_context.setRunner( m_prevRunner ); jamie@264: m_context.setConfig( NULL ); jamie@264: m_context.setResultCapture( m_prevResultCapture ); jamie@264: m_context.setConfig( m_prevConfig ); jamie@264: } jamie@264: jamie@264: void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { jamie@264: m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); jamie@264: } jamie@264: void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { jamie@264: m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); jamie@264: } jamie@264: jamie@264: Totals runTest( TestCase const& testCase ) { jamie@264: Totals prevTotals = m_totals; jamie@264: jamie@264: std::string redirectedCout; jamie@264: std::string redirectedCerr; jamie@264: jamie@264: TestCaseInfo testInfo = testCase.getTestCaseInfo(); jamie@264: jamie@264: m_reporter->testCaseStarting( testInfo ); jamie@264: jamie@264: m_activeTestCase = &testCase; jamie@264: m_testCaseTracker = TestCaseTracker( testInfo.name ); jamie@264: jamie@264: do { jamie@264: do { jamie@264: runCurrentTest( redirectedCout, redirectedCerr ); jamie@264: } jamie@264: while( !m_testCaseTracker->isCompleted() && !aborting() ); jamie@264: } jamie@264: while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); jamie@264: jamie@264: Totals deltaTotals = m_totals.delta( prevTotals ); jamie@264: m_totals.testCases += deltaTotals.testCases; jamie@264: m_reporter->testCaseEnded( TestCaseStats( testInfo, jamie@264: deltaTotals, jamie@264: redirectedCout, jamie@264: redirectedCerr, jamie@264: aborting() ) ); jamie@264: jamie@264: m_activeTestCase = NULL; jamie@264: m_testCaseTracker.reset(); jamie@264: jamie@264: return deltaTotals; jamie@264: } jamie@264: jamie@264: Ptr config() const { jamie@264: return m_config; jamie@264: } jamie@264: jamie@264: private: // IResultCapture jamie@264: jamie@264: virtual void assertionEnded( AssertionResult const& result ) { jamie@264: if( result.getResultType() == ResultWas::Ok ) { jamie@264: m_totals.assertions.passed++; jamie@264: } jamie@264: else if( !result.isOk() ) { jamie@264: m_totals.assertions.failed++; jamie@264: } jamie@264: jamie@264: if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) jamie@264: m_messages.clear(); jamie@264: jamie@264: // Reset working state jamie@264: m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); jamie@264: m_lastResult = result; jamie@264: } jamie@264: jamie@264: virtual bool sectionStarted ( jamie@264: SectionInfo const& sectionInfo, jamie@264: Counts& assertions jamie@264: ) jamie@264: { jamie@264: std::ostringstream oss; jamie@264: oss << sectionInfo.name << "@" << sectionInfo.lineInfo; jamie@264: jamie@264: if( !m_testCaseTracker->enterSection( oss.str() ) ) jamie@264: return false; jamie@264: jamie@264: m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; jamie@264: jamie@264: m_reporter->sectionStarting( sectionInfo ); jamie@264: jamie@264: assertions = m_totals.assertions; jamie@264: jamie@264: return true; jamie@264: } jamie@264: bool testForMissingAssertions( Counts& assertions ) { jamie@264: if( assertions.total() != 0 || jamie@264: !m_config->warnAboutMissingAssertions() || jamie@264: m_testCaseTracker->currentSectionHasChildren() ) jamie@264: return false; jamie@264: m_totals.assertions.failed++; jamie@264: assertions.failed++; jamie@264: return true; jamie@264: } jamie@264: jamie@264: virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { jamie@264: if( std::uncaught_exception() ) { jamie@264: m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); jamie@264: return; jamie@264: } jamie@264: jamie@264: Counts assertions = m_totals.assertions - prevAssertions; jamie@264: bool missingAssertions = testForMissingAssertions( assertions ); jamie@264: jamie@264: m_testCaseTracker->leaveSection(); jamie@264: jamie@264: m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); jamie@264: m_messages.clear(); jamie@264: } jamie@264: jamie@264: virtual void pushScopedMessage( MessageInfo const& message ) { jamie@264: m_messages.push_back( message ); jamie@264: } jamie@264: jamie@264: virtual void popScopedMessage( MessageInfo const& message ) { jamie@264: m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); jamie@264: } jamie@264: jamie@264: virtual std::string getCurrentTestName() const { jamie@264: return m_activeTestCase jamie@264: ? m_activeTestCase->getTestCaseInfo().name jamie@264: : ""; jamie@264: } jamie@264: jamie@264: virtual const AssertionResult* getLastResult() const { jamie@264: return &m_lastResult; jamie@264: } jamie@264: jamie@264: public: jamie@264: // !TBD We need to do this another way! jamie@264: bool aborting() const { jamie@264: return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); jamie@264: } jamie@264: jamie@264: private: jamie@264: jamie@264: void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { jamie@264: TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); jamie@264: SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); jamie@264: m_reporter->sectionStarting( testCaseSection ); jamie@264: Counts prevAssertions = m_totals.assertions; jamie@264: double duration = 0; jamie@264: try { jamie@264: m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); jamie@264: TestCaseTracker::Guard guard( *m_testCaseTracker ); jamie@264: jamie@264: Timer timer; jamie@264: timer.start(); jamie@264: if( m_reporter->getPreferences().shouldRedirectStdOut ) { jamie@264: StreamRedirect coutRedir( std::cout, redirectedCout ); jamie@264: StreamRedirect cerrRedir( std::cerr, redirectedCerr ); jamie@264: m_activeTestCase->invoke(); jamie@264: } jamie@264: else { jamie@264: m_activeTestCase->invoke(); jamie@264: } jamie@264: duration = timer.getElapsedSeconds(); jamie@264: } jamie@264: catch( TestFailureException& ) { jamie@264: // This just means the test was aborted due to failure jamie@264: } jamie@264: catch(...) { jamie@264: ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(), jamie@264: m_lastAssertionInfo.lineInfo, jamie@264: m_lastAssertionInfo.capturedExpression.c_str(), jamie@264: m_lastAssertionInfo.resultDisposition ); jamie@264: exResult.useActiveException(); jamie@264: } jamie@264: // If sections ended prematurely due to an exception we stored their jamie@264: // infos here so we can tear them down outside the unwind process. jamie@264: for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), jamie@264: itEnd = m_unfinishedSections.rend(); jamie@264: it != itEnd; jamie@264: ++it ) jamie@264: sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); jamie@264: m_unfinishedSections.clear(); jamie@264: m_messages.clear(); jamie@264: jamie@264: Counts assertions = m_totals.assertions - prevAssertions; jamie@264: bool missingAssertions = testForMissingAssertions( assertions ); jamie@264: jamie@264: if( testCaseInfo.okToFail() ) { jamie@264: std::swap( assertions.failedButOk, assertions.failed ); jamie@264: m_totals.assertions.failed -= assertions.failedButOk; jamie@264: m_totals.assertions.failedButOk += assertions.failedButOk; jamie@264: } jamie@264: jamie@264: SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); jamie@264: m_reporter->sectionEnded( testCaseSectionStats ); jamie@264: } jamie@264: jamie@264: private: jamie@264: struct UnfinishedSections { jamie@264: UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) jamie@264: : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) jamie@264: {} jamie@264: jamie@264: SectionInfo info; jamie@264: Counts prevAssertions; jamie@264: double durationInSeconds; jamie@264: }; jamie@264: jamie@264: TestRunInfo m_runInfo; jamie@264: IMutableContext& m_context; jamie@264: TestCase const* m_activeTestCase; jamie@264: Option m_testCaseTracker; jamie@264: AssertionResult m_lastResult; jamie@264: jamie@264: Ptr m_config; jamie@264: Totals m_totals; jamie@264: Ptr m_reporter; jamie@264: std::vector m_messages; jamie@264: IRunner* m_prevRunner; jamie@264: IResultCapture* m_prevResultCapture; jamie@264: Ptr m_prevConfig; jamie@264: AssertionInfo m_lastAssertionInfo; jamie@264: std::vector m_unfinishedSections; jamie@264: }; jamie@264: jamie@264: IResultCapture& getResultCapture() { jamie@264: if( IResultCapture* capture = getCurrentContext().getResultCapture() ) jamie@264: return *capture; jamie@264: else jamie@264: throw std::logic_error( "No result capture instance" ); jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: internal/catch_version.h jamie@264: #define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: // Versioning information jamie@264: struct Version { jamie@264: Version( unsigned int _majorVersion, jamie@264: unsigned int _minorVersion, jamie@264: unsigned int _buildNumber, jamie@264: char const* const _branchName ) jamie@264: : majorVersion( _majorVersion ), jamie@264: minorVersion( _minorVersion ), jamie@264: buildNumber( _buildNumber ), jamie@264: branchName( _branchName ) jamie@264: {} jamie@264: jamie@264: unsigned int const majorVersion; jamie@264: unsigned int const minorVersion; jamie@264: unsigned int const buildNumber; jamie@264: char const* const branchName; jamie@264: jamie@264: private: jamie@264: void operator=( Version const& ); jamie@264: }; jamie@264: jamie@264: extern Version libraryVersion; jamie@264: } jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class Runner { jamie@264: jamie@264: public: jamie@264: Runner( Ptr const& config ) jamie@264: : m_config( config ) jamie@264: { jamie@264: openStream(); jamie@264: makeReporter(); jamie@264: } jamie@264: jamie@264: Totals runTests() { jamie@264: jamie@264: RunContext context( m_config.get(), m_reporter ); jamie@264: jamie@264: Totals totals; jamie@264: jamie@264: context.testGroupStarting( "", 1, 1 ); // deprecated? jamie@264: jamie@264: TestSpec testSpec = m_config->testSpec(); jamie@264: if( !testSpec.hasFilters() ) jamie@264: testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests jamie@264: jamie@264: std::vector testCases; jamie@264: getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); jamie@264: jamie@264: int testsRunForGroup = 0; jamie@264: for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: testsRunForGroup++; jamie@264: if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { jamie@264: jamie@264: if( context.aborting() ) jamie@264: break; jamie@264: jamie@264: totals += context.runTest( *it ); jamie@264: m_testsAlreadyRun.insert( *it ); jamie@264: } jamie@264: } jamie@264: context.testGroupEnded( "", totals, 1, 1 ); jamie@264: return totals; jamie@264: } jamie@264: jamie@264: private: jamie@264: void openStream() { jamie@264: // Open output file, if specified jamie@264: if( !m_config->getFilename().empty() ) { jamie@264: m_ofs.open( m_config->getFilename().c_str() ); jamie@264: if( m_ofs.fail() ) { jamie@264: std::ostringstream oss; jamie@264: oss << "Unable to open file: '" << m_config->getFilename() << "'"; jamie@264: throw std::domain_error( oss.str() ); jamie@264: } jamie@264: m_config->setStreamBuf( m_ofs.rdbuf() ); jamie@264: } jamie@264: } jamie@264: void makeReporter() { jamie@264: std::string reporterName = m_config->getReporterName().empty() jamie@264: ? "console" jamie@264: : m_config->getReporterName(); jamie@264: jamie@264: m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); jamie@264: if( !m_reporter ) { jamie@264: std::ostringstream oss; jamie@264: oss << "No reporter registered with name: '" << reporterName << "'"; jamie@264: throw std::domain_error( oss.str() ); jamie@264: } jamie@264: } jamie@264: jamie@264: private: jamie@264: Ptr m_config; jamie@264: std::ofstream m_ofs; jamie@264: Ptr m_reporter; jamie@264: std::set m_testsAlreadyRun; jamie@264: }; jamie@264: jamie@264: class Session { jamie@264: static bool alreadyInstantiated; jamie@264: jamie@264: public: jamie@264: jamie@264: struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; jamie@264: jamie@264: Session() jamie@264: : m_cli( makeCommandLineParser() ) { jamie@264: if( alreadyInstantiated ) { jamie@264: std::string msg = "Only one instance of Catch::Session can ever be used"; jamie@264: std::cerr << msg << std::endl; jamie@264: throw std::logic_error( msg ); jamie@264: } jamie@264: alreadyInstantiated = true; jamie@264: } jamie@264: ~Session() { jamie@264: Catch::cleanUp(); jamie@264: } jamie@264: jamie@264: void showHelp( std::string const& processName ) { jamie@264: std::cout << "\nCatch v" << libraryVersion.majorVersion << "." jamie@264: << libraryVersion.minorVersion << " build " jamie@264: << libraryVersion.buildNumber; jamie@264: if( libraryVersion.branchName != std::string( "master" ) ) jamie@264: std::cout << " (" << libraryVersion.branchName << " branch)"; jamie@264: std::cout << "\n"; jamie@264: jamie@264: m_cli.usage( std::cout, processName ); jamie@264: std::cout << "For more detail usage please see the project docs\n" << std::endl; jamie@264: } jamie@264: jamie@264: int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { jamie@264: try { jamie@264: m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); jamie@264: m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); jamie@264: if( m_configData.showHelp ) jamie@264: showHelp( m_configData.processName ); jamie@264: m_config.reset(); jamie@264: } jamie@264: catch( std::exception& ex ) { jamie@264: { jamie@264: Colour colourGuard( Colour::Red ); jamie@264: std::cerr << "\nError(s) in input:\n" jamie@264: << Text( ex.what(), TextAttributes().setIndent(2) ) jamie@264: << "\n\n"; jamie@264: } jamie@264: m_cli.usage( std::cout, m_configData.processName ); jamie@264: return (std::numeric_limits::max)(); jamie@264: } jamie@264: return 0; jamie@264: } jamie@264: jamie@264: void useConfigData( ConfigData const& _configData ) { jamie@264: m_configData = _configData; jamie@264: m_config.reset(); jamie@264: } jamie@264: jamie@264: int run( int argc, char* const argv[] ) { jamie@264: jamie@264: int returnCode = applyCommandLine( argc, argv ); jamie@264: if( returnCode == 0 ) jamie@264: returnCode = run(); jamie@264: return returnCode; jamie@264: } jamie@264: jamie@264: int run() { jamie@264: if( m_configData.showHelp ) jamie@264: return 0; jamie@264: jamie@264: try jamie@264: { jamie@264: config(); // Force config to be constructed jamie@264: Runner runner( m_config ); jamie@264: jamie@264: // Handle list request jamie@264: if( Option listed = list( config() ) ) jamie@264: return static_cast( *listed ); jamie@264: jamie@264: return static_cast( runner.runTests().assertions.failed ); jamie@264: } jamie@264: catch( std::exception& ex ) { jamie@264: std::cerr << ex.what() << std::endl; jamie@264: return (std::numeric_limits::max)(); jamie@264: } jamie@264: } jamie@264: jamie@264: Clara::CommandLine const& cli() const { jamie@264: return m_cli; jamie@264: } jamie@264: std::vector const& unusedTokens() const { jamie@264: return m_unusedTokens; jamie@264: } jamie@264: ConfigData& configData() { jamie@264: return m_configData; jamie@264: } jamie@264: Config& config() { jamie@264: if( !m_config ) jamie@264: m_config = new Config( m_configData ); jamie@264: return *m_config; jamie@264: } jamie@264: jamie@264: private: jamie@264: Clara::CommandLine m_cli; jamie@264: std::vector m_unusedTokens; jamie@264: ConfigData m_configData; jamie@264: Ptr m_config; jamie@264: }; jamie@264: jamie@264: bool Session::alreadyInstantiated = false; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_registry_hub.hpp jamie@264: #define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_test_case_registry_impl.hpp jamie@264: #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class TestRegistry : public ITestCaseRegistry { jamie@264: public: jamie@264: TestRegistry() : m_unnamedCount( 0 ) {} jamie@264: virtual ~TestRegistry(); jamie@264: jamie@264: virtual void registerTest( TestCase const& testCase ) { jamie@264: std::string name = testCase.getTestCaseInfo().name; jamie@264: if( name == "" ) { jamie@264: std::ostringstream oss; jamie@264: oss << "Anonymous test case " << ++m_unnamedCount; jamie@264: return registerTest( testCase.withName( oss.str() ) ); jamie@264: } jamie@264: jamie@264: if( m_functions.find( testCase ) == m_functions.end() ) { jamie@264: m_functions.insert( testCase ); jamie@264: m_functionsInOrder.push_back( testCase ); jamie@264: if( !testCase.isHidden() ) jamie@264: m_nonHiddenFunctions.push_back( testCase ); jamie@264: } jamie@264: else { jamie@264: TestCase const& prev = *m_functions.find( testCase ); jamie@264: { jamie@264: Colour colourGuard( Colour::Red ); jamie@264: std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" jamie@264: << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" jamie@264: << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; jamie@264: } jamie@264: exit(1); jamie@264: } jamie@264: } jamie@264: jamie@264: virtual std::vector const& getAllTests() const { jamie@264: return m_functionsInOrder; jamie@264: } jamie@264: jamie@264: virtual std::vector const& getAllNonHiddenTests() const { jamie@264: return m_nonHiddenFunctions; jamie@264: } jamie@264: jamie@264: virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases ) const { jamie@264: for( std::vector::const_iterator it = m_functionsInOrder.begin(), jamie@264: itEnd = m_functionsInOrder.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) ) jamie@264: matchingTestCases.push_back( *it ); jamie@264: } jamie@264: } jamie@264: jamie@264: private: jamie@264: jamie@264: std::set m_functions; jamie@264: std::vector m_functionsInOrder; jamie@264: std::vector m_nonHiddenFunctions; jamie@264: size_t m_unnamedCount; jamie@264: }; jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////// jamie@264: jamie@264: class FreeFunctionTestCase : public SharedImpl { jamie@264: public: jamie@264: jamie@264: FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} jamie@264: jamie@264: virtual void invoke() const { jamie@264: m_fun(); jamie@264: } jamie@264: jamie@264: private: jamie@264: virtual ~FreeFunctionTestCase(); jamie@264: jamie@264: TestFunction m_fun; jamie@264: }; jamie@264: jamie@264: inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { jamie@264: std::string className = classOrQualifiedMethodName; jamie@264: if( startsWith( className, "&" ) ) jamie@264: { jamie@264: std::size_t lastColons = className.rfind( "::" ); jamie@264: std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); jamie@264: if( penultimateColons == std::string::npos ) jamie@264: penultimateColons = 1; jamie@264: className = className.substr( penultimateColons, lastColons-penultimateColons ); jamie@264: } jamie@264: return className; jamie@264: } jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////// jamie@264: jamie@264: AutoReg::AutoReg( TestFunction function, jamie@264: SourceLineInfo const& lineInfo, jamie@264: NameAndDesc const& nameAndDesc ) { jamie@264: registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); jamie@264: } jamie@264: jamie@264: AutoReg::~AutoReg() {} jamie@264: jamie@264: void AutoReg::registerTestCase( ITestCase* testCase, jamie@264: char const* classOrQualifiedMethodName, jamie@264: NameAndDesc const& nameAndDesc, jamie@264: SourceLineInfo const& lineInfo ) { jamie@264: jamie@264: getMutableRegistryHub().registerTest jamie@264: ( makeTestCase( testCase, jamie@264: extractClassName( classOrQualifiedMethodName ), jamie@264: nameAndDesc.name, jamie@264: nameAndDesc.description, jamie@264: lineInfo ) ); jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_reporter_registry.hpp jamie@264: #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class ReporterRegistry : public IReporterRegistry { jamie@264: jamie@264: public: jamie@264: jamie@264: virtual ~ReporterRegistry() { jamie@264: deleteAllValues( m_factories ); jamie@264: } jamie@264: jamie@264: virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { jamie@264: FactoryMap::const_iterator it = m_factories.find( name ); jamie@264: if( it == m_factories.end() ) jamie@264: return NULL; jamie@264: return it->second->create( ReporterConfig( config ) ); jamie@264: } jamie@264: jamie@264: void registerReporter( std::string const& name, IReporterFactory* factory ) { jamie@264: m_factories.insert( std::make_pair( name, factory ) ); jamie@264: } jamie@264: jamie@264: FactoryMap const& getFactories() const { jamie@264: return m_factories; jamie@264: } jamie@264: jamie@264: private: jamie@264: FactoryMap m_factories; jamie@264: }; jamie@264: } jamie@264: jamie@264: // #included from: catch_exception_translator_registry.hpp jamie@264: #define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED jamie@264: jamie@264: #ifdef __OBJC__ jamie@264: #import "Foundation/Foundation.h" jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { jamie@264: public: jamie@264: ~ExceptionTranslatorRegistry() { jamie@264: deleteAll( m_translators ); jamie@264: } jamie@264: jamie@264: virtual void registerTranslator( const IExceptionTranslator* translator ) { jamie@264: m_translators.push_back( translator ); jamie@264: } jamie@264: jamie@264: virtual std::string translateActiveException() const { jamie@264: try { jamie@264: #ifdef __OBJC__ jamie@264: // In Objective-C try objective-c exceptions first jamie@264: @try { jamie@264: throw; jamie@264: } jamie@264: @catch (NSException *exception) { jamie@264: return toString( [exception description] ); jamie@264: } jamie@264: #else jamie@264: throw; jamie@264: #endif jamie@264: } jamie@264: catch( TestFailureException& ) { jamie@264: throw; jamie@264: } jamie@264: catch( std::exception& ex ) { jamie@264: return ex.what(); jamie@264: } jamie@264: catch( std::string& msg ) { jamie@264: return msg; jamie@264: } jamie@264: catch( const char* msg ) { jamie@264: return msg; jamie@264: } jamie@264: catch(...) { jamie@264: return tryTranslators( m_translators.begin() ); jamie@264: } jamie@264: } jamie@264: jamie@264: std::string tryTranslators( std::vector::const_iterator it ) const { jamie@264: if( it == m_translators.end() ) jamie@264: return "Unknown exception"; jamie@264: jamie@264: try { jamie@264: return (*it)->translate(); jamie@264: } jamie@264: catch(...) { jamie@264: return tryTranslators( it+1 ); jamie@264: } jamie@264: } jamie@264: jamie@264: private: jamie@264: std::vector m_translators; jamie@264: }; jamie@264: } jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: namespace { jamie@264: jamie@264: class RegistryHub : public IRegistryHub, public IMutableRegistryHub { jamie@264: jamie@264: RegistryHub( RegistryHub const& ); jamie@264: void operator=( RegistryHub const& ); jamie@264: jamie@264: public: // IRegistryHub jamie@264: RegistryHub() { jamie@264: } jamie@264: virtual IReporterRegistry const& getReporterRegistry() const { jamie@264: return m_reporterRegistry; jamie@264: } jamie@264: virtual ITestCaseRegistry const& getTestCaseRegistry() const { jamie@264: return m_testCaseRegistry; jamie@264: } jamie@264: virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { jamie@264: return m_exceptionTranslatorRegistry; jamie@264: } jamie@264: jamie@264: public: // IMutableRegistryHub jamie@264: virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { jamie@264: m_reporterRegistry.registerReporter( name, factory ); jamie@264: } jamie@264: virtual void registerTest( TestCase const& testInfo ) { jamie@264: m_testCaseRegistry.registerTest( testInfo ); jamie@264: } jamie@264: virtual void registerTranslator( const IExceptionTranslator* translator ) { jamie@264: m_exceptionTranslatorRegistry.registerTranslator( translator ); jamie@264: } jamie@264: jamie@264: private: jamie@264: TestRegistry m_testCaseRegistry; jamie@264: ReporterRegistry m_reporterRegistry; jamie@264: ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; jamie@264: }; jamie@264: jamie@264: // Single, global, instance jamie@264: inline RegistryHub*& getTheRegistryHub() { jamie@264: static RegistryHub* theRegistryHub = NULL; jamie@264: if( !theRegistryHub ) jamie@264: theRegistryHub = new RegistryHub(); jamie@264: return theRegistryHub; jamie@264: } jamie@264: } jamie@264: jamie@264: IRegistryHub& getRegistryHub() { jamie@264: return *getTheRegistryHub(); jamie@264: } jamie@264: IMutableRegistryHub& getMutableRegistryHub() { jamie@264: return *getTheRegistryHub(); jamie@264: } jamie@264: void cleanUp() { jamie@264: delete getTheRegistryHub(); jamie@264: getTheRegistryHub() = NULL; jamie@264: cleanUpContext(); jamie@264: } jamie@264: std::string translateActiveException() { jamie@264: return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_notimplemented_exception.hpp jamie@264: #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) jamie@264: : m_lineInfo( lineInfo ) { jamie@264: std::ostringstream oss; jamie@264: oss << lineInfo << ": function "; jamie@264: oss << "not implemented"; jamie@264: m_what = oss.str(); jamie@264: } jamie@264: jamie@264: const char* NotImplementedException::what() const CATCH_NOEXCEPT { jamie@264: return m_what.c_str(); jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_context_impl.hpp jamie@264: #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_stream.hpp jamie@264: #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_streambuf.h jamie@264: #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class StreamBufBase : public std::streambuf { jamie@264: public: jamie@264: virtual ~StreamBufBase() CATCH_NOEXCEPT; jamie@264: }; jamie@264: } jamie@264: jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: template jamie@264: class StreamBufImpl : public StreamBufBase { jamie@264: char data[bufferSize]; jamie@264: WriterF m_writer; jamie@264: jamie@264: public: jamie@264: StreamBufImpl() { jamie@264: setp( data, data + sizeof(data) ); jamie@264: } jamie@264: jamie@264: ~StreamBufImpl() CATCH_NOEXCEPT { jamie@264: sync(); jamie@264: } jamie@264: jamie@264: private: jamie@264: int overflow( int c ) { jamie@264: sync(); jamie@264: jamie@264: if( c != EOF ) { jamie@264: if( pbase() == epptr() ) jamie@264: m_writer( std::string( 1, static_cast( c ) ) ); jamie@264: else jamie@264: sputc( static_cast( c ) ); jamie@264: } jamie@264: return 0; jamie@264: } jamie@264: jamie@264: int sync() { jamie@264: if( pbase() != pptr() ) { jamie@264: m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); jamie@264: setp( pbase(), epptr() ); jamie@264: } jamie@264: return 0; jamie@264: } jamie@264: }; jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////// jamie@264: jamie@264: struct OutputDebugWriter { jamie@264: jamie@264: void operator()( std::string const&str ) { jamie@264: writeToDebugConsole( str ); jamie@264: } jamie@264: }; jamie@264: jamie@264: Stream::Stream() jamie@264: : streamBuf( NULL ), isOwned( false ) jamie@264: {} jamie@264: jamie@264: Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) jamie@264: : streamBuf( _streamBuf ), isOwned( _isOwned ) jamie@264: {} jamie@264: jamie@264: void Stream::release() { jamie@264: if( isOwned ) { jamie@264: delete streamBuf; jamie@264: streamBuf = NULL; jamie@264: isOwned = false; jamie@264: } jamie@264: } jamie@264: } jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class Context : public IMutableContext { jamie@264: jamie@264: Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} jamie@264: Context( Context const& ); jamie@264: void operator=( Context const& ); jamie@264: jamie@264: public: // IContext jamie@264: virtual IResultCapture* getResultCapture() { jamie@264: return m_resultCapture; jamie@264: } jamie@264: virtual IRunner* getRunner() { jamie@264: return m_runner; jamie@264: } jamie@264: virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { jamie@264: return getGeneratorsForCurrentTest() jamie@264: .getGeneratorInfo( fileInfo, totalSize ) jamie@264: .getCurrentIndex(); jamie@264: } jamie@264: virtual bool advanceGeneratorsForCurrentTest() { jamie@264: IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); jamie@264: return generators && generators->moveNext(); jamie@264: } jamie@264: jamie@264: virtual Ptr getConfig() const { jamie@264: return m_config; jamie@264: } jamie@264: jamie@264: public: // IMutableContext jamie@264: virtual void setResultCapture( IResultCapture* resultCapture ) { jamie@264: m_resultCapture = resultCapture; jamie@264: } jamie@264: virtual void setRunner( IRunner* runner ) { jamie@264: m_runner = runner; jamie@264: } jamie@264: virtual void setConfig( Ptr const& config ) { jamie@264: m_config = config; jamie@264: } jamie@264: jamie@264: friend IMutableContext& getCurrentMutableContext(); jamie@264: jamie@264: private: jamie@264: IGeneratorsForTest* findGeneratorsForCurrentTest() { jamie@264: std::string testName = getResultCapture()->getCurrentTestName(); jamie@264: jamie@264: std::map::const_iterator it = jamie@264: m_generatorsByTestName.find( testName ); jamie@264: return it != m_generatorsByTestName.end() jamie@264: ? it->second jamie@264: : NULL; jamie@264: } jamie@264: jamie@264: IGeneratorsForTest& getGeneratorsForCurrentTest() { jamie@264: IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); jamie@264: if( !generators ) { jamie@264: std::string testName = getResultCapture()->getCurrentTestName(); jamie@264: generators = createGeneratorsForTest(); jamie@264: m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); jamie@264: } jamie@264: return *generators; jamie@264: } jamie@264: jamie@264: private: jamie@264: Ptr m_config; jamie@264: IRunner* m_runner; jamie@264: IResultCapture* m_resultCapture; jamie@264: std::map m_generatorsByTestName; jamie@264: }; jamie@264: jamie@264: namespace { jamie@264: Context* currentContext = NULL; jamie@264: } jamie@264: IMutableContext& getCurrentMutableContext() { jamie@264: if( !currentContext ) jamie@264: currentContext = new Context(); jamie@264: return *currentContext; jamie@264: } jamie@264: IContext& getCurrentContext() { jamie@264: return getCurrentMutableContext(); jamie@264: } jamie@264: jamie@264: Stream createStream( std::string const& streamName ) { jamie@264: if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false ); jamie@264: if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false ); jamie@264: if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); jamie@264: jamie@264: throw std::domain_error( "Unknown stream: " + streamName ); jamie@264: } jamie@264: jamie@264: void cleanUpContext() { jamie@264: delete currentContext; jamie@264: currentContext = NULL; jamie@264: } jamie@264: } jamie@264: jamie@264: // #included from: catch_console_colour_impl.hpp jamie@264: #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { namespace Detail { jamie@264: struct IColourImpl { jamie@264: virtual ~IColourImpl() {} jamie@264: virtual void use( Colour::Code _colourCode ) = 0; jamie@264: }; jamie@264: }} jamie@264: jamie@264: #if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// jamie@264: jamie@264: #ifndef NOMINMAX jamie@264: #define NOMINMAX jamie@264: #endif jamie@264: jamie@264: #ifdef __AFXDLL jamie@264: #include jamie@264: #else jamie@264: #include jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: namespace { jamie@264: jamie@264: class Win32ColourImpl : public Detail::IColourImpl { jamie@264: public: jamie@264: Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) jamie@264: { jamie@264: CONSOLE_SCREEN_BUFFER_INFO csbiInfo; jamie@264: GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); jamie@264: originalAttributes = csbiInfo.wAttributes; jamie@264: } jamie@264: jamie@264: virtual void use( Colour::Code _colourCode ) { jamie@264: switch( _colourCode ) { jamie@264: case Colour::None: return setTextAttribute( originalAttributes ); jamie@264: case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); jamie@264: case Colour::Red: return setTextAttribute( FOREGROUND_RED ); jamie@264: case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); jamie@264: case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); jamie@264: case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); jamie@264: case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); jamie@264: case Colour::Grey: return setTextAttribute( 0 ); jamie@264: jamie@264: case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); jamie@264: case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); jamie@264: case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); jamie@264: case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); jamie@264: jamie@264: case Colour::Bright: throw std::logic_error( "not a colour" ); jamie@264: } jamie@264: } jamie@264: jamie@264: private: jamie@264: void setTextAttribute( WORD _textAttribute ) { jamie@264: SetConsoleTextAttribute( stdoutHandle, _textAttribute ); jamie@264: } jamie@264: HANDLE stdoutHandle; jamie@264: WORD originalAttributes; jamie@264: }; jamie@264: jamie@264: inline bool shouldUseColourForPlatform() { jamie@264: return true; jamie@264: } jamie@264: jamie@264: static Detail::IColourImpl* platformColourInstance() { jamie@264: static Win32ColourImpl s_instance; jamie@264: return &s_instance; jamie@264: } jamie@264: jamie@264: } // end anon namespace jamie@264: } // end namespace Catch jamie@264: jamie@264: #else // Not Windows - assumed to be POSIX compatible ////////////////////////// jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: namespace { jamie@264: jamie@264: // use POSIX/ ANSI console terminal codes jamie@264: // Thanks to Adam Strzelecki for original contribution jamie@264: // (http://github.com/nanoant) jamie@264: // https://github.com/philsquared/Catch/pull/131 jamie@264: class PosixColourImpl : public Detail::IColourImpl { jamie@264: public: jamie@264: virtual void use( Colour::Code _colourCode ) { jamie@264: switch( _colourCode ) { jamie@264: case Colour::None: jamie@264: case Colour::White: return setColour( "[0m" ); jamie@264: case Colour::Red: return setColour( "[0;31m" ); jamie@264: case Colour::Green: return setColour( "[0;32m" ); jamie@264: case Colour::Blue: return setColour( "[0:34m" ); jamie@264: case Colour::Cyan: return setColour( "[0;36m" ); jamie@264: case Colour::Yellow: return setColour( "[0;33m" ); jamie@264: case Colour::Grey: return setColour( "[1;30m" ); jamie@264: jamie@264: case Colour::LightGrey: return setColour( "[0;37m" ); jamie@264: case Colour::BrightRed: return setColour( "[1;31m" ); jamie@264: case Colour::BrightGreen: return setColour( "[1;32m" ); jamie@264: case Colour::BrightWhite: return setColour( "[1;37m" ); jamie@264: jamie@264: case Colour::Bright: throw std::logic_error( "not a colour" ); jamie@264: } jamie@264: } jamie@264: private: jamie@264: void setColour( const char* _escapeCode ) { jamie@264: std::cout << '\033' << _escapeCode; jamie@264: } jamie@264: }; jamie@264: jamie@264: inline bool shouldUseColourForPlatform() { jamie@264: return isatty(STDOUT_FILENO); jamie@264: } jamie@264: jamie@264: static Detail::IColourImpl* platformColourInstance() { jamie@264: static PosixColourImpl s_instance; jamie@264: return &s_instance; jamie@264: } jamie@264: jamie@264: } // end anon namespace jamie@264: } // end namespace Catch jamie@264: jamie@264: #endif // not Windows jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: namespace { jamie@264: struct NoColourImpl : Detail::IColourImpl { jamie@264: void use( Colour::Code ) {} jamie@264: jamie@264: static IColourImpl* instance() { jamie@264: static NoColourImpl s_instance; jamie@264: return &s_instance; jamie@264: } jamie@264: }; jamie@264: static bool shouldUseColour() { jamie@264: return shouldUseColourForPlatform() && !isDebuggerActive(); jamie@264: } jamie@264: } jamie@264: jamie@264: Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } jamie@264: Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } jamie@264: Colour::~Colour(){ if( !m_moved ) use( None ); } jamie@264: void Colour::use( Code _colourCode ) { jamie@264: impl()->use( _colourCode ); jamie@264: } jamie@264: jamie@264: Detail::IColourImpl* Colour::impl() { jamie@264: return shouldUseColour() jamie@264: ? platformColourInstance() jamie@264: : NoColourImpl::instance(); jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_generators_impl.hpp jamie@264: #define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct GeneratorInfo : IGeneratorInfo { jamie@264: jamie@264: GeneratorInfo( std::size_t size ) jamie@264: : m_size( size ), jamie@264: m_currentIndex( 0 ) jamie@264: {} jamie@264: jamie@264: bool moveNext() { jamie@264: if( ++m_currentIndex == m_size ) { jamie@264: m_currentIndex = 0; jamie@264: return false; jamie@264: } jamie@264: return true; jamie@264: } jamie@264: jamie@264: std::size_t getCurrentIndex() const { jamie@264: return m_currentIndex; jamie@264: } jamie@264: jamie@264: std::size_t m_size; jamie@264: std::size_t m_currentIndex; jamie@264: }; jamie@264: jamie@264: /////////////////////////////////////////////////////////////////////////// jamie@264: jamie@264: class GeneratorsForTest : public IGeneratorsForTest { jamie@264: jamie@264: public: jamie@264: ~GeneratorsForTest() { jamie@264: deleteAll( m_generatorsInOrder ); jamie@264: } jamie@264: jamie@264: IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { jamie@264: std::map::const_iterator it = m_generatorsByName.find( fileInfo ); jamie@264: if( it == m_generatorsByName.end() ) { jamie@264: IGeneratorInfo* info = new GeneratorInfo( size ); jamie@264: m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); jamie@264: m_generatorsInOrder.push_back( info ); jamie@264: return *info; jamie@264: } jamie@264: return *it->second; jamie@264: } jamie@264: jamie@264: bool moveNext() { jamie@264: std::vector::const_iterator it = m_generatorsInOrder.begin(); jamie@264: std::vector::const_iterator itEnd = m_generatorsInOrder.end(); jamie@264: for(; it != itEnd; ++it ) { jamie@264: if( (*it)->moveNext() ) jamie@264: return true; jamie@264: } jamie@264: return false; jamie@264: } jamie@264: jamie@264: private: jamie@264: std::map m_generatorsByName; jamie@264: std::vector m_generatorsInOrder; jamie@264: }; jamie@264: jamie@264: IGeneratorsForTest* createGeneratorsForTest() jamie@264: { jamie@264: return new GeneratorsForTest(); jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_assertionresult.hpp jamie@264: #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: AssertionInfo::AssertionInfo( std::string const& _macroName, jamie@264: SourceLineInfo const& _lineInfo, jamie@264: std::string const& _capturedExpression, jamie@264: ResultDisposition::Flags _resultDisposition ) jamie@264: : macroName( _macroName ), jamie@264: lineInfo( _lineInfo ), jamie@264: capturedExpression( _capturedExpression ), jamie@264: resultDisposition( _resultDisposition ) jamie@264: {} jamie@264: jamie@264: AssertionResult::AssertionResult() {} jamie@264: jamie@264: AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) jamie@264: : m_info( info ), jamie@264: m_resultData( data ) jamie@264: {} jamie@264: jamie@264: AssertionResult::~AssertionResult() {} jamie@264: jamie@264: // Result was a success jamie@264: bool AssertionResult::succeeded() const { jamie@264: return Catch::isOk( m_resultData.resultType ); jamie@264: } jamie@264: jamie@264: // Result was a success, or failure is suppressed jamie@264: bool AssertionResult::isOk() const { jamie@264: return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); jamie@264: } jamie@264: jamie@264: ResultWas::OfType AssertionResult::getResultType() const { jamie@264: return m_resultData.resultType; jamie@264: } jamie@264: jamie@264: bool AssertionResult::hasExpression() const { jamie@264: return !m_info.capturedExpression.empty(); jamie@264: } jamie@264: jamie@264: bool AssertionResult::hasMessage() const { jamie@264: return !m_resultData.message.empty(); jamie@264: } jamie@264: jamie@264: std::string AssertionResult::getExpression() const { jamie@264: if( isFalseTest( m_info.resultDisposition ) ) jamie@264: return "!" + m_info.capturedExpression; jamie@264: else jamie@264: return m_info.capturedExpression; jamie@264: } jamie@264: std::string AssertionResult::getExpressionInMacro() const { jamie@264: if( m_info.macroName.empty() ) jamie@264: return m_info.capturedExpression; jamie@264: else jamie@264: return m_info.macroName + "( " + m_info.capturedExpression + " )"; jamie@264: } jamie@264: jamie@264: bool AssertionResult::hasExpandedExpression() const { jamie@264: return hasExpression() && getExpandedExpression() != getExpression(); jamie@264: } jamie@264: jamie@264: std::string AssertionResult::getExpandedExpression() const { jamie@264: return m_resultData.reconstructedExpression; jamie@264: } jamie@264: jamie@264: std::string AssertionResult::getMessage() const { jamie@264: return m_resultData.message; jamie@264: } jamie@264: SourceLineInfo AssertionResult::getSourceInfo() const { jamie@264: return m_info.lineInfo; jamie@264: } jamie@264: jamie@264: std::string AssertionResult::getTestMacroName() const { jamie@264: return m_info.macroName; jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_test_case_info.hpp jamie@264: #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { jamie@264: if( tag == "." || jamie@264: tag == "hide" || jamie@264: tag == "!hide" ) jamie@264: return TestCaseInfo::IsHidden; jamie@264: else if( tag == "!throws" ) jamie@264: return TestCaseInfo::Throws; jamie@264: else if( tag == "!shouldfail" ) jamie@264: return TestCaseInfo::ShouldFail; jamie@264: else if( tag == "!mayfail" ) jamie@264: return TestCaseInfo::MayFail; jamie@264: else jamie@264: return TestCaseInfo::None; jamie@264: } jamie@264: inline bool isReservedTag( std::string const& tag ) { jamie@264: return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); jamie@264: } jamie@264: inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { jamie@264: if( isReservedTag( tag ) ) { jamie@264: { jamie@264: Colour colourGuard( Colour::Red ); jamie@264: std::cerr jamie@264: << "Tag name [" << tag << "] not allowed.\n" jamie@264: << "Tag names starting with non alpha-numeric characters are reserved\n"; jamie@264: } jamie@264: { jamie@264: Colour colourGuard( Colour::FileName ); jamie@264: std::cerr << _lineInfo << std::endl; jamie@264: } jamie@264: exit(1); jamie@264: } jamie@264: } jamie@264: jamie@264: TestCase makeTestCase( ITestCase* _testCase, jamie@264: std::string const& _className, jamie@264: std::string const& _name, jamie@264: std::string const& _descOrTags, jamie@264: SourceLineInfo const& _lineInfo ) jamie@264: { jamie@264: bool isHidden( startsWith( _name, "./" ) ); // Legacy support jamie@264: jamie@264: // Parse out tags jamie@264: std::set tags; jamie@264: std::string desc, tag; jamie@264: bool inTag = false; jamie@264: for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { jamie@264: char c = _descOrTags[i]; jamie@264: if( !inTag ) { jamie@264: if( c == '[' ) jamie@264: inTag = true; jamie@264: else jamie@264: desc += c; jamie@264: } jamie@264: else { jamie@264: if( c == ']' ) { jamie@264: enforceNotReservedTag( tag, _lineInfo ); jamie@264: jamie@264: inTag = false; jamie@264: if( tag == "hide" || tag == "." ) jamie@264: isHidden = true; jamie@264: else jamie@264: tags.insert( tag ); jamie@264: tag.clear(); jamie@264: } jamie@264: else jamie@264: tag += c; jamie@264: } jamie@264: } jamie@264: if( isHidden ) { jamie@264: tags.insert( "hide" ); jamie@264: tags.insert( "." ); jamie@264: } jamie@264: jamie@264: TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); jamie@264: return TestCase( _testCase, info ); jamie@264: } jamie@264: jamie@264: TestCaseInfo::TestCaseInfo( std::string const& _name, jamie@264: std::string const& _className, jamie@264: std::string const& _description, jamie@264: std::set const& _tags, jamie@264: SourceLineInfo const& _lineInfo ) jamie@264: : name( _name ), jamie@264: className( _className ), jamie@264: description( _description ), jamie@264: tags( _tags ), jamie@264: lineInfo( _lineInfo ), jamie@264: properties( None ) jamie@264: { jamie@264: std::ostringstream oss; jamie@264: for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { jamie@264: oss << "[" << *it << "]"; jamie@264: std::string lcaseTag = toLower( *it ); jamie@264: properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); jamie@264: lcaseTags.insert( lcaseTag ); jamie@264: } jamie@264: tagsAsString = oss.str(); jamie@264: } jamie@264: jamie@264: TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) jamie@264: : name( other.name ), jamie@264: className( other.className ), jamie@264: description( other.description ), jamie@264: tags( other.tags ), jamie@264: lcaseTags( other.lcaseTags ), jamie@264: tagsAsString( other.tagsAsString ), jamie@264: lineInfo( other.lineInfo ), jamie@264: properties( other.properties ) jamie@264: {} jamie@264: jamie@264: bool TestCaseInfo::isHidden() const { jamie@264: return ( properties & IsHidden ) != 0; jamie@264: } jamie@264: bool TestCaseInfo::throws() const { jamie@264: return ( properties & Throws ) != 0; jamie@264: } jamie@264: bool TestCaseInfo::okToFail() const { jamie@264: return ( properties & (ShouldFail | MayFail ) ) != 0; jamie@264: } jamie@264: bool TestCaseInfo::expectedToFail() const { jamie@264: return ( properties & (ShouldFail ) ) != 0; jamie@264: } jamie@264: jamie@264: TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} jamie@264: jamie@264: TestCase::TestCase( TestCase const& other ) jamie@264: : TestCaseInfo( other ), jamie@264: test( other.test ) jamie@264: {} jamie@264: jamie@264: TestCase TestCase::withName( std::string const& _newName ) const { jamie@264: TestCase other( *this ); jamie@264: other.name = _newName; jamie@264: return other; jamie@264: } jamie@264: jamie@264: void TestCase::swap( TestCase& other ) { jamie@264: test.swap( other.test ); jamie@264: name.swap( other.name ); jamie@264: className.swap( other.className ); jamie@264: description.swap( other.description ); jamie@264: tags.swap( other.tags ); jamie@264: lcaseTags.swap( other.lcaseTags ); jamie@264: tagsAsString.swap( other.tagsAsString ); jamie@264: std::swap( TestCaseInfo::properties, static_cast( other ).properties ); jamie@264: std::swap( lineInfo, other.lineInfo ); jamie@264: } jamie@264: jamie@264: void TestCase::invoke() const { jamie@264: test->invoke(); jamie@264: } jamie@264: jamie@264: bool TestCase::operator == ( TestCase const& other ) const { jamie@264: return test.get() == other.test.get() && jamie@264: name == other.name && jamie@264: className == other.className; jamie@264: } jamie@264: jamie@264: bool TestCase::operator < ( TestCase const& other ) const { jamie@264: return name < other.name; jamie@264: } jamie@264: TestCase& TestCase::operator = ( TestCase const& other ) { jamie@264: TestCase temp( other ); jamie@264: swap( temp ); jamie@264: return *this; jamie@264: } jamie@264: jamie@264: TestCaseInfo const& TestCase::getTestCaseInfo() const jamie@264: { jamie@264: return *this; jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_version.hpp jamie@264: #define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: // These numbers are maintained by a script jamie@264: Version libraryVersion( 1, 0, 53, "master" ); jamie@264: } jamie@264: jamie@264: // #included from: catch_message.hpp jamie@264: #define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: MessageInfo::MessageInfo( std::string const& _macroName, jamie@264: SourceLineInfo const& _lineInfo, jamie@264: ResultWas::OfType _type ) jamie@264: : macroName( _macroName ), jamie@264: lineInfo( _lineInfo ), jamie@264: type( _type ), jamie@264: sequence( ++globalCount ) jamie@264: {} jamie@264: jamie@264: // This may need protecting if threading support is added jamie@264: unsigned int MessageInfo::globalCount = 0; jamie@264: jamie@264: //////////////////////////////////////////////////////////////////////////// jamie@264: jamie@264: ScopedMessage::ScopedMessage( MessageBuilder const& builder ) jamie@264: : m_info( builder.m_info ) jamie@264: { jamie@264: m_info.message = builder.m_stream.str(); jamie@264: getResultCapture().pushScopedMessage( m_info ); jamie@264: } jamie@264: ScopedMessage::ScopedMessage( ScopedMessage const& other ) jamie@264: : m_info( other.m_info ) jamie@264: {} jamie@264: jamie@264: ScopedMessage::~ScopedMessage() { jamie@264: getResultCapture().popScopedMessage( m_info ); jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_legacy_reporter_adapter.hpp jamie@264: #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_legacy_reporter_adapter.h jamie@264: #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED jamie@264: jamie@264: namespace Catch jamie@264: { jamie@264: // Deprecated jamie@264: struct IReporter : IShared { jamie@264: virtual ~IReporter(); jamie@264: jamie@264: virtual bool shouldRedirectStdout() const = 0; jamie@264: jamie@264: virtual void StartTesting() = 0; jamie@264: virtual void EndTesting( Totals const& totals ) = 0; jamie@264: virtual void StartGroup( std::string const& groupName ) = 0; jamie@264: virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; jamie@264: virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; jamie@264: virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; jamie@264: virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; jamie@264: virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; jamie@264: virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; jamie@264: virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; jamie@264: virtual void Aborted() = 0; jamie@264: virtual void Result( AssertionResult const& result ) = 0; jamie@264: }; jamie@264: jamie@264: class LegacyReporterAdapter : public SharedImpl jamie@264: { jamie@264: public: jamie@264: LegacyReporterAdapter( Ptr const& legacyReporter ); jamie@264: virtual ~LegacyReporterAdapter(); jamie@264: jamie@264: virtual ReporterPreferences getPreferences() const; jamie@264: virtual void noMatchingTestCases( std::string const& ); jamie@264: virtual void testRunStarting( TestRunInfo const& ); jamie@264: virtual void testGroupStarting( GroupInfo const& groupInfo ); jamie@264: virtual void testCaseStarting( TestCaseInfo const& testInfo ); jamie@264: virtual void sectionStarting( SectionInfo const& sectionInfo ); jamie@264: virtual void assertionStarting( AssertionInfo const& ); jamie@264: virtual bool assertionEnded( AssertionStats const& assertionStats ); jamie@264: virtual void sectionEnded( SectionStats const& sectionStats ); jamie@264: virtual void testCaseEnded( TestCaseStats const& testCaseStats ); jamie@264: virtual void testGroupEnded( TestGroupStats const& testGroupStats ); jamie@264: virtual void testRunEnded( TestRunStats const& testRunStats ); jamie@264: jamie@264: private: jamie@264: Ptr m_legacyReporter; jamie@264: }; jamie@264: } jamie@264: jamie@264: namespace Catch jamie@264: { jamie@264: LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) jamie@264: : m_legacyReporter( legacyReporter ) jamie@264: {} jamie@264: LegacyReporterAdapter::~LegacyReporterAdapter() {} jamie@264: jamie@264: ReporterPreferences LegacyReporterAdapter::getPreferences() const { jamie@264: ReporterPreferences prefs; jamie@264: prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); jamie@264: return prefs; jamie@264: } jamie@264: jamie@264: void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} jamie@264: void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { jamie@264: m_legacyReporter->StartTesting(); jamie@264: } jamie@264: void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { jamie@264: m_legacyReporter->StartGroup( groupInfo.name ); jamie@264: } jamie@264: void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { jamie@264: m_legacyReporter->StartTestCase( testInfo ); jamie@264: } jamie@264: void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { jamie@264: m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); jamie@264: } jamie@264: void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { jamie@264: // Not on legacy interface jamie@264: } jamie@264: jamie@264: bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { jamie@264: if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { jamie@264: for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: if( it->type == ResultWas::Info ) { jamie@264: ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); jamie@264: rb << it->message; jamie@264: rb.setResultType( ResultWas::Info ); jamie@264: AssertionResult result = rb.build(); jamie@264: m_legacyReporter->Result( result ); jamie@264: } jamie@264: } jamie@264: } jamie@264: m_legacyReporter->Result( assertionStats.assertionResult ); jamie@264: return true; jamie@264: } jamie@264: void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { jamie@264: if( sectionStats.missingAssertions ) jamie@264: m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); jamie@264: m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); jamie@264: } jamie@264: void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { jamie@264: m_legacyReporter->EndTestCase jamie@264: ( testCaseStats.testInfo, jamie@264: testCaseStats.totals, jamie@264: testCaseStats.stdOut, jamie@264: testCaseStats.stdErr ); jamie@264: } jamie@264: void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { jamie@264: if( testGroupStats.aborting ) jamie@264: m_legacyReporter->Aborted(); jamie@264: m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); jamie@264: } jamie@264: void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { jamie@264: m_legacyReporter->EndTesting( testRunStats.totals ); jamie@264: } jamie@264: } jamie@264: jamie@264: // #included from: catch_timer.hpp jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic push jamie@264: #pragma clang diagnostic ignored "-Wc++11-long-long" jamie@264: #endif jamie@264: jamie@264: #ifdef CATCH_PLATFORM_WINDOWS jamie@264: #include jamie@264: #else jamie@264: #include jamie@264: #endif jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: namespace { jamie@264: #ifdef CATCH_PLATFORM_WINDOWS jamie@264: uint64_t getCurrentTicks() { jamie@264: static uint64_t hz=0, hzo=0; jamie@264: if (!hz) { jamie@264: QueryPerformanceFrequency((LARGE_INTEGER*)&hz); jamie@264: QueryPerformanceCounter((LARGE_INTEGER*)&hzo); jamie@264: } jamie@264: uint64_t t; jamie@264: QueryPerformanceCounter((LARGE_INTEGER*)&t); jamie@264: return ((t-hzo)*1000000)/hz; jamie@264: } jamie@264: #else jamie@264: uint64_t getCurrentTicks() { jamie@264: timeval t; jamie@264: gettimeofday(&t,NULL); jamie@264: return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); jamie@264: } jamie@264: #endif jamie@264: } jamie@264: jamie@264: void Timer::start() { jamie@264: m_ticks = getCurrentTicks(); jamie@264: } jamie@264: unsigned int Timer::getElapsedNanoseconds() const { jamie@264: return static_cast(getCurrentTicks() - m_ticks); jamie@264: } jamie@264: unsigned int Timer::getElapsedMilliseconds() const { jamie@264: return static_cast((getCurrentTicks() - m_ticks)/1000); jamie@264: } jamie@264: double Timer::getElapsedSeconds() const { jamie@264: return (getCurrentTicks() - m_ticks)/1000000.0; jamie@264: } jamie@264: jamie@264: } // namespace Catch jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #endif jamie@264: // #included from: catch_common.hpp jamie@264: #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: bool startsWith( std::string const& s, std::string const& prefix ) { jamie@264: return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; jamie@264: } jamie@264: bool endsWith( std::string const& s, std::string const& suffix ) { jamie@264: return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; jamie@264: } jamie@264: bool contains( std::string const& s, std::string const& infix ) { jamie@264: return s.find( infix ) != std::string::npos; jamie@264: } jamie@264: void toLowerInPlace( std::string& s ) { jamie@264: std::transform( s.begin(), s.end(), s.begin(), ::tolower ); jamie@264: } jamie@264: std::string toLower( std::string const& s ) { jamie@264: std::string lc = s; jamie@264: toLowerInPlace( lc ); jamie@264: return lc; jamie@264: } jamie@264: std::string trim( std::string const& str ) { jamie@264: static char const* whitespaceChars = "\n\r\t "; jamie@264: std::string::size_type start = str.find_first_not_of( whitespaceChars ); jamie@264: std::string::size_type end = str.find_last_not_of( whitespaceChars ); jamie@264: jamie@264: return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; jamie@264: } jamie@264: jamie@264: pluralise::pluralise( std::size_t count, std::string const& label ) jamie@264: : m_count( count ), jamie@264: m_label( label ) jamie@264: {} jamie@264: jamie@264: std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { jamie@264: os << pluraliser.m_count << " " << pluraliser.m_label; jamie@264: if( pluraliser.m_count != 1 ) jamie@264: os << "s"; jamie@264: return os; jamie@264: } jamie@264: jamie@264: SourceLineInfo::SourceLineInfo() : line( 0 ){} jamie@264: SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) jamie@264: : file( _file ), jamie@264: line( _line ) jamie@264: {} jamie@264: SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) jamie@264: : file( other.file ), jamie@264: line( other.line ) jamie@264: {} jamie@264: bool SourceLineInfo::empty() const { jamie@264: return file.empty(); jamie@264: } jamie@264: bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { jamie@264: return line == other.line && file == other.file; jamie@264: } jamie@264: jamie@264: std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { jamie@264: #ifndef __GNUG__ jamie@264: os << info.file << "(" << info.line << ")"; jamie@264: #else jamie@264: os << info.file << ":" << info.line; jamie@264: #endif jamie@264: return os; jamie@264: } jamie@264: jamie@264: void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { jamie@264: std::ostringstream oss; jamie@264: oss << locationInfo << ": Internal Catch error: '" << message << "'"; jamie@264: if( alwaysTrue() ) jamie@264: throw std::logic_error( oss.str() ); jamie@264: } jamie@264: } jamie@264: jamie@264: // #included from: catch_section.hpp jamie@264: #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: SectionInfo::SectionInfo jamie@264: ( SourceLineInfo const& _lineInfo, jamie@264: std::string const& _name, jamie@264: std::string const& _description ) jamie@264: : name( _name ), jamie@264: description( _description ), jamie@264: lineInfo( _lineInfo ) jamie@264: {} jamie@264: jamie@264: Section::Section( SectionInfo const& info ) jamie@264: : m_info( info ), jamie@264: m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) jamie@264: { jamie@264: m_timer.start(); jamie@264: } jamie@264: jamie@264: Section::~Section() { jamie@264: if( m_sectionIncluded ) jamie@264: getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); jamie@264: } jamie@264: jamie@264: // This indicates whether the section should be executed or not jamie@264: Section::operator bool() const { jamie@264: return m_sectionIncluded; jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_debugger.hpp jamie@264: #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: #ifdef CATCH_PLATFORM_MAC jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch{ jamie@264: jamie@264: // The following function is taken directly from the following technical note: jamie@264: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html jamie@264: jamie@264: // Returns true if the current process is being debugged (either jamie@264: // running under the debugger or has a debugger attached post facto). jamie@264: bool isDebuggerActive(){ jamie@264: jamie@264: int mib[4]; jamie@264: struct kinfo_proc info; jamie@264: size_t size; jamie@264: jamie@264: // Initialize the flags so that, if sysctl fails for some bizarre jamie@264: // reason, we get a predictable result. jamie@264: jamie@264: info.kp_proc.p_flag = 0; jamie@264: jamie@264: // Initialize mib, which tells sysctl the info we want, in this case jamie@264: // we're looking for information about a specific process ID. jamie@264: jamie@264: mib[0] = CTL_KERN; jamie@264: mib[1] = KERN_PROC; jamie@264: mib[2] = KERN_PROC_PID; jamie@264: mib[3] = getpid(); jamie@264: jamie@264: // Call sysctl. jamie@264: jamie@264: size = sizeof(info); jamie@264: if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { jamie@264: std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; jamie@264: return false; jamie@264: } jamie@264: jamie@264: // We're being debugged if the P_TRACED flag is set. jamie@264: jamie@264: return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); jamie@264: } jamie@264: } // namespace Catch jamie@264: jamie@264: #elif defined(_MSC_VER) jamie@264: extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); jamie@264: namespace Catch { jamie@264: bool isDebuggerActive() { jamie@264: return IsDebuggerPresent() != 0; jamie@264: } jamie@264: } jamie@264: #elif defined(__MINGW32__) jamie@264: extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); jamie@264: namespace Catch { jamie@264: bool isDebuggerActive() { jamie@264: return IsDebuggerPresent() != 0; jamie@264: } jamie@264: } jamie@264: #else jamie@264: namespace Catch { jamie@264: inline bool isDebuggerActive() { return false; } jamie@264: } jamie@264: #endif // Platform jamie@264: jamie@264: #ifdef CATCH_PLATFORM_WINDOWS jamie@264: extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); jamie@264: namespace Catch { jamie@264: void writeToDebugConsole( std::string const& text ) { jamie@264: ::OutputDebugStringA( text.c_str() ); jamie@264: } jamie@264: } jamie@264: #else jamie@264: namespace Catch { jamie@264: void writeToDebugConsole( std::string const& text ) { jamie@264: // !TBD: Need a version for Mac/ XCode and other IDEs jamie@264: std::cout << text; jamie@264: } jamie@264: } jamie@264: #endif // Platform jamie@264: jamie@264: // #included from: catch_tostring.hpp jamie@264: #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: namespace Detail { jamie@264: jamie@264: namespace { jamie@264: struct Endianness { jamie@264: enum Arch { Big, Little }; jamie@264: jamie@264: static Arch which() { jamie@264: union _{ jamie@264: int asInt; jamie@264: char asChar[sizeof (int)]; jamie@264: } u; jamie@264: jamie@264: u.asInt = 1; jamie@264: return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; jamie@264: } jamie@264: }; jamie@264: } jamie@264: jamie@264: std::string rawMemoryToString( const void *object, std::size_t size ) jamie@264: { jamie@264: // Reverse order for little endian architectures jamie@264: int i = 0, end = static_cast( size ), inc = 1; jamie@264: if( Endianness::which() == Endianness::Little ) { jamie@264: i = end-1; jamie@264: end = inc = -1; jamie@264: } jamie@264: jamie@264: unsigned char const *bytes = static_cast(object); jamie@264: std::ostringstream os; jamie@264: os << "0x" << std::setfill('0') << std::hex; jamie@264: for( ; i != end; i += inc ) jamie@264: os << std::setw(2) << static_cast(bytes[i]); jamie@264: return os.str(); jamie@264: } jamie@264: } jamie@264: jamie@264: std::string toString( std::string const& value ) { jamie@264: std::string s = value; jamie@264: if( getCurrentContext().getConfig()->showInvisibles() ) { jamie@264: for(size_t i = 0; i < s.size(); ++i ) { jamie@264: std::string subs; jamie@264: switch( s[i] ) { jamie@264: case '\n': subs = "\\n"; break; jamie@264: case '\t': subs = "\\t"; break; jamie@264: default: break; jamie@264: } jamie@264: if( !subs.empty() ) { jamie@264: s = s.substr( 0, i ) + subs + s.substr( i+1 ); jamie@264: ++i; jamie@264: } jamie@264: } jamie@264: } jamie@264: return "\"" + s + "\""; jamie@264: } jamie@264: std::string toString( std::wstring const& value ) { jamie@264: jamie@264: std::string s; jamie@264: s.reserve( value.size() ); jamie@264: for(size_t i = 0; i < value.size(); ++i ) jamie@264: s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; jamie@264: return toString( s ); jamie@264: } jamie@264: jamie@264: std::string toString( const char* const value ) { jamie@264: return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); jamie@264: } jamie@264: jamie@264: std::string toString( char* const value ) { jamie@264: return Catch::toString( static_cast( value ) ); jamie@264: } jamie@264: jamie@264: std::string toString( const wchar_t* const value ) jamie@264: { jamie@264: return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); jamie@264: } jamie@264: jamie@264: std::string toString( wchar_t* const value ) jamie@264: { jamie@264: return Catch::toString( static_cast( value ) ); jamie@264: } jamie@264: jamie@264: std::string toString( int value ) { jamie@264: std::ostringstream oss; jamie@264: oss << value; jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: std::string toString( unsigned long value ) { jamie@264: std::ostringstream oss; jamie@264: if( value > 8192 ) jamie@264: oss << "0x" << std::hex << value; jamie@264: else jamie@264: oss << value; jamie@264: return oss.str(); jamie@264: } jamie@264: jamie@264: std::string toString( unsigned int value ) { jamie@264: return toString( static_cast( value ) ); jamie@264: } jamie@264: jamie@264: template jamie@264: std::string fpToString( T value, int precision ) { jamie@264: std::ostringstream oss; jamie@264: oss << std::setprecision( precision ) jamie@264: << std::fixed jamie@264: << value; jamie@264: std::string d = oss.str(); jamie@264: std::size_t i = d.find_last_not_of( '0' ); jamie@264: if( i != std::string::npos && i != d.size()-1 ) { jamie@264: if( d[i] == '.' ) jamie@264: i++; jamie@264: d = d.substr( 0, i+1 ); jamie@264: } jamie@264: return d; jamie@264: } jamie@264: jamie@264: std::string toString( const double value ) { jamie@264: return fpToString( value, 10 ); jamie@264: } jamie@264: std::string toString( const float value ) { jamie@264: return fpToString( value, 5 ) + "f"; jamie@264: } jamie@264: jamie@264: std::string toString( bool value ) { jamie@264: return value ? "true" : "false"; jamie@264: } jamie@264: jamie@264: std::string toString( char value ) { jamie@264: return value < ' ' jamie@264: ? toString( static_cast( value ) ) jamie@264: : Detail::makeString( value ); jamie@264: } jamie@264: jamie@264: std::string toString( signed char value ) { jamie@264: return toString( static_cast( value ) ); jamie@264: } jamie@264: jamie@264: std::string toString( unsigned char value ) { jamie@264: return toString( static_cast( value ) ); jamie@264: } jamie@264: jamie@264: #ifdef CATCH_CONFIG_CPP11_NULLPTR jamie@264: std::string toString( std::nullptr_t ) { jamie@264: return "nullptr"; jamie@264: } jamie@264: #endif jamie@264: jamie@264: #ifdef __OBJC__ jamie@264: std::string toString( NSString const * const& nsstring ) { jamie@264: if( !nsstring ) jamie@264: return "nil"; jamie@264: return "@" + toString([nsstring UTF8String]); jamie@264: } jamie@264: std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { jamie@264: if( !nsstring ) jamie@264: return "nil"; jamie@264: return "@" + toString([nsstring UTF8String]); jamie@264: } jamie@264: std::string toString( NSObject* const& nsObject ) { jamie@264: return toString( [nsObject description] ); jamie@264: } jamie@264: #endif jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_result_builder.hpp jamie@264: #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: ResultBuilder::ResultBuilder( char const* macroName, jamie@264: SourceLineInfo const& lineInfo, jamie@264: char const* capturedExpression, jamie@264: ResultDisposition::Flags resultDisposition ) jamie@264: : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), jamie@264: m_shouldDebugBreak( false ), jamie@264: m_shouldThrow( false ) jamie@264: {} jamie@264: jamie@264: ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { jamie@264: m_data.resultType = result; jamie@264: return *this; jamie@264: } jamie@264: ResultBuilder& ResultBuilder::setResultType( bool result ) { jamie@264: m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; jamie@264: return *this; jamie@264: } jamie@264: ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { jamie@264: m_exprComponents.lhs = lhs; jamie@264: return *this; jamie@264: } jamie@264: ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { jamie@264: m_exprComponents.rhs = rhs; jamie@264: return *this; jamie@264: } jamie@264: ResultBuilder& ResultBuilder::setOp( std::string const& op ) { jamie@264: m_exprComponents.op = op; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: void ResultBuilder::endExpression() { jamie@264: m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); jamie@264: captureExpression(); jamie@264: } jamie@264: jamie@264: void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { jamie@264: m_assertionInfo.resultDisposition = resultDisposition; jamie@264: m_stream.oss << Catch::translateActiveException(); jamie@264: captureResult( ResultWas::ThrewException ); jamie@264: } jamie@264: jamie@264: void ResultBuilder::captureResult( ResultWas::OfType resultType ) { jamie@264: setResultType( resultType ); jamie@264: captureExpression(); jamie@264: } jamie@264: jamie@264: void ResultBuilder::captureExpression() { jamie@264: AssertionResult result = build(); jamie@264: getResultCapture().assertionEnded( result ); jamie@264: jamie@264: if( !result.isOk() ) { jamie@264: if( getCurrentContext().getConfig()->shouldDebugBreak() ) jamie@264: m_shouldDebugBreak = true; jamie@264: if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal ) jamie@264: m_shouldThrow = true; jamie@264: } jamie@264: } jamie@264: void ResultBuilder::react() { jamie@264: if( m_shouldThrow ) jamie@264: throw Catch::TestFailureException(); jamie@264: } jamie@264: jamie@264: bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } jamie@264: bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } jamie@264: jamie@264: AssertionResult ResultBuilder::build() const jamie@264: { jamie@264: assert( m_data.resultType != ResultWas::Unknown ); jamie@264: jamie@264: AssertionResultData data = m_data; jamie@264: jamie@264: // Flip bool results if testFalse is set jamie@264: if( m_exprComponents.testFalse ) { jamie@264: if( data.resultType == ResultWas::Ok ) jamie@264: data.resultType = ResultWas::ExpressionFailed; jamie@264: else if( data.resultType == ResultWas::ExpressionFailed ) jamie@264: data.resultType = ResultWas::Ok; jamie@264: } jamie@264: jamie@264: data.message = m_stream.oss.str(); jamie@264: data.reconstructedExpression = reconstructExpression(); jamie@264: if( m_exprComponents.testFalse ) { jamie@264: if( m_exprComponents.op == "" ) jamie@264: data.reconstructedExpression = "!" + data.reconstructedExpression; jamie@264: else jamie@264: data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; jamie@264: } jamie@264: return AssertionResult( m_assertionInfo, data ); jamie@264: } jamie@264: std::string ResultBuilder::reconstructExpression() const { jamie@264: if( m_exprComponents.op == "" ) jamie@264: return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; jamie@264: else if( m_exprComponents.op == "matches" ) jamie@264: return m_exprComponents.lhs + " " + m_exprComponents.rhs; jamie@264: else if( m_exprComponents.op != "!" ) { jamie@264: if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && jamie@264: m_exprComponents.lhs.find("\n") == std::string::npos && jamie@264: m_exprComponents.rhs.find("\n") == std::string::npos ) jamie@264: return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; jamie@264: else jamie@264: return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; jamie@264: } jamie@264: else jamie@264: return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: catch_tag_alias_registry.hpp jamie@264: #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_tag_alias_registry.h jamie@264: #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class TagAliasRegistry : public ITagAliasRegistry { jamie@264: public: jamie@264: virtual ~TagAliasRegistry(); jamie@264: virtual Option find( std::string const& alias ) const; jamie@264: virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; jamie@264: void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); jamie@264: static TagAliasRegistry& get(); jamie@264: jamie@264: private: jamie@264: std::map m_registry; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: TagAliasRegistry::~TagAliasRegistry() {} jamie@264: jamie@264: Option TagAliasRegistry::find( std::string const& alias ) const { jamie@264: std::map::const_iterator it = m_registry.find( alias ); jamie@264: if( it != m_registry.end() ) jamie@264: return it->second; jamie@264: else jamie@264: return Option(); jamie@264: } jamie@264: jamie@264: std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { jamie@264: std::string expandedTestSpec = unexpandedTestSpec; jamie@264: for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: std::size_t pos = expandedTestSpec.find( it->first ); jamie@264: if( pos != std::string::npos ) { jamie@264: expandedTestSpec = expandedTestSpec.substr( 0, pos ) + jamie@264: it->second.tag + jamie@264: expandedTestSpec.substr( pos + it->first.size() ); jamie@264: } jamie@264: } jamie@264: return expandedTestSpec; jamie@264: } jamie@264: jamie@264: void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { jamie@264: jamie@264: if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { jamie@264: std::ostringstream oss; jamie@264: oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; jamie@264: throw std::domain_error( oss.str().c_str() ); jamie@264: } jamie@264: if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { jamie@264: std::ostringstream oss; jamie@264: oss << "error: tag alias, \"" << alias << "\" already registered.\n" jamie@264: << "\tFirst seen at " << find(alias)->lineInfo << "\n" jamie@264: << "\tRedefined at " << lineInfo; jamie@264: throw std::domain_error( oss.str().c_str() ); jamie@264: } jamie@264: } jamie@264: jamie@264: TagAliasRegistry& TagAliasRegistry::get() { jamie@264: static TagAliasRegistry instance; jamie@264: return instance; jamie@264: jamie@264: } jamie@264: jamie@264: ITagAliasRegistry::~ITagAliasRegistry() {} jamie@264: ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } jamie@264: jamie@264: RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { jamie@264: try { jamie@264: TagAliasRegistry::get().add( alias, tag, lineInfo ); jamie@264: } jamie@264: catch( std::exception& ex ) { jamie@264: Colour colourGuard( Colour::Red ); jamie@264: std::cerr << ex.what() << std::endl; jamie@264: exit(1); jamie@264: } jamie@264: } jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: ../reporters/catch_reporter_xml.hpp jamie@264: #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED jamie@264: jamie@264: // #included from: catch_reporter_bases.hpp jamie@264: #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct StreamingReporterBase : SharedImpl { jamie@264: jamie@264: StreamingReporterBase( ReporterConfig const& _config ) jamie@264: : m_config( _config.fullConfig() ), jamie@264: stream( _config.stream() ) jamie@264: {} jamie@264: jamie@264: virtual ~StreamingReporterBase(); jamie@264: jamie@264: virtual void noMatchingTestCases( std::string const& ) {} jamie@264: jamie@264: virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { jamie@264: currentTestRunInfo = _testRunInfo; jamie@264: } jamie@264: virtual void testGroupStarting( GroupInfo const& _groupInfo ) { jamie@264: currentGroupInfo = _groupInfo; jamie@264: } jamie@264: jamie@264: virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { jamie@264: currentTestCaseInfo = _testInfo; jamie@264: } jamie@264: virtual void sectionStarting( SectionInfo const& _sectionInfo ) { jamie@264: m_sectionStack.push_back( _sectionInfo ); jamie@264: } jamie@264: jamie@264: virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { jamie@264: m_sectionStack.pop_back(); jamie@264: } jamie@264: virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { jamie@264: currentTestCaseInfo.reset(); jamie@264: assert( m_sectionStack.empty() ); jamie@264: } jamie@264: virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { jamie@264: currentGroupInfo.reset(); jamie@264: } jamie@264: virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { jamie@264: currentTestCaseInfo.reset(); jamie@264: currentGroupInfo.reset(); jamie@264: currentTestRunInfo.reset(); jamie@264: } jamie@264: jamie@264: Ptr m_config; jamie@264: std::ostream& stream; jamie@264: jamie@264: LazyStat currentTestRunInfo; jamie@264: LazyStat currentGroupInfo; jamie@264: LazyStat currentTestCaseInfo; jamie@264: jamie@264: std::vector m_sectionStack; jamie@264: }; jamie@264: jamie@264: struct CumulativeReporterBase : SharedImpl { jamie@264: template jamie@264: struct Node : SharedImpl<> { jamie@264: explicit Node( T const& _value ) : value( _value ) {} jamie@264: virtual ~Node() {} jamie@264: jamie@264: typedef std::vector > ChildNodes; jamie@264: T value; jamie@264: ChildNodes children; jamie@264: }; jamie@264: struct SectionNode : SharedImpl<> { jamie@264: explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} jamie@264: virtual ~SectionNode(); jamie@264: jamie@264: bool operator == ( SectionNode const& other ) const { jamie@264: return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; jamie@264: } jamie@264: bool operator == ( Ptr const& other ) const { jamie@264: return operator==( *other ); jamie@264: } jamie@264: jamie@264: SectionStats stats; jamie@264: typedef std::vector > ChildSections; jamie@264: typedef std::vector Assertions; jamie@264: ChildSections childSections; jamie@264: Assertions assertions; jamie@264: std::string stdOut; jamie@264: std::string stdErr; jamie@264: }; jamie@264: jamie@264: struct BySectionInfo { jamie@264: BySectionInfo( SectionInfo const& other ) : m_other( other ) {} jamie@264: BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} jamie@264: bool operator() ( Ptr const& node ) const { jamie@264: return node->stats.sectionInfo.lineInfo == m_other.lineInfo; jamie@264: } jamie@264: private: jamie@264: void operator=( BySectionInfo const& ); jamie@264: SectionInfo const& m_other; jamie@264: }; jamie@264: jamie@264: typedef Node TestCaseNode; jamie@264: typedef Node TestGroupNode; jamie@264: typedef Node TestRunNode; jamie@264: jamie@264: CumulativeReporterBase( ReporterConfig const& _config ) jamie@264: : m_config( _config.fullConfig() ), jamie@264: stream( _config.stream() ) jamie@264: {} jamie@264: ~CumulativeReporterBase(); jamie@264: jamie@264: virtual void testRunStarting( TestRunInfo const& ) {} jamie@264: virtual void testGroupStarting( GroupInfo const& ) {} jamie@264: jamie@264: virtual void testCaseStarting( TestCaseInfo const& ) {} jamie@264: jamie@264: virtual void sectionStarting( SectionInfo const& sectionInfo ) { jamie@264: SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); jamie@264: Ptr node; jamie@264: if( m_sectionStack.empty() ) { jamie@264: if( !m_rootSection ) jamie@264: m_rootSection = new SectionNode( incompleteStats ); jamie@264: node = m_rootSection; jamie@264: } jamie@264: else { jamie@264: SectionNode& parentNode = *m_sectionStack.back(); jamie@264: SectionNode::ChildSections::const_iterator it = jamie@264: std::find_if( parentNode.childSections.begin(), jamie@264: parentNode.childSections.end(), jamie@264: BySectionInfo( sectionInfo ) ); jamie@264: if( it == parentNode.childSections.end() ) { jamie@264: node = new SectionNode( incompleteStats ); jamie@264: parentNode.childSections.push_back( node ); jamie@264: } jamie@264: else jamie@264: node = *it; jamie@264: } jamie@264: m_sectionStack.push_back( node ); jamie@264: m_deepestSection = node; jamie@264: } jamie@264: jamie@264: virtual void assertionStarting( AssertionInfo const& ) {} jamie@264: jamie@264: virtual bool assertionEnded( AssertionStats const& assertionStats ) { jamie@264: assert( !m_sectionStack.empty() ); jamie@264: SectionNode& sectionNode = *m_sectionStack.back(); jamie@264: sectionNode.assertions.push_back( assertionStats ); jamie@264: return true; jamie@264: } jamie@264: virtual void sectionEnded( SectionStats const& sectionStats ) { jamie@264: assert( !m_sectionStack.empty() ); jamie@264: SectionNode& node = *m_sectionStack.back(); jamie@264: node.stats = sectionStats; jamie@264: m_sectionStack.pop_back(); jamie@264: } jamie@264: virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { jamie@264: Ptr node = new TestCaseNode( testCaseStats ); jamie@264: assert( m_sectionStack.size() == 0 ); jamie@264: node->children.push_back( m_rootSection ); jamie@264: m_testCases.push_back( node ); jamie@264: m_rootSection.reset(); jamie@264: jamie@264: assert( m_deepestSection ); jamie@264: m_deepestSection->stdOut = testCaseStats.stdOut; jamie@264: m_deepestSection->stdErr = testCaseStats.stdErr; jamie@264: } jamie@264: virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { jamie@264: Ptr node = new TestGroupNode( testGroupStats ); jamie@264: node->children.swap( m_testCases ); jamie@264: m_testGroups.push_back( node ); jamie@264: } jamie@264: virtual void testRunEnded( TestRunStats const& testRunStats ) { jamie@264: Ptr node = new TestRunNode( testRunStats ); jamie@264: node->children.swap( m_testGroups ); jamie@264: m_testRuns.push_back( node ); jamie@264: testRunEndedCumulative(); jamie@264: } jamie@264: virtual void testRunEndedCumulative() = 0; jamie@264: jamie@264: Ptr m_config; jamie@264: std::ostream& stream; jamie@264: std::vector m_assertions; jamie@264: std::vector > > m_sections; jamie@264: std::vector > m_testCases; jamie@264: std::vector > m_testGroups; jamie@264: jamie@264: std::vector > m_testRuns; jamie@264: jamie@264: Ptr m_rootSection; jamie@264: Ptr m_deepestSection; jamie@264: std::vector > m_sectionStack; jamie@264: jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: ../internal/catch_reporter_registrars.hpp jamie@264: #define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: template jamie@264: class LegacyReporterRegistrar { jamie@264: jamie@264: class ReporterFactory : public IReporterFactory { jamie@264: virtual IStreamingReporter* create( ReporterConfig const& config ) const { jamie@264: return new LegacyReporterAdapter( new T( config ) ); jamie@264: } jamie@264: jamie@264: virtual std::string getDescription() const { jamie@264: return T::getDescription(); jamie@264: } jamie@264: }; jamie@264: jamie@264: public: jamie@264: jamie@264: LegacyReporterRegistrar( std::string const& name ) { jamie@264: getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); jamie@264: } jamie@264: }; jamie@264: jamie@264: template jamie@264: class ReporterRegistrar { jamie@264: jamie@264: class ReporterFactory : public IReporterFactory { jamie@264: jamie@264: // *** Please Note ***: jamie@264: // - If you end up here looking at a compiler error because it's trying to register jamie@264: // your custom reporter class be aware that the native reporter interface has changed jamie@264: // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via jamie@264: // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. jamie@264: // However please consider updating to the new interface as the old one is now jamie@264: // deprecated and will probably be removed quite soon! jamie@264: // Please contact me via github if you have any questions at all about this. jamie@264: // In fact, ideally, please contact me anyway to let me know you've hit this - as I have jamie@264: // no idea who is actually using custom reporters at all (possibly no-one!). jamie@264: // The new interface is designed to minimise exposure to interface changes in the future. jamie@264: virtual IStreamingReporter* create( ReporterConfig const& config ) const { jamie@264: return new T( config ); jamie@264: } jamie@264: jamie@264: virtual std::string getDescription() const { jamie@264: return T::getDescription(); jamie@264: } jamie@264: }; jamie@264: jamie@264: public: jamie@264: jamie@264: ReporterRegistrar( std::string const& name ) { jamie@264: getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); jamie@264: } jamie@264: }; jamie@264: } jamie@264: jamie@264: #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ jamie@264: namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } jamie@264: #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ jamie@264: namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } jamie@264: jamie@264: // #included from: ../internal/catch_xmlwriter.hpp jamie@264: #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class XmlWriter { jamie@264: public: jamie@264: jamie@264: class ScopedElement { jamie@264: public: jamie@264: ScopedElement( XmlWriter* writer ) jamie@264: : m_writer( writer ) jamie@264: {} jamie@264: jamie@264: ScopedElement( ScopedElement const& other ) jamie@264: : m_writer( other.m_writer ){ jamie@264: other.m_writer = NULL; jamie@264: } jamie@264: jamie@264: ~ScopedElement() { jamie@264: if( m_writer ) jamie@264: m_writer->endElement(); jamie@264: } jamie@264: jamie@264: ScopedElement& writeText( std::string const& text, bool indent = true ) { jamie@264: m_writer->writeText( text, indent ); jamie@264: return *this; jamie@264: } jamie@264: jamie@264: template jamie@264: ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { jamie@264: m_writer->writeAttribute( name, attribute ); jamie@264: return *this; jamie@264: } jamie@264: jamie@264: private: jamie@264: mutable XmlWriter* m_writer; jamie@264: }; jamie@264: jamie@264: XmlWriter() jamie@264: : m_tagIsOpen( false ), jamie@264: m_needsNewline( false ), jamie@264: m_os( &std::cout ) jamie@264: {} jamie@264: jamie@264: XmlWriter( std::ostream& os ) jamie@264: : m_tagIsOpen( false ), jamie@264: m_needsNewline( false ), jamie@264: m_os( &os ) jamie@264: {} jamie@264: jamie@264: ~XmlWriter() { jamie@264: while( !m_tags.empty() ) jamie@264: endElement(); jamie@264: } jamie@264: jamie@264: //# ifndef CATCH_CPP11_OR_GREATER jamie@264: // XmlWriter& operator = ( XmlWriter const& other ) { jamie@264: // XmlWriter temp( other ); jamie@264: // swap( temp ); jamie@264: // return *this; jamie@264: // } jamie@264: //# else jamie@264: // XmlWriter( XmlWriter const& ) = default; jamie@264: // XmlWriter( XmlWriter && ) = default; jamie@264: // XmlWriter& operator = ( XmlWriter const& ) = default; jamie@264: // XmlWriter& operator = ( XmlWriter && ) = default; jamie@264: //# endif jamie@264: // jamie@264: // void swap( XmlWriter& other ) { jamie@264: // std::swap( m_tagIsOpen, other.m_tagIsOpen ); jamie@264: // std::swap( m_needsNewline, other.m_needsNewline ); jamie@264: // std::swap( m_tags, other.m_tags ); jamie@264: // std::swap( m_indent, other.m_indent ); jamie@264: // std::swap( m_os, other.m_os ); jamie@264: // } jamie@264: jamie@264: XmlWriter& startElement( std::string const& name ) { jamie@264: ensureTagClosed(); jamie@264: newlineIfNecessary(); jamie@264: stream() << m_indent << "<" << name; jamie@264: m_tags.push_back( name ); jamie@264: m_indent += " "; jamie@264: m_tagIsOpen = true; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: ScopedElement scopedElement( std::string const& name ) { jamie@264: ScopedElement scoped( this ); jamie@264: startElement( name ); jamie@264: return scoped; jamie@264: } jamie@264: jamie@264: XmlWriter& endElement() { jamie@264: newlineIfNecessary(); jamie@264: m_indent = m_indent.substr( 0, m_indent.size()-2 ); jamie@264: if( m_tagIsOpen ) { jamie@264: stream() << "/>\n"; jamie@264: m_tagIsOpen = false; jamie@264: } jamie@264: else { jamie@264: stream() << m_indent << "\n"; jamie@264: } jamie@264: m_tags.pop_back(); jamie@264: return *this; jamie@264: } jamie@264: jamie@264: XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { jamie@264: if( !name.empty() && !attribute.empty() ) { jamie@264: stream() << " " << name << "=\""; jamie@264: writeEncodedText( attribute ); jamie@264: stream() << "\""; jamie@264: } jamie@264: return *this; jamie@264: } jamie@264: jamie@264: XmlWriter& writeAttribute( std::string const& name, bool attribute ) { jamie@264: stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: template jamie@264: XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { jamie@264: if( !name.empty() ) jamie@264: stream() << " " << name << "=\"" << attribute << "\""; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: XmlWriter& writeText( std::string const& text, bool indent = true ) { jamie@264: if( !text.empty() ){ jamie@264: bool tagWasOpen = m_tagIsOpen; jamie@264: ensureTagClosed(); jamie@264: if( tagWasOpen && indent ) jamie@264: stream() << m_indent; jamie@264: writeEncodedText( text ); jamie@264: m_needsNewline = true; jamie@264: } jamie@264: return *this; jamie@264: } jamie@264: jamie@264: XmlWriter& writeComment( std::string const& text ) { jamie@264: ensureTagClosed(); jamie@264: stream() << m_indent << ""; jamie@264: m_needsNewline = true; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: XmlWriter& writeBlankLine() { jamie@264: ensureTagClosed(); jamie@264: stream() << "\n"; jamie@264: return *this; jamie@264: } jamie@264: jamie@264: void setStream( std::ostream& os ) { jamie@264: m_os = &os; jamie@264: } jamie@264: jamie@264: private: jamie@264: XmlWriter( XmlWriter const& ); jamie@264: void operator=( XmlWriter const& ); jamie@264: jamie@264: std::ostream& stream() { jamie@264: return *m_os; jamie@264: } jamie@264: jamie@264: void ensureTagClosed() { jamie@264: if( m_tagIsOpen ) { jamie@264: stream() << ">\n"; jamie@264: m_tagIsOpen = false; jamie@264: } jamie@264: } jamie@264: jamie@264: void newlineIfNecessary() { jamie@264: if( m_needsNewline ) { jamie@264: stream() << "\n"; jamie@264: m_needsNewline = false; jamie@264: } jamie@264: } jamie@264: jamie@264: void writeEncodedText( std::string const& text ) { jamie@264: static const char* charsToEncode = "<&\""; jamie@264: std::string mtext = text; jamie@264: std::string::size_type pos = mtext.find_first_of( charsToEncode ); jamie@264: while( pos != std::string::npos ) { jamie@264: stream() << mtext.substr( 0, pos ); jamie@264: jamie@264: switch( mtext[pos] ) { jamie@264: case '<': jamie@264: stream() << "<"; jamie@264: break; jamie@264: case '&': jamie@264: stream() << "&"; jamie@264: break; jamie@264: case '\"': jamie@264: stream() << """; jamie@264: break; jamie@264: } jamie@264: mtext = mtext.substr( pos+1 ); jamie@264: pos = mtext.find_first_of( charsToEncode ); jamie@264: } jamie@264: stream() << mtext; jamie@264: } jamie@264: jamie@264: bool m_tagIsOpen; jamie@264: bool m_needsNewline; jamie@264: std::vector m_tags; jamie@264: std::string m_indent; jamie@264: std::ostream* m_os; jamie@264: }; jamie@264: jamie@264: } jamie@264: namespace Catch { jamie@264: class XmlReporter : public SharedImpl { jamie@264: public: jamie@264: XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {} jamie@264: jamie@264: static std::string getDescription() { jamie@264: return "Reports test results as an XML document"; jamie@264: } jamie@264: virtual ~XmlReporter(); jamie@264: jamie@264: private: // IReporter jamie@264: jamie@264: virtual bool shouldRedirectStdout() const { jamie@264: return true; jamie@264: } jamie@264: jamie@264: virtual void StartTesting() { jamie@264: m_xml.setStream( m_config.stream() ); jamie@264: m_xml.startElement( "Catch" ); jamie@264: if( !m_config.fullConfig()->name().empty() ) jamie@264: m_xml.writeAttribute( "name", m_config.fullConfig()->name() ); jamie@264: } jamie@264: jamie@264: virtual void EndTesting( const Totals& totals ) { jamie@264: m_xml.scopedElement( "OverallResults" ) jamie@264: .writeAttribute( "successes", totals.assertions.passed ) jamie@264: .writeAttribute( "failures", totals.assertions.failed ) jamie@264: .writeAttribute( "expectedFailures", totals.assertions.failedButOk ); jamie@264: m_xml.endElement(); jamie@264: } jamie@264: jamie@264: virtual void StartGroup( const std::string& groupName ) { jamie@264: m_xml.startElement( "Group" ) jamie@264: .writeAttribute( "name", groupName ); jamie@264: } jamie@264: jamie@264: virtual void EndGroup( const std::string&, const Totals& totals ) { jamie@264: m_xml.scopedElement( "OverallResults" ) jamie@264: .writeAttribute( "successes", totals.assertions.passed ) jamie@264: .writeAttribute( "failures", totals.assertions.failed ) jamie@264: .writeAttribute( "expectedFailures", totals.assertions.failedButOk ); jamie@264: m_xml.endElement(); jamie@264: } jamie@264: jamie@264: virtual void StartSection( const std::string& sectionName, const std::string& description ) { jamie@264: if( m_sectionDepth++ > 0 ) { jamie@264: m_xml.startElement( "Section" ) jamie@264: .writeAttribute( "name", trim( sectionName ) ) jamie@264: .writeAttribute( "description", description ); jamie@264: } jamie@264: } jamie@264: virtual void NoAssertionsInSection( const std::string& ) {} jamie@264: virtual void NoAssertionsInTestCase( const std::string& ) {} jamie@264: jamie@264: virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) { jamie@264: if( --m_sectionDepth > 0 ) { jamie@264: m_xml.scopedElement( "OverallResults" ) jamie@264: .writeAttribute( "successes", assertions.passed ) jamie@264: .writeAttribute( "failures", assertions.failed ) jamie@264: .writeAttribute( "expectedFailures", assertions.failedButOk ); jamie@264: m_xml.endElement(); jamie@264: } jamie@264: } jamie@264: jamie@264: virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) { jamie@264: m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); jamie@264: m_currentTestSuccess = true; jamie@264: } jamie@264: jamie@264: virtual void Result( const Catch::AssertionResult& assertionResult ) { jamie@264: if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok ) jamie@264: return; jamie@264: jamie@264: if( assertionResult.hasExpression() ) { jamie@264: m_xml.startElement( "Expression" ) jamie@264: .writeAttribute( "success", assertionResult.succeeded() ) jamie@264: .writeAttribute( "filename", assertionResult.getSourceInfo().file ) jamie@264: .writeAttribute( "line", assertionResult.getSourceInfo().line ); jamie@264: jamie@264: m_xml.scopedElement( "Original" ) jamie@264: .writeText( assertionResult.getExpression() ); jamie@264: m_xml.scopedElement( "Expanded" ) jamie@264: .writeText( assertionResult.getExpandedExpression() ); jamie@264: m_currentTestSuccess &= assertionResult.succeeded(); jamie@264: } jamie@264: jamie@264: switch( assertionResult.getResultType() ) { jamie@264: case ResultWas::ThrewException: jamie@264: m_xml.scopedElement( "Exception" ) jamie@264: .writeAttribute( "filename", assertionResult.getSourceInfo().file ) jamie@264: .writeAttribute( "line", assertionResult.getSourceInfo().line ) jamie@264: .writeText( assertionResult.getMessage() ); jamie@264: m_currentTestSuccess = false; jamie@264: break; jamie@264: case ResultWas::Info: jamie@264: m_xml.scopedElement( "Info" ) jamie@264: .writeText( assertionResult.getMessage() ); jamie@264: break; jamie@264: case ResultWas::Warning: jamie@264: m_xml.scopedElement( "Warning" ) jamie@264: .writeText( assertionResult.getMessage() ); jamie@264: break; jamie@264: case ResultWas::ExplicitFailure: jamie@264: m_xml.scopedElement( "Failure" ) jamie@264: .writeText( assertionResult.getMessage() ); jamie@264: m_currentTestSuccess = false; jamie@264: break; jamie@264: case ResultWas::Unknown: jamie@264: case ResultWas::Ok: jamie@264: case ResultWas::FailureBit: jamie@264: case ResultWas::ExpressionFailed: jamie@264: case ResultWas::Exception: jamie@264: case ResultWas::DidntThrowException: jamie@264: break; jamie@264: } jamie@264: if( assertionResult.hasExpression() ) jamie@264: m_xml.endElement(); jamie@264: } jamie@264: jamie@264: virtual void Aborted() { jamie@264: // !TBD jamie@264: } jamie@264: jamie@264: virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) { jamie@264: m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess ); jamie@264: m_xml.endElement(); jamie@264: } jamie@264: jamie@264: private: jamie@264: ReporterConfig m_config; jamie@264: bool m_currentTestSuccess; jamie@264: XmlWriter m_xml; jamie@264: int m_sectionDepth; jamie@264: }; jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: ../reporters/catch_reporter_junit.hpp jamie@264: #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: class JunitReporter : public CumulativeReporterBase { jamie@264: public: jamie@264: JunitReporter( ReporterConfig const& _config ) jamie@264: : CumulativeReporterBase( _config ), jamie@264: xml( _config.stream() ) jamie@264: {} jamie@264: jamie@264: ~JunitReporter(); jamie@264: jamie@264: static std::string getDescription() { jamie@264: return "Reports test results in an XML format that looks like Ant's junitreport target"; jamie@264: } jamie@264: jamie@264: virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} jamie@264: jamie@264: virtual ReporterPreferences getPreferences() const { jamie@264: ReporterPreferences prefs; jamie@264: prefs.shouldRedirectStdOut = true; jamie@264: return prefs; jamie@264: } jamie@264: jamie@264: virtual void testRunStarting( TestRunInfo const& runInfo ) { jamie@264: CumulativeReporterBase::testRunStarting( runInfo ); jamie@264: xml.startElement( "testsuites" ); jamie@264: } jamie@264: jamie@264: virtual void testGroupStarting( GroupInfo const& groupInfo ) { jamie@264: suiteTimer.start(); jamie@264: stdOutForSuite.str(""); jamie@264: stdErrForSuite.str(""); jamie@264: unexpectedExceptions = 0; jamie@264: CumulativeReporterBase::testGroupStarting( groupInfo ); jamie@264: } jamie@264: jamie@264: virtual bool assertionEnded( AssertionStats const& assertionStats ) { jamie@264: if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) jamie@264: unexpectedExceptions++; jamie@264: return CumulativeReporterBase::assertionEnded( assertionStats ); jamie@264: } jamie@264: jamie@264: virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { jamie@264: stdOutForSuite << testCaseStats.stdOut; jamie@264: stdErrForSuite << testCaseStats.stdErr; jamie@264: CumulativeReporterBase::testCaseEnded( testCaseStats ); jamie@264: } jamie@264: jamie@264: virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { jamie@264: double suiteTime = suiteTimer.getElapsedSeconds(); jamie@264: CumulativeReporterBase::testGroupEnded( testGroupStats ); jamie@264: writeGroup( *m_testGroups.back(), suiteTime ); jamie@264: } jamie@264: jamie@264: virtual void testRunEndedCumulative() { jamie@264: xml.endElement(); jamie@264: } jamie@264: jamie@264: void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { jamie@264: XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); jamie@264: TestGroupStats const& stats = groupNode.value; jamie@264: xml.writeAttribute( "name", stats.groupInfo.name ); jamie@264: xml.writeAttribute( "errors", unexpectedExceptions ); jamie@264: xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); jamie@264: xml.writeAttribute( "tests", stats.totals.assertions.total() ); jamie@264: xml.writeAttribute( "hostname", "tbd" ); // !TBD jamie@264: if( m_config->showDurations() == ShowDurations::Never ) jamie@264: xml.writeAttribute( "time", "" ); jamie@264: else jamie@264: xml.writeAttribute( "time", suiteTime ); jamie@264: xml.writeAttribute( "timestamp", "tbd" ); // !TBD jamie@264: jamie@264: // Write test cases jamie@264: for( TestGroupNode::ChildNodes::const_iterator jamie@264: it = groupNode.children.begin(), itEnd = groupNode.children.end(); jamie@264: it != itEnd; jamie@264: ++it ) jamie@264: writeTestCase( **it ); jamie@264: jamie@264: xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); jamie@264: xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); jamie@264: } jamie@264: jamie@264: void writeTestCase( TestCaseNode const& testCaseNode ) { jamie@264: TestCaseStats const& stats = testCaseNode.value; jamie@264: jamie@264: // All test cases have exactly one section - which represents the jamie@264: // test case itself. That section may have 0-n nested sections jamie@264: assert( testCaseNode.children.size() == 1 ); jamie@264: SectionNode const& rootSection = *testCaseNode.children.front(); jamie@264: jamie@264: std::string className = stats.testInfo.className; jamie@264: jamie@264: if( className.empty() ) { jamie@264: if( rootSection.childSections.empty() ) jamie@264: className = "global"; jamie@264: } jamie@264: writeSection( className, "", rootSection ); jamie@264: } jamie@264: jamie@264: void writeSection( std::string const& className, jamie@264: std::string const& rootName, jamie@264: SectionNode const& sectionNode ) { jamie@264: std::string name = trim( sectionNode.stats.sectionInfo.name ); jamie@264: if( !rootName.empty() ) jamie@264: name = rootName + "/" + name; jamie@264: jamie@264: if( !sectionNode.assertions.empty() || jamie@264: !sectionNode.stdOut.empty() || jamie@264: !sectionNode.stdErr.empty() ) { jamie@264: XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); jamie@264: if( className.empty() ) { jamie@264: xml.writeAttribute( "classname", name ); jamie@264: xml.writeAttribute( "name", "root" ); jamie@264: } jamie@264: else { jamie@264: xml.writeAttribute( "classname", className ); jamie@264: xml.writeAttribute( "name", name ); jamie@264: } jamie@264: xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) ); jamie@264: jamie@264: writeAssertions( sectionNode ); jamie@264: jamie@264: if( !sectionNode.stdOut.empty() ) jamie@264: xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); jamie@264: if( !sectionNode.stdErr.empty() ) jamie@264: xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); jamie@264: } jamie@264: for( SectionNode::ChildSections::const_iterator jamie@264: it = sectionNode.childSections.begin(), jamie@264: itEnd = sectionNode.childSections.end(); jamie@264: it != itEnd; jamie@264: ++it ) jamie@264: if( className.empty() ) jamie@264: writeSection( name, "", **it ); jamie@264: else jamie@264: writeSection( className, name, **it ); jamie@264: } jamie@264: jamie@264: void writeAssertions( SectionNode const& sectionNode ) { jamie@264: for( SectionNode::Assertions::const_iterator jamie@264: it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); jamie@264: it != itEnd; jamie@264: ++it ) jamie@264: writeAssertion( *it ); jamie@264: } jamie@264: void writeAssertion( AssertionStats const& stats ) { jamie@264: AssertionResult const& result = stats.assertionResult; jamie@264: if( !result.isOk() ) { jamie@264: std::string elementName; jamie@264: switch( result.getResultType() ) { jamie@264: case ResultWas::ThrewException: jamie@264: elementName = "error"; jamie@264: break; jamie@264: case ResultWas::ExplicitFailure: jamie@264: elementName = "failure"; jamie@264: break; jamie@264: case ResultWas::ExpressionFailed: jamie@264: elementName = "failure"; jamie@264: break; jamie@264: case ResultWas::DidntThrowException: jamie@264: elementName = "failure"; jamie@264: break; jamie@264: jamie@264: // We should never see these here: jamie@264: case ResultWas::Info: jamie@264: case ResultWas::Warning: jamie@264: case ResultWas::Ok: jamie@264: case ResultWas::Unknown: jamie@264: case ResultWas::FailureBit: jamie@264: case ResultWas::Exception: jamie@264: elementName = "internalError"; jamie@264: break; jamie@264: } jamie@264: jamie@264: XmlWriter::ScopedElement e = xml.scopedElement( elementName ); jamie@264: jamie@264: xml.writeAttribute( "message", result.getExpandedExpression() ); jamie@264: xml.writeAttribute( "type", result.getTestMacroName() ); jamie@264: jamie@264: std::ostringstream oss; jamie@264: if( !result.getMessage().empty() ) jamie@264: oss << result.getMessage() << "\n"; jamie@264: for( std::vector::const_iterator jamie@264: it = stats.infoMessages.begin(), jamie@264: itEnd = stats.infoMessages.end(); jamie@264: it != itEnd; jamie@264: ++it ) jamie@264: if( it->type == ResultWas::Info ) jamie@264: oss << it->message << "\n"; jamie@264: jamie@264: oss << "at " << result.getSourceInfo(); jamie@264: xml.writeText( oss.str(), false ); jamie@264: } jamie@264: } jamie@264: jamie@264: XmlWriter xml; jamie@264: Timer suiteTimer; jamie@264: std::ostringstream stdOutForSuite; jamie@264: std::ostringstream stdErrForSuite; jamie@264: unsigned int unexpectedExceptions; jamie@264: }; jamie@264: jamie@264: INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: ../reporters/catch_reporter_console.hpp jamie@264: #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED jamie@264: jamie@264: #include jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct ConsoleReporter : StreamingReporterBase { jamie@264: ConsoleReporter( ReporterConfig const& _config ) jamie@264: : StreamingReporterBase( _config ), jamie@264: m_headerPrinted( false ) jamie@264: {} jamie@264: jamie@264: virtual ~ConsoleReporter(); jamie@264: static std::string getDescription() { jamie@264: return "Reports test results as plain lines of text"; jamie@264: } jamie@264: virtual ReporterPreferences getPreferences() const { jamie@264: ReporterPreferences prefs; jamie@264: prefs.shouldRedirectStdOut = false; jamie@264: return prefs; jamie@264: } jamie@264: jamie@264: virtual void noMatchingTestCases( std::string const& spec ) { jamie@264: stream << "No test cases matched '" << spec << "'" << std::endl; jamie@264: } jamie@264: jamie@264: virtual void assertionStarting( AssertionInfo const& ) { jamie@264: } jamie@264: jamie@264: virtual bool assertionEnded( AssertionStats const& _assertionStats ) { jamie@264: AssertionResult const& result = _assertionStats.assertionResult; jamie@264: jamie@264: bool printInfoMessages = true; jamie@264: jamie@264: // Drop out if result was successful and we're not printing those jamie@264: if( !m_config->includeSuccessfulResults() && result.isOk() ) { jamie@264: if( result.getResultType() != ResultWas::Warning ) jamie@264: return false; jamie@264: printInfoMessages = false; jamie@264: } jamie@264: jamie@264: lazyPrint(); jamie@264: jamie@264: AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); jamie@264: printer.print(); jamie@264: stream << std::endl; jamie@264: return true; jamie@264: } jamie@264: jamie@264: virtual void sectionStarting( SectionInfo const& _sectionInfo ) { jamie@264: m_headerPrinted = false; jamie@264: StreamingReporterBase::sectionStarting( _sectionInfo ); jamie@264: } jamie@264: virtual void sectionEnded( SectionStats const& _sectionStats ) { jamie@264: if( _sectionStats.missingAssertions ) { jamie@264: lazyPrint(); jamie@264: Colour colour( Colour::ResultError ); jamie@264: if( m_sectionStack.size() > 1 ) jamie@264: stream << "\nNo assertions in section"; jamie@264: else jamie@264: stream << "\nNo assertions in test case"; jamie@264: stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; jamie@264: } jamie@264: if( m_headerPrinted ) { jamie@264: if( m_config->showDurations() == ShowDurations::Always ) jamie@264: stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; jamie@264: m_headerPrinted = false; jamie@264: } jamie@264: else { jamie@264: if( m_config->showDurations() == ShowDurations::Always ) jamie@264: stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; jamie@264: } jamie@264: StreamingReporterBase::sectionEnded( _sectionStats ); jamie@264: } jamie@264: jamie@264: virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { jamie@264: StreamingReporterBase::testCaseEnded( _testCaseStats ); jamie@264: m_headerPrinted = false; jamie@264: } jamie@264: virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { jamie@264: if( currentGroupInfo.used ) { jamie@264: printSummaryDivider(); jamie@264: stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; jamie@264: printTotals( _testGroupStats.totals ); jamie@264: stream << "\n" << std::endl; jamie@264: } jamie@264: StreamingReporterBase::testGroupEnded( _testGroupStats ); jamie@264: } jamie@264: virtual void testRunEnded( TestRunStats const& _testRunStats ) { jamie@264: printTotalsDivider( _testRunStats.totals ); jamie@264: printTotals( _testRunStats.totals ); jamie@264: stream << std::endl; jamie@264: StreamingReporterBase::testRunEnded( _testRunStats ); jamie@264: } jamie@264: jamie@264: private: jamie@264: jamie@264: class AssertionPrinter { jamie@264: void operator= ( AssertionPrinter const& ); jamie@264: public: jamie@264: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) jamie@264: : stream( _stream ), jamie@264: stats( _stats ), jamie@264: result( _stats.assertionResult ), jamie@264: colour( Colour::None ), jamie@264: message( result.getMessage() ), jamie@264: messages( _stats.infoMessages ), jamie@264: printInfoMessages( _printInfoMessages ) jamie@264: { jamie@264: switch( result.getResultType() ) { jamie@264: case ResultWas::Ok: jamie@264: colour = Colour::Success; jamie@264: passOrFail = "PASSED"; jamie@264: //if( result.hasMessage() ) jamie@264: if( _stats.infoMessages.size() == 1 ) jamie@264: messageLabel = "with message"; jamie@264: if( _stats.infoMessages.size() > 1 ) jamie@264: messageLabel = "with messages"; jamie@264: break; jamie@264: case ResultWas::ExpressionFailed: jamie@264: if( result.isOk() ) { jamie@264: colour = Colour::Success; jamie@264: passOrFail = "FAILED - but was ok"; jamie@264: } jamie@264: else { jamie@264: colour = Colour::Error; jamie@264: passOrFail = "FAILED"; jamie@264: } jamie@264: if( _stats.infoMessages.size() == 1 ) jamie@264: messageLabel = "with message"; jamie@264: if( _stats.infoMessages.size() > 1 ) jamie@264: messageLabel = "with messages"; jamie@264: break; jamie@264: case ResultWas::ThrewException: jamie@264: colour = Colour::Error; jamie@264: passOrFail = "FAILED"; jamie@264: messageLabel = "due to unexpected exception with message"; jamie@264: break; jamie@264: case ResultWas::DidntThrowException: jamie@264: colour = Colour::Error; jamie@264: passOrFail = "FAILED"; jamie@264: messageLabel = "because no exception was thrown where one was expected"; jamie@264: break; jamie@264: case ResultWas::Info: jamie@264: messageLabel = "info"; jamie@264: break; jamie@264: case ResultWas::Warning: jamie@264: messageLabel = "warning"; jamie@264: break; jamie@264: case ResultWas::ExplicitFailure: jamie@264: passOrFail = "FAILED"; jamie@264: colour = Colour::Error; jamie@264: if( _stats.infoMessages.size() == 1 ) jamie@264: messageLabel = "explicitly with message"; jamie@264: if( _stats.infoMessages.size() > 1 ) jamie@264: messageLabel = "explicitly with messages"; jamie@264: break; jamie@264: // These cases are here to prevent compiler warnings jamie@264: case ResultWas::Unknown: jamie@264: case ResultWas::FailureBit: jamie@264: case ResultWas::Exception: jamie@264: passOrFail = "** internal error **"; jamie@264: colour = Colour::Error; jamie@264: break; jamie@264: } jamie@264: } jamie@264: jamie@264: void print() const { jamie@264: printSourceInfo(); jamie@264: if( stats.totals.assertions.total() > 0 ) { jamie@264: if( result.isOk() ) jamie@264: stream << "\n"; jamie@264: printResultType(); jamie@264: printOriginalExpression(); jamie@264: printReconstructedExpression(); jamie@264: } jamie@264: else { jamie@264: stream << "\n"; jamie@264: } jamie@264: printMessage(); jamie@264: } jamie@264: jamie@264: private: jamie@264: void printResultType() const { jamie@264: if( !passOrFail.empty() ) { jamie@264: Colour colourGuard( colour ); jamie@264: stream << passOrFail << ":\n"; jamie@264: } jamie@264: } jamie@264: void printOriginalExpression() const { jamie@264: if( result.hasExpression() ) { jamie@264: Colour colourGuard( Colour::OriginalExpression ); jamie@264: stream << " "; jamie@264: stream << result.getExpressionInMacro(); jamie@264: stream << "\n"; jamie@264: } jamie@264: } jamie@264: void printReconstructedExpression() const { jamie@264: if( result.hasExpandedExpression() ) { jamie@264: stream << "with expansion:\n"; jamie@264: Colour colourGuard( Colour::ReconstructedExpression ); jamie@264: stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; jamie@264: } jamie@264: } jamie@264: void printMessage() const { jamie@264: if( !messageLabel.empty() ) jamie@264: stream << messageLabel << ":" << "\n"; jamie@264: for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); jamie@264: it != itEnd; jamie@264: ++it ) { jamie@264: // If this assertion is a warning ignore any INFO messages jamie@264: if( printInfoMessages || it->type != ResultWas::Info ) jamie@264: stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; jamie@264: } jamie@264: } jamie@264: void printSourceInfo() const { jamie@264: Colour colourGuard( Colour::FileName ); jamie@264: stream << result.getSourceInfo() << ": "; jamie@264: } jamie@264: jamie@264: std::ostream& stream; jamie@264: AssertionStats const& stats; jamie@264: AssertionResult const& result; jamie@264: Colour::Code colour; jamie@264: std::string passOrFail; jamie@264: std::string messageLabel; jamie@264: std::string message; jamie@264: std::vector messages; jamie@264: bool printInfoMessages; jamie@264: }; jamie@264: jamie@264: void lazyPrint() { jamie@264: jamie@264: if( !currentTestRunInfo.used ) jamie@264: lazyPrintRunInfo(); jamie@264: if( !currentGroupInfo.used ) jamie@264: lazyPrintGroupInfo(); jamie@264: jamie@264: if( !m_headerPrinted ) { jamie@264: printTestCaseAndSectionHeader(); jamie@264: m_headerPrinted = true; jamie@264: } jamie@264: } jamie@264: void lazyPrintRunInfo() { jamie@264: stream << "\n" << getLineOfChars<'~'>() << "\n"; jamie@264: Colour colour( Colour::SecondaryText ); jamie@264: stream << currentTestRunInfo->name jamie@264: << " is a Catch v" << libraryVersion.majorVersion << "." jamie@264: << libraryVersion.minorVersion << " b" jamie@264: << libraryVersion.buildNumber; jamie@264: if( libraryVersion.branchName != std::string( "master" ) ) jamie@264: stream << " (" << libraryVersion.branchName << ")"; jamie@264: stream << " host application.\n" jamie@264: << "Run with -? for options\n\n"; jamie@264: jamie@264: currentTestRunInfo.used = true; jamie@264: } jamie@264: void lazyPrintGroupInfo() { jamie@264: if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { jamie@264: printClosedHeader( "Group: " + currentGroupInfo->name ); jamie@264: currentGroupInfo.used = true; jamie@264: } jamie@264: } jamie@264: void printTestCaseAndSectionHeader() { jamie@264: assert( !m_sectionStack.empty() ); jamie@264: printOpenHeader( currentTestCaseInfo->name ); jamie@264: jamie@264: if( m_sectionStack.size() > 1 ) { jamie@264: Colour colourGuard( Colour::Headers ); jamie@264: jamie@264: std::vector::const_iterator jamie@264: it = m_sectionStack.begin()+1, // Skip first section (test case) jamie@264: itEnd = m_sectionStack.end(); jamie@264: for( ; it != itEnd; ++it ) jamie@264: printHeaderString( it->name, 2 ); jamie@264: } jamie@264: jamie@264: SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; jamie@264: jamie@264: if( !lineInfo.empty() ){ jamie@264: stream << getLineOfChars<'-'>() << "\n"; jamie@264: Colour colourGuard( Colour::FileName ); jamie@264: stream << lineInfo << "\n"; jamie@264: } jamie@264: stream << getLineOfChars<'.'>() << "\n" << std::endl; jamie@264: } jamie@264: jamie@264: void printClosedHeader( std::string const& _name ) { jamie@264: printOpenHeader( _name ); jamie@264: stream << getLineOfChars<'.'>() << "\n"; jamie@264: } jamie@264: void printOpenHeader( std::string const& _name ) { jamie@264: stream << getLineOfChars<'-'>() << "\n"; jamie@264: { jamie@264: Colour colourGuard( Colour::Headers ); jamie@264: printHeaderString( _name ); jamie@264: } jamie@264: } jamie@264: jamie@264: // if string has a : in first line will set indent to follow it on jamie@264: // subsequent lines jamie@264: void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { jamie@264: std::size_t i = _string.find( ": " ); jamie@264: if( i != std::string::npos ) jamie@264: i+=2; jamie@264: else jamie@264: i = 0; jamie@264: stream << Text( _string, TextAttributes() jamie@264: .setIndent( indent+i) jamie@264: .setInitialIndent( indent ) ) << "\n"; jamie@264: } jamie@264: jamie@264: struct SummaryColumn { jamie@264: jamie@264: SummaryColumn( std::string const& _label, Colour::Code _colour ) jamie@264: : label( _label ), jamie@264: colour( _colour ) jamie@264: {} jamie@264: SummaryColumn addRow( std::size_t count ) { jamie@264: std::ostringstream oss; jamie@264: oss << count; jamie@264: std::string row = oss.str(); jamie@264: for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { jamie@264: while( it->size() < row.size() ) jamie@264: *it = " " + *it; jamie@264: while( it->size() > row.size() ) jamie@264: row = " " + row; jamie@264: } jamie@264: rows.push_back( row ); jamie@264: return *this; jamie@264: } jamie@264: jamie@264: std::string label; jamie@264: Colour::Code colour; jamie@264: std::vector rows; jamie@264: jamie@264: }; jamie@264: jamie@264: void printTotals( Totals const& totals ) { jamie@264: if( totals.testCases.total() == 0 ) { jamie@264: stream << Colour( Colour::Warning ) << "No tests ran\n"; jamie@264: } jamie@264: else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { jamie@264: stream << Colour( Colour::ResultSuccess ) << "All tests passed"; jamie@264: stream << " (" jamie@264: << pluralise( totals.assertions.passed, "assertion" ) << " in " jamie@264: << pluralise( totals.testCases.passed, "test case" ) << ")" jamie@264: << "\n"; jamie@264: } jamie@264: else { jamie@264: jamie@264: std::vector columns; jamie@264: columns.push_back( SummaryColumn( "", Colour::None ) jamie@264: .addRow( totals.testCases.total() ) jamie@264: .addRow( totals.assertions.total() ) ); jamie@264: columns.push_back( SummaryColumn( "passed", Colour::Success ) jamie@264: .addRow( totals.testCases.passed ) jamie@264: .addRow( totals.assertions.passed ) ); jamie@264: columns.push_back( SummaryColumn( "failed", Colour::ResultError ) jamie@264: .addRow( totals.testCases.failed ) jamie@264: .addRow( totals.assertions.failed ) ); jamie@264: columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) jamie@264: .addRow( totals.testCases.failedButOk ) jamie@264: .addRow( totals.assertions.failedButOk ) ); jamie@264: jamie@264: printSummaryRow( "test cases", columns, 0 ); jamie@264: printSummaryRow( "assertions", columns, 1 ); jamie@264: } jamie@264: } jamie@264: void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { jamie@264: for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { jamie@264: std::string value = it->rows[row]; jamie@264: if( it->label.empty() ) { jamie@264: stream << label << ": "; jamie@264: if( value != "0" ) jamie@264: stream << value; jamie@264: else jamie@264: stream << Colour( Colour::Warning ) << "- none -"; jamie@264: } jamie@264: else if( value != "0" ) { jamie@264: stream << Colour( Colour::LightGrey ) << " | "; jamie@264: stream << Colour( it->colour ) jamie@264: << value << " " << it->label; jamie@264: } jamie@264: } jamie@264: stream << "\n"; jamie@264: } jamie@264: jamie@264: static std::size_t makeRatio( std::size_t number, std::size_t total ) { jamie@264: std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; jamie@264: return ( ratio == 0 && number > 0 ) ? 1 : ratio; jamie@264: } jamie@264: static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { jamie@264: if( i > j && i > k ) jamie@264: return i; jamie@264: else if( j > k ) jamie@264: return j; jamie@264: else jamie@264: return k; jamie@264: } jamie@264: jamie@264: void printTotalsDivider( Totals const& totals ) { jamie@264: if( totals.testCases.total() > 0 ) { jamie@264: std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); jamie@264: std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); jamie@264: std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); jamie@264: while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) jamie@264: findMax( failedRatio, failedButOkRatio, passedRatio )++; jamie@264: while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) jamie@264: findMax( failedRatio, failedButOkRatio, passedRatio )--; jamie@264: jamie@264: stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); jamie@264: stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); jamie@264: if( totals.testCases.allPassed() ) jamie@264: stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); jamie@264: else jamie@264: stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); jamie@264: } jamie@264: else { jamie@264: stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); jamie@264: } jamie@264: stream << "\n"; jamie@264: } jamie@264: void printSummaryDivider() { jamie@264: stream << getLineOfChars<'-'>() << "\n"; jamie@264: } jamie@264: template jamie@264: static char const* getLineOfChars() { jamie@264: static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; jamie@264: if( !*line ) { jamie@264: memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); jamie@264: line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; jamie@264: } jamie@264: return line; jamie@264: } jamie@264: jamie@264: private: jamie@264: bool m_headerPrinted; jamie@264: }; jamie@264: jamie@264: INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: // #included from: ../reporters/catch_reporter_compact.hpp jamie@264: #define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED jamie@264: jamie@264: namespace Catch { jamie@264: jamie@264: struct CompactReporter : StreamingReporterBase { jamie@264: jamie@264: CompactReporter( ReporterConfig const& _config ) jamie@264: : StreamingReporterBase( _config ) jamie@264: {} jamie@264: jamie@264: virtual ~CompactReporter(); jamie@264: jamie@264: static std::string getDescription() { jamie@264: return "Reports test results on a single line, suitable for IDEs"; jamie@264: } jamie@264: jamie@264: virtual ReporterPreferences getPreferences() const { jamie@264: ReporterPreferences prefs; jamie@264: prefs.shouldRedirectStdOut = false; jamie@264: return prefs; jamie@264: } jamie@264: jamie@264: virtual void noMatchingTestCases( std::string const& spec ) { jamie@264: stream << "No test cases matched '" << spec << "'" << std::endl; jamie@264: } jamie@264: jamie@264: virtual void assertionStarting( AssertionInfo const& ) { jamie@264: } jamie@264: jamie@264: virtual bool assertionEnded( AssertionStats const& _assertionStats ) { jamie@264: AssertionResult const& result = _assertionStats.assertionResult; jamie@264: jamie@264: bool printInfoMessages = true; jamie@264: jamie@264: // Drop out if result was successful and we're not printing those jamie@264: if( !m_config->includeSuccessfulResults() && result.isOk() ) { jamie@264: if( result.getResultType() != ResultWas::Warning ) jamie@264: return false; jamie@264: printInfoMessages = false; jamie@264: } jamie@264: jamie@264: AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); jamie@264: printer.print(); jamie@264: jamie@264: stream << std::endl; jamie@264: return true; jamie@264: } jamie@264: jamie@264: virtual void testRunEnded( TestRunStats const& _testRunStats ) { jamie@264: printTotals( _testRunStats.totals ); jamie@264: stream << "\n" << std::endl; jamie@264: StreamingReporterBase::testRunEnded( _testRunStats ); jamie@264: } jamie@264: jamie@264: private: jamie@264: class AssertionPrinter { jamie@264: void operator= ( AssertionPrinter const& ); jamie@264: public: jamie@264: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) jamie@264: : stream( _stream ) jamie@264: , stats( _stats ) jamie@264: , result( _stats.assertionResult ) jamie@264: , messages( _stats.infoMessages ) jamie@264: , itMessage( _stats.infoMessages.begin() ) jamie@264: , printInfoMessages( _printInfoMessages ) jamie@264: {} jamie@264: jamie@264: void print() { jamie@264: printSourceInfo(); jamie@264: jamie@264: itMessage = messages.begin(); jamie@264: jamie@264: switch( result.getResultType() ) { jamie@264: case ResultWas::Ok: jamie@264: printResultType( Colour::ResultSuccess, passedString() ); jamie@264: printOriginalExpression(); jamie@264: printReconstructedExpression(); jamie@264: if ( ! result.hasExpression() ) jamie@264: printRemainingMessages( Colour::None ); jamie@264: else jamie@264: printRemainingMessages(); jamie@264: break; jamie@264: case ResultWas::ExpressionFailed: jamie@264: if( result.isOk() ) jamie@264: printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); jamie@264: else jamie@264: printResultType( Colour::Error, failedString() ); jamie@264: printOriginalExpression(); jamie@264: printReconstructedExpression(); jamie@264: printRemainingMessages(); jamie@264: break; jamie@264: case ResultWas::ThrewException: jamie@264: printResultType( Colour::Error, failedString() ); jamie@264: printIssue( "unexpected exception with message:" ); jamie@264: printMessage(); jamie@264: printExpressionWas(); jamie@264: printRemainingMessages(); jamie@264: break; jamie@264: case ResultWas::DidntThrowException: jamie@264: printResultType( Colour::Error, failedString() ); jamie@264: printIssue( "expected exception, got none" ); jamie@264: printExpressionWas(); jamie@264: printRemainingMessages(); jamie@264: break; jamie@264: case ResultWas::Info: jamie@264: printResultType( Colour::None, "info" ); jamie@264: printMessage(); jamie@264: printRemainingMessages(); jamie@264: break; jamie@264: case ResultWas::Warning: jamie@264: printResultType( Colour::None, "warning" ); jamie@264: printMessage(); jamie@264: printRemainingMessages(); jamie@264: break; jamie@264: case ResultWas::ExplicitFailure: jamie@264: printResultType( Colour::Error, failedString() ); jamie@264: printIssue( "explicitly" ); jamie@264: printRemainingMessages( Colour::None ); jamie@264: break; jamie@264: // These cases are here to prevent compiler warnings jamie@264: case ResultWas::Unknown: jamie@264: case ResultWas::FailureBit: jamie@264: case ResultWas::Exception: jamie@264: printResultType( Colour::Error, "** internal error **" ); jamie@264: break; jamie@264: } jamie@264: } jamie@264: jamie@264: private: jamie@264: // Colour::LightGrey jamie@264: jamie@264: static Colour::Code dimColour() { return Colour::FileName; } jamie@264: jamie@264: #ifdef CATCH_PLATFORM_MAC jamie@264: static const char* failedString() { return "FAILED"; } jamie@264: static const char* passedString() { return "PASSED"; } jamie@264: #else jamie@264: static const char* failedString() { return "failed"; } jamie@264: static const char* passedString() { return "passed"; } jamie@264: #endif jamie@264: jamie@264: void printSourceInfo() const { jamie@264: Colour colourGuard( Colour::FileName ); jamie@264: stream << result.getSourceInfo() << ":"; jamie@264: } jamie@264: jamie@264: void printResultType( Colour::Code colour, std::string passOrFail ) const { jamie@264: if( !passOrFail.empty() ) { jamie@264: { jamie@264: Colour colourGuard( colour ); jamie@264: stream << " " << passOrFail; jamie@264: } jamie@264: stream << ":"; jamie@264: } jamie@264: } jamie@264: jamie@264: void printIssue( std::string issue ) const { jamie@264: stream << " " << issue; jamie@264: } jamie@264: jamie@264: void printExpressionWas() { jamie@264: if( result.hasExpression() ) { jamie@264: stream << ";"; jamie@264: { jamie@264: Colour colour( dimColour() ); jamie@264: stream << " expression was:"; jamie@264: } jamie@264: printOriginalExpression(); jamie@264: } jamie@264: } jamie@264: jamie@264: void printOriginalExpression() const { jamie@264: if( result.hasExpression() ) { jamie@264: stream << " " << result.getExpression(); jamie@264: } jamie@264: } jamie@264: jamie@264: void printReconstructedExpression() const { jamie@264: if( result.hasExpandedExpression() ) { jamie@264: { jamie@264: Colour colour( dimColour() ); jamie@264: stream << " for: "; jamie@264: } jamie@264: stream << result.getExpandedExpression(); jamie@264: } jamie@264: } jamie@264: jamie@264: void printMessage() { jamie@264: if ( itMessage != messages.end() ) { jamie@264: stream << " '" << itMessage->message << "'"; jamie@264: ++itMessage; jamie@264: } jamie@264: } jamie@264: jamie@264: void printRemainingMessages( Colour::Code colour = dimColour() ) { jamie@264: if ( itMessage == messages.end() ) jamie@264: return; jamie@264: jamie@264: // using messages.end() directly yields compilation error: jamie@264: std::vector::const_iterator itEnd = messages.end(); jamie@264: const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); jamie@264: jamie@264: { jamie@264: Colour colourGuard( colour ); jamie@264: stream << " with " << pluralise( N, "message" ) << ":"; jamie@264: } jamie@264: jamie@264: for(; itMessage != itEnd; ) { jamie@264: // If this assertion is a warning ignore any INFO messages jamie@264: if( printInfoMessages || itMessage->type != ResultWas::Info ) { jamie@264: stream << " '" << itMessage->message << "'"; jamie@264: if ( ++itMessage != itEnd ) { jamie@264: Colour colourGuard( dimColour() ); jamie@264: stream << " and"; jamie@264: } jamie@264: } jamie@264: } jamie@264: } jamie@264: jamie@264: private: jamie@264: std::ostream& stream; jamie@264: AssertionStats const& stats; jamie@264: AssertionResult const& result; jamie@264: std::vector messages; jamie@264: std::vector::const_iterator itMessage; jamie@264: bool printInfoMessages; jamie@264: }; jamie@264: jamie@264: // Colour, message variants: jamie@264: // - white: No tests ran. jamie@264: // - red: Failed [both/all] N test cases, failed [both/all] M assertions. jamie@264: // - white: Passed [both/all] N test cases (no assertions). jamie@264: // - red: Failed N tests cases, failed M assertions. jamie@264: // - green: Passed [both/all] N tests cases with M assertions. jamie@264: jamie@264: std::string bothOrAll( std::size_t count ) const { jamie@264: return count == 1 ? "" : count == 2 ? "both " : "all " ; jamie@264: } jamie@264: jamie@264: void printTotals( const Totals& totals ) const { jamie@264: if( totals.testCases.total() == 0 ) { jamie@264: stream << "No tests ran."; jamie@264: } jamie@264: else if( totals.testCases.failed == totals.testCases.total() ) { jamie@264: Colour colour( Colour::ResultError ); jamie@264: const std::string qualify_assertions_failed = jamie@264: totals.assertions.failed == totals.assertions.total() ? jamie@264: bothOrAll( totals.assertions.failed ) : ""; jamie@264: stream << jamie@264: "Failed " << bothOrAll( totals.testCases.failed ) jamie@264: << pluralise( totals.testCases.failed, "test case" ) << ", " jamie@264: "failed " << qualify_assertions_failed << jamie@264: pluralise( totals.assertions.failed, "assertion" ) << "."; jamie@264: } jamie@264: else if( totals.assertions.total() == 0 ) { jamie@264: stream << jamie@264: "Passed " << bothOrAll( totals.testCases.total() ) jamie@264: << pluralise( totals.testCases.total(), "test case" ) jamie@264: << " (no assertions)."; jamie@264: } jamie@264: else if( totals.assertions.failed ) { jamie@264: Colour colour( Colour::ResultError ); jamie@264: stream << jamie@264: "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " jamie@264: "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; jamie@264: } jamie@264: else { jamie@264: Colour colour( Colour::ResultSuccess ); jamie@264: stream << jamie@264: "Passed " << bothOrAll( totals.testCases.passed ) jamie@264: << pluralise( totals.testCases.passed, "test case" ) << jamie@264: " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; jamie@264: } jamie@264: } jamie@264: }; jamie@264: jamie@264: INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) jamie@264: jamie@264: } // end namespace Catch jamie@264: jamie@264: namespace Catch { jamie@264: NonCopyable::~NonCopyable() {} jamie@264: IShared::~IShared() {} jamie@264: StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} jamie@264: IContext::~IContext() {} jamie@264: IResultCapture::~IResultCapture() {} jamie@264: ITestCase::~ITestCase() {} jamie@264: ITestCaseRegistry::~ITestCaseRegistry() {} jamie@264: IRegistryHub::~IRegistryHub() {} jamie@264: IMutableRegistryHub::~IMutableRegistryHub() {} jamie@264: IExceptionTranslator::~IExceptionTranslator() {} jamie@264: IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} jamie@264: IReporter::~IReporter() {} jamie@264: IReporterFactory::~IReporterFactory() {} jamie@264: IReporterRegistry::~IReporterRegistry() {} jamie@264: IStreamingReporter::~IStreamingReporter() {} jamie@264: AssertionStats::~AssertionStats() {} jamie@264: SectionStats::~SectionStats() {} jamie@264: TestCaseStats::~TestCaseStats() {} jamie@264: TestGroupStats::~TestGroupStats() {} jamie@264: TestRunStats::~TestRunStats() {} jamie@264: CumulativeReporterBase::SectionNode::~SectionNode() {} jamie@264: CumulativeReporterBase::~CumulativeReporterBase() {} jamie@264: jamie@264: StreamingReporterBase::~StreamingReporterBase() {} jamie@264: ConsoleReporter::~ConsoleReporter() {} jamie@264: CompactReporter::~CompactReporter() {} jamie@264: IRunner::~IRunner() {} jamie@264: IMutableContext::~IMutableContext() {} jamie@264: IConfig::~IConfig() {} jamie@264: XmlReporter::~XmlReporter() {} jamie@264: JunitReporter::~JunitReporter() {} jamie@264: TestRegistry::~TestRegistry() {} jamie@264: FreeFunctionTestCase::~FreeFunctionTestCase() {} jamie@264: IGeneratorInfo::~IGeneratorInfo() {} jamie@264: IGeneratorsForTest::~IGeneratorsForTest() {} jamie@264: TestSpec::Pattern::~Pattern() {} jamie@264: TestSpec::NamePattern::~NamePattern() {} jamie@264: TestSpec::TagPattern::~TagPattern() {} jamie@264: TestSpec::ExcludedPattern::~ExcludedPattern() {} jamie@264: jamie@264: Matchers::Impl::StdString::Equals::~Equals() {} jamie@264: Matchers::Impl::StdString::Contains::~Contains() {} jamie@264: Matchers::Impl::StdString::StartsWith::~StartsWith() {} jamie@264: Matchers::Impl::StdString::EndsWith::~EndsWith() {} jamie@264: jamie@264: void Config::dummy() {} jamie@264: jamie@264: INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter ) jamie@264: } jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #endif jamie@264: jamie@264: #endif jamie@264: jamie@264: #ifdef CATCH_CONFIG_MAIN jamie@264: // #included from: internal/catch_default_main.hpp jamie@264: #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED jamie@264: jamie@264: #ifndef __OBJC__ jamie@264: jamie@264: // Standard C/C++ main entry point jamie@264: int main (int argc, char * const argv[]) { jamie@264: return Catch::Session().run( argc, argv ); jamie@264: } jamie@264: jamie@264: #else // __OBJC__ jamie@264: jamie@264: // Objective-C entry point jamie@264: int main (int argc, char * const argv[]) { jamie@264: #if !CATCH_ARC_ENABLED jamie@264: NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; jamie@264: #endif jamie@264: jamie@264: Catch::registerTestMethods(); jamie@264: int result = Catch::Session().run( argc, (char* const*)argv ); jamie@264: jamie@264: #if !CATCH_ARC_ENABLED jamie@264: [pool drain]; jamie@264: #endif jamie@264: jamie@264: return result; jamie@264: } jamie@264: jamie@264: #endif // __OBJC__ jamie@264: jamie@264: #endif jamie@264: jamie@264: #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED jamie@264: # undef CLARA_CONFIG_MAIN jamie@264: #endif jamie@264: jamie@264: ////// jamie@264: jamie@264: // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ jamie@264: #ifdef CATCH_CONFIG_PREFIX_ALL jamie@264: jamie@264: #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) jamie@264: #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) jamie@264: jamie@264: #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) jamie@264: #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) jamie@264: #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) jamie@264: jamie@264: #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) jamie@264: #define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) jamie@264: #define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) jamie@264: #define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) jamie@264: #define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) jamie@264: jamie@264: #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) jamie@264: #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) jamie@264: #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) jamie@264: jamie@264: #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) jamie@264: #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) jamie@264: jamie@264: #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) jamie@264: #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) jamie@264: #define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) jamie@264: #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) jamie@264: #define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) jamie@264: jamie@264: #ifdef CATCH_CONFIG_VARIADIC_MACROS jamie@264: #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) jamie@264: #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) jamie@264: #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) jamie@264: #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) jamie@264: #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) jamie@264: #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) jamie@264: #else jamie@264: #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) jamie@264: #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) jamie@264: #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) jamie@264: #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) jamie@264: #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) jamie@264: #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) jamie@264: #endif jamie@264: #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) jamie@264: jamie@264: #define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) jamie@264: #define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) jamie@264: jamie@264: #define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) jamie@264: jamie@264: // "BDD-style" convenience wrappers jamie@264: #ifdef CATCH_CONFIG_VARIADIC_MACROS jamie@264: #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) jamie@264: #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) jamie@264: #else jamie@264: #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) jamie@264: #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) jamie@264: #endif jamie@264: #define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) jamie@264: #define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) jamie@264: #define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) jamie@264: #define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) jamie@264: #define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) jamie@264: jamie@264: // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required jamie@264: #else jamie@264: jamie@264: #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) jamie@264: #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) jamie@264: jamie@264: #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) jamie@264: #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) jamie@264: #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) jamie@264: jamie@264: #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) jamie@264: #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) jamie@264: #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) jamie@264: #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) jamie@264: #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) jamie@264: jamie@264: #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) jamie@264: #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) jamie@264: #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) jamie@264: jamie@264: #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) jamie@264: #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) jamie@264: jamie@264: #define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) jamie@264: #define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) jamie@264: #define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) jamie@264: #define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) jamie@264: #define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) jamie@264: jamie@264: #ifdef CATCH_CONFIG_VARIADIC_MACROS jamie@264: #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) jamie@264: #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) jamie@264: #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) jamie@264: #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) jamie@264: #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) jamie@264: #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) jamie@264: #else jamie@264: #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) jamie@264: #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) jamie@264: #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) jamie@264: #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) jamie@264: #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) jamie@264: #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) jamie@264: #endif jamie@264: #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) jamie@264: jamie@264: #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) jamie@264: #define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) jamie@264: jamie@264: #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) jamie@264: jamie@264: #endif jamie@264: jamie@264: #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) jamie@264: jamie@264: // "BDD-style" convenience wrappers jamie@264: #ifdef CATCH_CONFIG_VARIADIC_MACROS jamie@264: #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) jamie@264: #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) jamie@264: #else jamie@264: #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) jamie@264: #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) jamie@264: #endif jamie@264: #define GIVEN( desc ) SECTION( " Given: " desc, "" ) jamie@264: #define WHEN( desc ) SECTION( " When: " desc, "" ) jamie@264: #define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) jamie@264: #define THEN( desc ) SECTION( " Then: " desc, "" ) jamie@264: #define AND_THEN( desc ) SECTION( " And: " desc, "" ) jamie@264: jamie@264: using Catch::Detail::Approx; jamie@264: jamie@264: // #included from: internal/catch_reenable_warnings.h jamie@264: jamie@264: #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED jamie@264: jamie@264: #ifdef __clang__ jamie@264: #pragma clang diagnostic pop jamie@264: #elif defined __GNUC__ jamie@264: #pragma GCC diagnostic pop jamie@264: #endif jamie@264: jamie@264: #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED jamie@264: