|
@@ -1,6 +1,6 @@
|
|
|
/*
|
|
|
- * CATCH v1.0 build 53 (master branch)
|
|
|
- * Generated: 2014-08-20 08:08:19.533804
|
|
|
+ * Catch v1.5.7
|
|
|
+ * Generated: 2016-09-27 10:45:46.824849
|
|
|
* ----------------------------------------------------------
|
|
|
* This file has been merged from multiple headers. Please don't edit it directly
|
|
|
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
|
|
@@ -13,31 +13,41 @@
|
|
|
|
|
|
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
|
|
|
|
|
-// #included from: internal/catch_suppress_warnings.h
|
|
|
+#ifdef __clang__
|
|
|
+# pragma clang system_header
|
|
|
+#elif defined __GNUC__
|
|
|
+# pragma GCC system_header
|
|
|
+#endif
|
|
|
|
|
|
-#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
|
|
|
+// #included from: internal/catch_suppress_warnings.h
|
|
|
|
|
|
#ifdef __clang__
|
|
|
-#pragma clang diagnostic ignored "-Wglobal-constructors"
|
|
|
-#pragma clang diagnostic ignored "-Wvariadic-macros"
|
|
|
-#pragma clang diagnostic ignored "-Wc99-extensions"
|
|
|
-#pragma clang diagnostic ignored "-Wunused-variable"
|
|
|
-#pragma clang diagnostic push
|
|
|
-#pragma clang diagnostic ignored "-Wpadded"
|
|
|
-#pragma clang diagnostic ignored "-Wc++98-compat"
|
|
|
-#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
|
|
+# ifdef __ICC // icpc defines the __clang__ macro
|
|
|
+# pragma warning(push)
|
|
|
+# pragma warning(disable: 161 1682)
|
|
|
+# else // __ICC
|
|
|
+# pragma clang diagnostic ignored "-Wglobal-constructors"
|
|
|
+# pragma clang diagnostic ignored "-Wvariadic-macros"
|
|
|
+# pragma clang diagnostic ignored "-Wc99-extensions"
|
|
|
+# pragma clang diagnostic ignored "-Wunused-variable"
|
|
|
+# pragma clang diagnostic push
|
|
|
+# pragma clang diagnostic ignored "-Wpadded"
|
|
|
+# pragma clang diagnostic ignored "-Wc++98-compat"
|
|
|
+# pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
|
|
+# pragma clang diagnostic ignored "-Wswitch-enum"
|
|
|
+# pragma clang diagnostic ignored "-Wcovered-switch-default"
|
|
|
+# endif
|
|
|
#elif defined __GNUC__
|
|
|
-#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
|
|
-#pragma GCC diagnostic ignored "-Wunused-variable"
|
|
|
-#pragma GCC diagnostic push
|
|
|
-#pragma GCC diagnostic ignored "-Wpadded"
|
|
|
+# pragma GCC diagnostic ignored "-Wvariadic-macros"
|
|
|
+# pragma GCC diagnostic ignored "-Wunused-variable"
|
|
|
+# pragma GCC diagnostic push
|
|
|
+# pragma GCC diagnostic ignored "-Wpadded"
|
|
|
#endif
|
|
|
-
|
|
|
-#ifdef CATCH_CONFIG_MAIN
|
|
|
-# define CATCH_CONFIG_RUNNER
|
|
|
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
|
|
|
+# define CATCH_IMPL
|
|
|
#endif
|
|
|
|
|
|
-#ifdef CATCH_CONFIG_RUNNER
|
|
|
+#ifdef CATCH_IMPL
|
|
|
# ifndef CLARA_CONFIG_MAIN
|
|
|
# define CLARA_CONFIG_MAIN_NOT_DEFINED
|
|
|
# define CLARA_CONFIG_MAIN
|
|
@@ -52,7 +62,11 @@
|
|
|
|
|
|
#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
|
|
|
#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
|
|
|
-#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
|
|
|
+#ifdef CATCH_CONFIG_COUNTER
|
|
|
+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
|
|
|
+#else
|
|
|
+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
|
|
|
+#endif
|
|
|
|
|
|
#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
|
|
|
#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
|
|
@@ -64,70 +78,94 @@
|
|
|
// #included from: catch_compiler_capabilities.h
|
|
|
#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
|
|
|
|
|
-// Much of the following code is based on Boost (1.53)
|
|
|
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
|
|
|
+// The following features are defined:
|
|
|
+//
|
|
|
+// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
|
|
|
+// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
|
|
|
+// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
|
|
|
+// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
|
|
|
+// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
|
|
|
+// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
|
|
|
+// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
|
|
|
+// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
|
|
|
+
|
|
|
+// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
|
|
|
+
|
|
|
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
|
|
|
+// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
|
|
|
+// ****************
|
|
|
+// Note to maintainers: if new toggles are added please document them
|
|
|
+// in configuration.md, too
|
|
|
+// ****************
|
|
|
+
|
|
|
+// In general each macro has a _NO_<feature name> form
|
|
|
+// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
|
|
|
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
|
|
|
+// can be combined, en-mass, with the _NO_ forms later.
|
|
|
+
|
|
|
+// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
|
|
|
+
|
|
|
+#ifdef __cplusplus
|
|
|
+
|
|
|
+# if __cplusplus >= 201103L
|
|
|
+# define CATCH_CPP11_OR_GREATER
|
|
|
+# endif
|
|
|
+
|
|
|
+# if __cplusplus >= 201402L
|
|
|
+# define CATCH_CPP14_OR_GREATER
|
|
|
+# endif
|
|
|
+
|
|
|
+#endif
|
|
|
|
|
|
#ifdef __clang__
|
|
|
|
|
|
# if __has_feature(cxx_nullptr)
|
|
|
-# define CATCH_CONFIG_CPP11_NULLPTR
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
|
|
# endif
|
|
|
|
|
|
# if __has_feature(cxx_noexcept)
|
|
|
-# define CATCH_CONFIG_CPP11_NOEXCEPT
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
|
|
# endif
|
|
|
|
|
|
+# if defined(CATCH_CPP11_OR_GREATER)
|
|
|
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
|
|
|
+# endif
|
|
|
+
|
|
|
#endif // __clang__
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
// Borland
|
|
|
#ifdef __BORLANDC__
|
|
|
|
|
|
-#if (__BORLANDC__ > 0x582 )
|
|
|
-//#define CATCH_CONFIG_SFINAE // Not confirmed
|
|
|
-#endif
|
|
|
-
|
|
|
#endif // __BORLANDC__
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
// EDG
|
|
|
#ifdef __EDG_VERSION__
|
|
|
|
|
|
-#if (__EDG_VERSION__ > 238 )
|
|
|
-//#define CATCH_CONFIG_SFINAE // Not confirmed
|
|
|
-#endif
|
|
|
-
|
|
|
#endif // __EDG_VERSION__
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
// Digital Mars
|
|
|
#ifdef __DMC__
|
|
|
|
|
|
-#if (__DMC__ > 0x840 )
|
|
|
-//#define CATCH_CONFIG_SFINAE // Not confirmed
|
|
|
-#endif
|
|
|
-
|
|
|
#endif // __DMC__
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
// GCC
|
|
|
#ifdef __GNUC__
|
|
|
|
|
|
-#if __GNUC__ < 3
|
|
|
-
|
|
|
-#if (__GNUC_MINOR__ >= 96 )
|
|
|
-//#define CATCH_CONFIG_SFINAE
|
|
|
-#endif
|
|
|
-
|
|
|
-#elif __GNUC__ >= 3
|
|
|
+# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
|
|
+# endif
|
|
|
|
|
|
-// #define CATCH_CONFIG_SFINAE // Taking this out completely for now
|
|
|
+# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER)
|
|
|
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
|
|
|
+# endif
|
|
|
|
|
|
-#endif // __GNUC__ < 3
|
|
|
-
|
|
|
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) )
|
|
|
-
|
|
|
-#define CATCH_CONFIG_CPP11_NULLPTR
|
|
|
-#endif
|
|
|
+// - otherwise more recent versions define __cplusplus >= 201103L
|
|
|
+// and will get picked up below
|
|
|
|
|
|
#endif // __GNUC__
|
|
|
|
|
@@ -135,33 +173,116 @@
|
|
|
// Visual C++
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
|
-#if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
|
|
|
-//#define CATCH_CONFIG_SFINAE // Not confirmed
|
|
|
+#if (_MSC_VER >= 1600)
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
|
|
+#endif
|
|
|
+
|
|
|
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
|
|
|
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
|
|
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
|
|
#endif
|
|
|
|
|
|
#endif // _MSC_VER
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
// Use variadic macros if the compiler supports them
|
|
|
#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
|
|
|
( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
|
|
|
( defined __GNUC__ && __GNUC__ >= 3 ) || \
|
|
|
( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
|
|
|
|
|
|
-#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS
|
|
|
-#define CATCH_CONFIG_VARIADIC_MACROS
|
|
|
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
|
|
|
+
|
|
|
#endif
|
|
|
|
|
|
+// Use __COUNTER__ if the compiler supports it
|
|
|
+#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
|
|
|
+ ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
|
|
|
+ ( defined __clang__ && __clang_major__ >= 3 )
|
|
|
+
|
|
|
+#define CATCH_INTERNAL_CONFIG_COUNTER
|
|
|
+
|
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
// C++ language feature support
|
|
|
|
|
|
-// detect language version:
|
|
|
-#if (__cplusplus == 201103L)
|
|
|
-# define CATCH_CPP11
|
|
|
-# define CATCH_CPP11_OR_GREATER
|
|
|
-#elif (__cplusplus >= 201103L)
|
|
|
-# define CATCH_CPP11_OR_GREATER
|
|
|
+// catch all support for C++11
|
|
|
+#if defined(CATCH_CPP11_OR_GREATER)
|
|
|
+
|
|
|
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
|
|
+# endif
|
|
|
+
|
|
|
+# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
|
|
+# endif
|
|
|
+
|
|
|
+# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
|
|
+# endif
|
|
|
+
|
|
|
+# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
|
|
|
+# endif
|
|
|
+
|
|
|
+# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
|
|
|
+# endif
|
|
|
+
|
|
|
+# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
|
|
|
+# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
|
|
|
+# endif
|
|
|
+
|
|
|
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
|
|
|
+# endif
|
|
|
+
|
|
|
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
|
|
|
+# endif
|
|
|
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
|
|
|
+# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
|
|
+# endif
|
|
|
+
|
|
|
+#endif // __cplusplus >= 201103L
|
|
|
+
|
|
|
+// Now set the actual defines based on the above + anything the user has configured
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
|
|
|
+# define CATCH_CONFIG_CPP11_NULLPTR
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
|
|
|
+# define CATCH_CONFIG_CPP11_NOEXCEPT
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
|
|
|
+# define CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
|
|
|
+# define CATCH_CONFIG_CPP11_IS_ENUM
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
|
|
|
+# define CATCH_CONFIG_CPP11_TUPLE
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
|
|
|
+# define CATCH_CONFIG_VARIADIC_MACROS
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
|
|
|
+# define CATCH_CONFIG_CPP11_LONG_LONG
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
|
|
|
+# define CATCH_CONFIG_CPP11_OVERRIDE
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
|
|
|
+# define CATCH_CONFIG_CPP11_UNIQUE_PTR
|
|
|
+#endif
|
|
|
+#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
|
|
+# define CATCH_CONFIG_COUNTER
|
|
|
+#endif
|
|
|
+
|
|
|
+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
|
|
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
|
|
#endif
|
|
|
|
|
|
// noexcept support:
|
|
@@ -173,11 +294,47 @@
|
|
|
# define CATCH_NOEXCEPT_IS(x)
|
|
|
#endif
|
|
|
|
|
|
+// nullptr support
|
|
|
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
|
|
+# define CATCH_NULL nullptr
|
|
|
+#else
|
|
|
+# define CATCH_NULL NULL
|
|
|
+#endif
|
|
|
+
|
|
|
+// override support
|
|
|
+#ifdef CATCH_CONFIG_CPP11_OVERRIDE
|
|
|
+# define CATCH_OVERRIDE override
|
|
|
+#else
|
|
|
+# define CATCH_OVERRIDE
|
|
|
+#endif
|
|
|
+
|
|
|
+// unique_ptr support
|
|
|
+#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
|
|
|
+# define CATCH_AUTO_PTR( T ) std::unique_ptr<T>
|
|
|
+#else
|
|
|
+# define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
|
|
|
+#endif
|
|
|
+
|
|
|
namespace Catch {
|
|
|
|
|
|
+ struct IConfig;
|
|
|
+
|
|
|
+ struct CaseSensitive { enum Choice {
|
|
|
+ Yes,
|
|
|
+ No
|
|
|
+ }; };
|
|
|
+
|
|
|
class NonCopyable {
|
|
|
- NonCopyable( NonCopyable const& );
|
|
|
- void operator = ( NonCopyable const& );
|
|
|
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
+ NonCopyable( NonCopyable const& ) = delete;
|
|
|
+ NonCopyable( NonCopyable && ) = delete;
|
|
|
+ NonCopyable& operator = ( NonCopyable const& ) = delete;
|
|
|
+ NonCopyable& operator = ( NonCopyable && ) = delete;
|
|
|
+#else
|
|
|
+ NonCopyable( NonCopyable const& info );
|
|
|
+ NonCopyable& operator = ( NonCopyable const& );
|
|
|
+#endif
|
|
|
+
|
|
|
protected:
|
|
|
NonCopyable() {}
|
|
|
virtual ~NonCopyable();
|
|
@@ -215,6 +372,7 @@ namespace Catch {
|
|
|
void toLowerInPlace( std::string& s );
|
|
|
std::string toLower( std::string const& s );
|
|
|
std::string trim( std::string const& str );
|
|
|
+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
|
|
|
|
|
|
struct pluralise {
|
|
|
pluralise( std::size_t count, std::string const& label );
|
|
@@ -230,13 +388,14 @@ namespace Catch {
|
|
|
SourceLineInfo();
|
|
|
SourceLineInfo( char const* _file, std::size_t _line );
|
|
|
SourceLineInfo( SourceLineInfo const& other );
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
SourceLineInfo( SourceLineInfo && ) = default;
|
|
|
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
|
|
|
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
|
|
|
# endif
|
|
|
bool empty() const;
|
|
|
bool operator == ( SourceLineInfo const& other ) const;
|
|
|
+ bool operator < ( SourceLineInfo const& other ) const;
|
|
|
|
|
|
std::string file;
|
|
|
std::size_t line;
|
|
@@ -251,6 +410,9 @@ namespace Catch {
|
|
|
|
|
|
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
|
|
|
|
|
|
+ void seedRng( IConfig const& config );
|
|
|
+ unsigned int rngSeed();
|
|
|
+
|
|
|
// Use this in variadic streaming macros to allow
|
|
|
// >> +StreamEndStop
|
|
|
// as well as
|
|
@@ -336,7 +498,7 @@ namespace Catch {
|
|
|
template<typename T>
|
|
|
class Ptr {
|
|
|
public:
|
|
|
- Ptr() : m_p( NULL ){}
|
|
|
+ Ptr() : m_p( CATCH_NULL ){}
|
|
|
Ptr( T* p ) : m_p( p ){
|
|
|
if( m_p )
|
|
|
m_p->addRef();
|
|
@@ -352,7 +514,7 @@ namespace Catch {
|
|
|
void reset() {
|
|
|
if( m_p )
|
|
|
m_p->release();
|
|
|
- m_p = NULL;
|
|
|
+ m_p = CATCH_NULL;
|
|
|
}
|
|
|
Ptr& operator = ( T* p ){
|
|
|
Ptr temp( p );
|
|
@@ -365,12 +527,11 @@ namespace Catch {
|
|
|
return *this;
|
|
|
}
|
|
|
void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
|
|
|
- T* get() { return m_p; }
|
|
|
- const T* get() const{ return m_p; }
|
|
|
+ T* get() const{ return m_p; }
|
|
|
T& operator*() const { return *m_p; }
|
|
|
T* operator->() const { return m_p; }
|
|
|
- bool operator !() const { return m_p == NULL; }
|
|
|
- operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); }
|
|
|
+ bool operator !() const { return m_p == CATCH_NULL; }
|
|
|
+ operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); }
|
|
|
|
|
|
private:
|
|
|
T* m_p;
|
|
@@ -467,9 +628,13 @@ namespace Catch {
|
|
|
struct ITestCaseRegistry {
|
|
|
virtual ~ITestCaseRegistry();
|
|
|
virtual std::vector<TestCase> const& getAllTests() const = 0;
|
|
|
- virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const = 0;
|
|
|
-
|
|
|
+ virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
|
|
|
};
|
|
|
+
|
|
|
+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
|
|
|
+ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
|
|
|
+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
namespace Catch {
|
|
@@ -502,27 +667,32 @@ struct NameAndDesc {
|
|
|
const char* description;
|
|
|
};
|
|
|
|
|
|
+void registerTestCase
|
|
|
+ ( ITestCase* testCase,
|
|
|
+ char const* className,
|
|
|
+ NameAndDesc const& nameAndDesc,
|
|
|
+ SourceLineInfo const& lineInfo );
|
|
|
+
|
|
|
struct AutoReg {
|
|
|
|
|
|
- AutoReg( TestFunction function,
|
|
|
- SourceLineInfo const& lineInfo,
|
|
|
- NameAndDesc const& nameAndDesc );
|
|
|
+ AutoReg
|
|
|
+ ( TestFunction function,
|
|
|
+ SourceLineInfo const& lineInfo,
|
|
|
+ NameAndDesc const& nameAndDesc );
|
|
|
|
|
|
template<typename C>
|
|
|
- AutoReg( void (C::*method)(),
|
|
|
- char const* className,
|
|
|
- NameAndDesc const& nameAndDesc,
|
|
|
- SourceLineInfo const& lineInfo ) {
|
|
|
- registerTestCase( new MethodTestCase<C>( method ),
|
|
|
- className,
|
|
|
- nameAndDesc,
|
|
|
- lineInfo );
|
|
|
- }
|
|
|
-
|
|
|
- void registerTestCase( ITestCase* testCase,
|
|
|
- char const* className,
|
|
|
- NameAndDesc const& nameAndDesc,
|
|
|
- SourceLineInfo const& lineInfo );
|
|
|
+ AutoReg
|
|
|
+ ( void (C::*method)(),
|
|
|
+ char const* className,
|
|
|
+ NameAndDesc const& nameAndDesc,
|
|
|
+ SourceLineInfo const& lineInfo ) {
|
|
|
+
|
|
|
+ registerTestCase
|
|
|
+ ( new MethodTestCase<C>( method ),
|
|
|
+ className,
|
|
|
+ nameAndDesc,
|
|
|
+ lineInfo );
|
|
|
+ }
|
|
|
|
|
|
~AutoReg();
|
|
|
|
|
@@ -531,50 +701,70 @@ private:
|
|
|
void operator= ( AutoReg const& );
|
|
|
};
|
|
|
|
|
|
+void registerTestCaseFunction
|
|
|
+ ( TestFunction function,
|
|
|
+ SourceLineInfo const& lineInfo,
|
|
|
+ NameAndDesc const& nameAndDesc );
|
|
|
+
|
|
|
} // end namespace Catch
|
|
|
|
|
|
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
+ #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
|
|
|
+ static void TestName(); \
|
|
|
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
|
|
|
+ static void TestName()
|
|
|
#define INTERNAL_CATCH_TESTCASE( ... ) \
|
|
|
- static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
|
|
|
- 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__ ) ); }\
|
|
|
- static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
|
|
|
+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
|
|
|
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
- #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
|
|
|
+ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
|
|
|
namespace{ \
|
|
|
- struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
|
|
|
+ struct TestName : ClassName{ \
|
|
|
void test(); \
|
|
|
}; \
|
|
|
- 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 ); \
|
|
|
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
|
|
|
} \
|
|
|
- void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
|
|
|
+ void TestName::test()
|
|
|
+ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
|
|
|
+ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
|
|
|
+
|
|
|
+ ///////////////////////////////////////////////////////////////////////////////
|
|
|
+ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
|
|
|
+ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) );
|
|
|
|
|
|
#else
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
+ #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
|
|
|
+ static void TestName(); \
|
|
|
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
|
|
|
+ static void TestName()
|
|
|
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
|
|
|
- static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
|
|
|
- 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 ) ); }\
|
|
|
- static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
|
|
|
+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
|
|
|
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
- #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
|
|
|
+ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
|
|
|
namespace{ \
|
|
|
- struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
|
|
|
+ struct TestCaseName : ClassName{ \
|
|
|
void test(); \
|
|
|
}; \
|
|
|
- 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 ); \
|
|
|
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
|
|
|
} \
|
|
|
- void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
|
|
|
+ void TestCaseName::test()
|
|
|
+ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
|
|
|
+ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
|
|
|
|
|
|
+ ///////////////////////////////////////////////////////////////////////////////
|
|
|
+ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
|
|
|
+ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) );
|
|
|
#endif
|
|
|
|
|
|
// #included from: internal/catch_capture.hpp
|
|
@@ -603,7 +793,9 @@ namespace Catch {
|
|
|
Exception = 0x100 | FailureBit,
|
|
|
|
|
|
ThrewException = Exception | 1,
|
|
|
- DidntThrowException = Exception | 2
|
|
|
+ DidntThrowException = Exception | 2,
|
|
|
+
|
|
|
+ FatalErrorCondition = 0x200 | FailureBit
|
|
|
|
|
|
}; };
|
|
|
|
|
@@ -616,11 +808,11 @@ namespace Catch {
|
|
|
|
|
|
// ResultDisposition::Flags enum
|
|
|
struct ResultDisposition { enum Flags {
|
|
|
- Normal = 0x00,
|
|
|
+ Normal = 0x01,
|
|
|
|
|
|
- ContinueOnFailure = 0x01, // Failures fail test, but execution continues
|
|
|
- FalseTest = 0x02, // Prefix expression with !
|
|
|
- SuppressFail = 0x04 // Failures are reported but do not fail the test
|
|
|
+ ContinueOnFailure = 0x02, // Failures fail test, but execution continues
|
|
|
+ FalseTest = 0x04, // Prefix expression with !
|
|
|
+ SuppressFail = 0x08 // Failures are reported but do not fail the test
|
|
|
}; };
|
|
|
|
|
|
inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
|
|
@@ -668,7 +860,7 @@ namespace Catch {
|
|
|
AssertionResult();
|
|
|
AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
|
|
|
~AssertionResult();
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
AssertionResult( AssertionResult const& ) = default;
|
|
|
AssertionResult( AssertionResult && ) = default;
|
|
|
AssertionResult& operator = ( AssertionResult const& ) = default;
|
|
@@ -695,6 +887,323 @@ namespace Catch {
|
|
|
|
|
|
} // end namespace Catch
|
|
|
|
|
|
+// #included from: catch_matchers.hpp
|
|
|
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
|
|
+
|
|
|
+namespace Catch {
|
|
|
+namespace Matchers {
|
|
|
+ namespace Impl {
|
|
|
+
|
|
|
+ namespace Generic {
|
|
|
+ template<typename ExpressionT> class AllOf;
|
|
|
+ template<typename ExpressionT> class AnyOf;
|
|
|
+ template<typename ExpressionT> class Not;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename ExpressionT>
|
|
|
+ struct Matcher : SharedImpl<IShared>
|
|
|
+ {
|
|
|
+ typedef ExpressionT ExpressionType;
|
|
|
+
|
|
|
+ virtual ~Matcher() {}
|
|
|
+ virtual Ptr<Matcher> clone() const = 0;
|
|
|
+ virtual bool match( ExpressionT const& expr ) const = 0;
|
|
|
+ virtual std::string toString() const = 0;
|
|
|
+
|
|
|
+ Generic::AllOf<ExpressionT> operator && ( Matcher<ExpressionT> const& other ) const;
|
|
|
+ Generic::AnyOf<ExpressionT> operator || ( Matcher<ExpressionT> const& other ) const;
|
|
|
+ Generic::Not<ExpressionT> operator ! () const;
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename DerivedT, typename ExpressionT>
|
|
|
+ struct MatcherImpl : Matcher<ExpressionT> {
|
|
|
+
|
|
|
+ virtual Ptr<Matcher<ExpressionT> > clone() const {
|
|
|
+ return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ namespace Generic {
|
|
|
+ template<typename ExpressionT>
|
|
|
+ class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT> {
|
|
|
+ public:
|
|
|
+ explicit Not( Matcher<ExpressionT> const& matcher ) : m_matcher(matcher.clone()) {}
|
|
|
+ Not( Not const& other ) : m_matcher( other.m_matcher ) {}
|
|
|
+
|
|
|
+ virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE {
|
|
|
+ return !m_matcher->match( expr );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual std::string toString() const CATCH_OVERRIDE {
|
|
|
+ return "not " + m_matcher->toString();
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ Ptr< Matcher<ExpressionT> > m_matcher;
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename ExpressionT>
|
|
|
+ class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
|
|
|
+ public:
|
|
|
+
|
|
|
+ AllOf() {}
|
|
|
+ AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
|
|
|
+
|
|
|
+ AllOf& add( Matcher<ExpressionT> const& matcher ) {
|
|
|
+ m_matchers.push_back( matcher.clone() );
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+ virtual bool match( ExpressionT const& expr ) const
|
|
|
+ {
|
|
|
+ for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
|
|
+ if( !m_matchers[i]->match( expr ) )
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ virtual std::string toString() const {
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << "( ";
|
|
|
+ for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
|
|
+ if( i != 0 )
|
|
|
+ oss << " and ";
|
|
|
+ oss << m_matchers[i]->toString();
|
|
|
+ }
|
|
|
+ oss << " )";
|
|
|
+ return oss.str();
|
|
|
+ }
|
|
|
+
|
|
|
+ AllOf operator && ( Matcher<ExpressionT> const& other ) const {
|
|
|
+ AllOf allOfExpr( *this );
|
|
|
+ allOfExpr.add( other );
|
|
|
+ return allOfExpr;
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename ExpressionT>
|
|
|
+ class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
|
|
|
+ public:
|
|
|
+
|
|
|
+ AnyOf() {}
|
|
|
+ AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
|
|
|
+
|
|
|
+ AnyOf& add( Matcher<ExpressionT> const& matcher ) {
|
|
|
+ m_matchers.push_back( matcher.clone() );
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+ virtual bool match( ExpressionT const& expr ) const
|
|
|
+ {
|
|
|
+ for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
|
|
+ if( m_matchers[i]->match( expr ) )
|
|
|
+ return true;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ virtual std::string toString() const {
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << "( ";
|
|
|
+ for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
|
|
+ if( i != 0 )
|
|
|
+ oss << " or ";
|
|
|
+ oss << m_matchers[i]->toString();
|
|
|
+ }
|
|
|
+ oss << " )";
|
|
|
+ return oss.str();
|
|
|
+ }
|
|
|
+
|
|
|
+ AnyOf operator || ( Matcher<ExpressionT> const& other ) const {
|
|
|
+ AnyOf anyOfExpr( *this );
|
|
|
+ anyOfExpr.add( other );
|
|
|
+ return anyOfExpr;
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
|
|
+ };
|
|
|
+
|
|
|
+ } // namespace Generic
|
|
|
+
|
|
|
+ template<typename ExpressionT>
|
|
|
+ Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator && ( Matcher<ExpressionT> const& other ) const {
|
|
|
+ Generic::AllOf<ExpressionT> allOfExpr;
|
|
|
+ allOfExpr.add( *this );
|
|
|
+ allOfExpr.add( other );
|
|
|
+ return allOfExpr;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename ExpressionT>
|
|
|
+ Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator || ( Matcher<ExpressionT> const& other ) const {
|
|
|
+ Generic::AnyOf<ExpressionT> anyOfExpr;
|
|
|
+ anyOfExpr.add( *this );
|
|
|
+ anyOfExpr.add( other );
|
|
|
+ return anyOfExpr;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename ExpressionT>
|
|
|
+ Generic::Not<ExpressionT> Matcher<ExpressionT>::operator ! () const {
|
|
|
+ return Generic::Not<ExpressionT>( *this );
|
|
|
+ }
|
|
|
+
|
|
|
+ namespace StdString {
|
|
|
+
|
|
|
+ inline std::string makeString( std::string const& str ) { return str; }
|
|
|
+ inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
|
|
|
+
|
|
|
+ struct CasedString
|
|
|
+ {
|
|
|
+ CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
|
|
|
+ : m_caseSensitivity( caseSensitivity ),
|
|
|
+ m_str( adjustString( str ) )
|
|
|
+ {}
|
|
|
+ std::string adjustString( std::string const& str ) const {
|
|
|
+ return m_caseSensitivity == CaseSensitive::No
|
|
|
+ ? toLower( str )
|
|
|
+ : str;
|
|
|
+
|
|
|
+ }
|
|
|
+ std::string toStringSuffix() const
|
|
|
+ {
|
|
|
+ return m_caseSensitivity == CaseSensitive::No
|
|
|
+ ? " (case insensitive)"
|
|
|
+ : "";
|
|
|
+ }
|
|
|
+ CaseSensitive::Choice m_caseSensitivity;
|
|
|
+ std::string m_str;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct Equals : MatcherImpl<Equals, std::string> {
|
|
|
+ Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
|
|
+ : m_data( str, caseSensitivity )
|
|
|
+ {}
|
|
|
+ Equals( Equals const& other ) : m_data( other.m_data ){}
|
|
|
+
|
|
|
+ virtual ~Equals();
|
|
|
+
|
|
|
+ virtual bool match( std::string const& expr ) const {
|
|
|
+ return m_data.m_str == m_data.adjustString( expr );;
|
|
|
+ }
|
|
|
+ virtual std::string toString() const {
|
|
|
+ return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
|
|
+ }
|
|
|
+
|
|
|
+ CasedString m_data;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct Contains : MatcherImpl<Contains, std::string> {
|
|
|
+ Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
|
|
+ : m_data( substr, caseSensitivity ){}
|
|
|
+ Contains( Contains const& other ) : m_data( other.m_data ){}
|
|
|
+
|
|
|
+ virtual ~Contains();
|
|
|
+
|
|
|
+ virtual bool match( std::string const& expr ) const {
|
|
|
+ return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos;
|
|
|
+ }
|
|
|
+ virtual std::string toString() const {
|
|
|
+ return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
|
|
+ }
|
|
|
+
|
|
|
+ CasedString m_data;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct StartsWith : MatcherImpl<StartsWith, std::string> {
|
|
|
+ StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
|
|
+ : m_data( substr, caseSensitivity ){}
|
|
|
+
|
|
|
+ StartsWith( StartsWith const& other ) : m_data( other.m_data ){}
|
|
|
+
|
|
|
+ virtual ~StartsWith();
|
|
|
+
|
|
|
+ virtual bool match( std::string const& expr ) const {
|
|
|
+ return startsWith( m_data.adjustString( expr ), m_data.m_str );
|
|
|
+ }
|
|
|
+ virtual std::string toString() const {
|
|
|
+ return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
|
|
+ }
|
|
|
+
|
|
|
+ CasedString m_data;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct EndsWith : MatcherImpl<EndsWith, std::string> {
|
|
|
+ EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
|
|
+ : m_data( substr, caseSensitivity ){}
|
|
|
+ EndsWith( EndsWith const& other ) : m_data( other.m_data ){}
|
|
|
+
|
|
|
+ virtual ~EndsWith();
|
|
|
+
|
|
|
+ virtual bool match( std::string const& expr ) const {
|
|
|
+ return endsWith( m_data.adjustString( expr ), m_data.m_str );
|
|
|
+ }
|
|
|
+ virtual std::string toString() const {
|
|
|
+ return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
|
|
+ }
|
|
|
+
|
|
|
+ CasedString m_data;
|
|
|
+ };
|
|
|
+ } // namespace StdString
|
|
|
+ } // namespace Impl
|
|
|
+
|
|
|
+ // The following functions create the actual matcher objects.
|
|
|
+ // This allows the types to be inferred
|
|
|
+ template<typename ExpressionT>
|
|
|
+ inline Impl::Generic::Not<ExpressionT> Not( Impl::Matcher<ExpressionT> const& m ) {
|
|
|
+ return Impl::Generic::Not<ExpressionT>( m );
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename ExpressionT>
|
|
|
+ inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
|
|
+ Impl::Matcher<ExpressionT> const& m2 ) {
|
|
|
+ return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
|
|
|
+ }
|
|
|
+ template<typename ExpressionT>
|
|
|
+ inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
|
|
+ Impl::Matcher<ExpressionT> const& m2,
|
|
|
+ Impl::Matcher<ExpressionT> const& m3 ) {
|
|
|
+ return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
|
|
+ }
|
|
|
+ template<typename ExpressionT>
|
|
|
+ inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
|
|
+ Impl::Matcher<ExpressionT> const& m2 ) {
|
|
|
+ return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
|
|
|
+ }
|
|
|
+ template<typename ExpressionT>
|
|
|
+ inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
|
|
+ Impl::Matcher<ExpressionT> const& m2,
|
|
|
+ Impl::Matcher<ExpressionT> const& m3 ) {
|
|
|
+ return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
|
|
+ }
|
|
|
+
|
|
|
+ inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
|
|
+ return Impl::StdString::Equals( str, caseSensitivity );
|
|
|
+ }
|
|
|
+ inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
|
|
+ return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity );
|
|
|
+ }
|
|
|
+ inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
|
|
+ return Impl::StdString::Contains( substr, caseSensitivity );
|
|
|
+ }
|
|
|
+ inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
|
|
+ return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity );
|
|
|
+ }
|
|
|
+ inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
|
|
|
+ return Impl::StdString::StartsWith( substr );
|
|
|
+ }
|
|
|
+ inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
|
|
|
+ return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
|
|
|
+ }
|
|
|
+ inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
|
|
|
+ return Impl::StdString::EndsWith( substr );
|
|
|
+ }
|
|
|
+ inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
|
|
|
+ return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
|
|
|
+ }
|
|
|
+
|
|
|
+} // namespace Matchers
|
|
|
+
|
|
|
+using namespace Matchers;
|
|
|
+
|
|
|
+} // namespace Catch
|
|
|
+
|
|
|
namespace Catch {
|
|
|
|
|
|
struct TestFailureException{};
|
|
@@ -721,11 +1230,12 @@ namespace Catch {
|
|
|
ResultBuilder( char const* macroName,
|
|
|
SourceLineInfo const& lineInfo,
|
|
|
char const* capturedExpression,
|
|
|
- ResultDisposition::Flags resultDisposition );
|
|
|
+ ResultDisposition::Flags resultDisposition,
|
|
|
+ char const* secondArg = "" );
|
|
|
|
|
|
template<typename T>
|
|
|
- ExpressionLhs<T const&> operator->* ( T const& operand );
|
|
|
- ExpressionLhs<bool> operator->* ( bool value );
|
|
|
+ ExpressionLhs<T const&> operator <= ( T const& operand );
|
|
|
+ ExpressionLhs<bool> operator <= ( bool value );
|
|
|
|
|
|
template<typename T>
|
|
|
ResultBuilder& operator << ( T const& value ) {
|
|
@@ -750,6 +1260,9 @@ namespace Catch {
|
|
|
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
|
|
|
void captureResult( ResultWas::OfType resultType );
|
|
|
void captureExpression();
|
|
|
+ void captureExpectedException( std::string const& expectedMessage );
|
|
|
+ void captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher );
|
|
|
+ void handleResult( AssertionResult const& result );
|
|
|
void react();
|
|
|
bool shouldDebugBreak() const;
|
|
|
bool allowThrows() const;
|
|
@@ -820,37 +1333,37 @@ namespace Internal {
|
|
|
template<typename T1, typename T2>
|
|
|
struct Evaluator<T1, T2, IsEqualTo> {
|
|
|
static bool evaluate( T1 const& lhs, T2 const& rhs) {
|
|
|
- return opCast( lhs ) == opCast( rhs );
|
|
|
+ return bool( opCast( lhs ) == opCast( rhs ) );
|
|
|
}
|
|
|
};
|
|
|
template<typename T1, typename T2>
|
|
|
struct Evaluator<T1, T2, IsNotEqualTo> {
|
|
|
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
|
- return opCast( lhs ) != opCast( rhs );
|
|
|
+ return bool( opCast( lhs ) != opCast( rhs ) );
|
|
|
}
|
|
|
};
|
|
|
template<typename T1, typename T2>
|
|
|
struct Evaluator<T1, T2, IsLessThan> {
|
|
|
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
|
- return opCast( lhs ) < opCast( rhs );
|
|
|
+ return bool( opCast( lhs ) < opCast( rhs ) );
|
|
|
}
|
|
|
};
|
|
|
template<typename T1, typename T2>
|
|
|
struct Evaluator<T1, T2, IsGreaterThan> {
|
|
|
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
|
- return opCast( lhs ) > opCast( rhs );
|
|
|
+ return bool( opCast( lhs ) > opCast( rhs ) );
|
|
|
}
|
|
|
};
|
|
|
template<typename T1, typename T2>
|
|
|
struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
|
|
|
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
|
- return opCast( lhs ) >= opCast( rhs );
|
|
|
+ return bool( opCast( lhs ) >= opCast( rhs ) );
|
|
|
}
|
|
|
};
|
|
|
template<typename T1, typename T2>
|
|
|
struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
|
|
|
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
|
- return opCast( lhs ) <= opCast( rhs );
|
|
|
+ return bool( opCast( lhs ) <= opCast( rhs ) );
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -928,13 +1441,51 @@ namespace Internal {
|
|
|
return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
|
|
|
}
|
|
|
|
|
|
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
|
|
|
+ // long long to unsigned X
|
|
|
+ template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
|
|
|
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
|
|
+ }
|
|
|
+ template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
|
|
|
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
|
|
+ }
|
|
|
+ template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
|
|
|
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
|
|
+ }
|
|
|
+ template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
|
|
|
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
|
|
+ }
|
|
|
+
|
|
|
+ // unsigned long long to X
|
|
|
+ template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
|
|
|
+ return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
|
|
|
+ }
|
|
|
+ template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
|
|
|
+ return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
|
|
|
+ }
|
|
|
+ template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
|
|
|
+ return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
|
|
|
+ }
|
|
|
+ template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
|
|
|
+ return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
|
|
|
+ }
|
|
|
+
|
|
|
+ // pointer to long long (when comparing against NULL)
|
|
|
+ template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
|
|
|
+ return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
|
|
|
+ }
|
|
|
+ template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
|
|
|
+ return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
|
|
|
+ }
|
|
|
+#endif // CATCH_CONFIG_CPP11_LONG_LONG
|
|
|
+
|
|
|
#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
|
|
// pointer to nullptr_t (when comparing against nullptr)
|
|
|
template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
|
|
|
- return Evaluator<T*, T*, Op>::evaluate( NULL, rhs );
|
|
|
+ return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
|
|
|
}
|
|
|
template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
|
|
|
- return Evaluator<T*, T*, Op>::evaluate( lhs, NULL );
|
|
|
+ return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
|
|
|
}
|
|
|
#endif // CATCH_CONFIG_CPP11_NULLPTR
|
|
|
|
|
@@ -948,40 +1499,6 @@ namespace Internal {
|
|
|
// #included from: catch_tostring.h
|
|
|
#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
|
|
|
|
|
|
-// #included from: catch_sfinae.hpp
|
|
|
-#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
|
|
|
-
|
|
|
-// Try to detect if the current compiler supports SFINAE
|
|
|
-
|
|
|
-namespace Catch {
|
|
|
-
|
|
|
- struct TrueType {
|
|
|
- static const bool value = true;
|
|
|
- typedef void Enable;
|
|
|
- char sizer[1];
|
|
|
- };
|
|
|
- struct FalseType {
|
|
|
- static const bool value = false;
|
|
|
- typedef void Disable;
|
|
|
- char sizer[2];
|
|
|
- };
|
|
|
-
|
|
|
-#ifdef CATCH_CONFIG_SFINAE
|
|
|
-
|
|
|
- template<bool> struct NotABooleanExpression;
|
|
|
-
|
|
|
- template<bool c> struct If : NotABooleanExpression<c> {};
|
|
|
- template<> struct If<true> : TrueType {};
|
|
|
- template<> struct If<false> : FalseType {};
|
|
|
-
|
|
|
- template<int size> struct SizedIf;
|
|
|
- template<> struct SizedIf<sizeof(TrueType)> : TrueType {};
|
|
|
- template<> struct SizedIf<sizeof(FalseType)> : FalseType {};
|
|
|
-
|
|
|
-#endif // CATCH_CONFIG_SFINAE
|
|
|
-
|
|
|
-} // end namespace Catch
|
|
|
-
|
|
|
#include <sstream>
|
|
|
#include <iomanip>
|
|
|
#include <limits>
|
|
@@ -1034,35 +1551,64 @@ inline id performOptionalSelector( id obj, SEL sel ) {
|
|
|
|
|
|
#endif
|
|
|
|
|
|
+#ifdef CATCH_CONFIG_CPP11_TUPLE
|
|
|
+#include <tuple>
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
|
|
|
+#include <type_traits>
|
|
|
+#endif
|
|
|
+
|
|
|
namespace Catch {
|
|
|
-namespace Detail {
|
|
|
|
|
|
-// SFINAE is currently disabled by default for all compilers.
|
|
|
-// If the non SFINAE version of IsStreamInsertable is ambiguous for you
|
|
|
-// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
|
|
|
-#ifdef CATCH_CONFIG_SFINAE
|
|
|
+// Why we're here.
|
|
|
+template<typename T>
|
|
|
+std::string toString( T const& value );
|
|
|
+
|
|
|
+// Built in overloads
|
|
|
|
|
|
- template<typename T>
|
|
|
- class IsStreamInsertableHelper {
|
|
|
- template<int N> struct TrueIfSizeable : TrueType {};
|
|
|
+std::string toString( std::string const& value );
|
|
|
+std::string toString( std::wstring const& value );
|
|
|
+std::string toString( const char* const value );
|
|
|
+std::string toString( char* const value );
|
|
|
+std::string toString( const wchar_t* const value );
|
|
|
+std::string toString( wchar_t* const value );
|
|
|
+std::string toString( int value );
|
|
|
+std::string toString( unsigned long value );
|
|
|
+std::string toString( unsigned int value );
|
|
|
+std::string toString( const double value );
|
|
|
+std::string toString( const float value );
|
|
|
+std::string toString( bool value );
|
|
|
+std::string toString( char value );
|
|
|
+std::string toString( signed char value );
|
|
|
+std::string toString( unsigned char value );
|
|
|
|
|
|
- template<typename T2>
|
|
|
- static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
|
|
|
- static FalseType dummy(...);
|
|
|
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
|
|
|
+std::string toString( long long value );
|
|
|
+std::string toString( unsigned long long value );
|
|
|
+#endif
|
|
|
|
|
|
- public:
|
|
|
- typedef SizedIf<sizeof(dummy((T*)0))> type;
|
|
|
- };
|
|
|
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
|
|
+std::string toString( std::nullptr_t );
|
|
|
+#endif
|
|
|
|
|
|
- template<typename T>
|
|
|
- struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
|
|
|
+#ifdef __OBJC__
|
|
|
+ std::string toString( NSString const * const& nsstring );
|
|
|
+ std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
|
|
|
+ std::string toString( NSObject* const& nsObject );
|
|
|
+#endif
|
|
|
|
|
|
-#else
|
|
|
+namespace Detail {
|
|
|
+
|
|
|
+ extern const std::string unprintableString;
|
|
|
|
|
|
struct BorgType {
|
|
|
template<typename T> BorgType( T const& );
|
|
|
};
|
|
|
|
|
|
+ struct TrueType { char sizer[1]; };
|
|
|
+ struct FalseType { char sizer[2]; };
|
|
|
+
|
|
|
TrueType& testStreamable( std::ostream& );
|
|
|
FalseType testStreamable( FalseType );
|
|
|
|
|
@@ -1075,12 +1621,38 @@ namespace Detail {
|
|
|
enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
|
|
|
};
|
|
|
|
|
|
-#endif
|
|
|
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
|
|
|
+ template<typename T,
|
|
|
+ bool IsEnum = std::is_enum<T>::value
|
|
|
+ >
|
|
|
+ struct EnumStringMaker
|
|
|
+ {
|
|
|
+ static std::string convert( T const& ) { return unprintableString; }
|
|
|
+ };
|
|
|
|
|
|
+ template<typename T>
|
|
|
+ struct EnumStringMaker<T,true>
|
|
|
+ {
|
|
|
+ static std::string convert( T const& v )
|
|
|
+ {
|
|
|
+ return ::Catch::toString(
|
|
|
+ static_cast<typename std::underlying_type<T>::type>(v)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ };
|
|
|
+#endif
|
|
|
template<bool C>
|
|
|
struct StringMakerBase {
|
|
|
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
|
|
|
template<typename T>
|
|
|
- static std::string convert( T const& ) { return "{?}"; }
|
|
|
+ static std::string convert( T const& v )
|
|
|
+ {
|
|
|
+ return EnumStringMaker<T>::convert( v );
|
|
|
+ }
|
|
|
+#else
|
|
|
+ template<typename T>
|
|
|
+ static std::string convert( T const& ) { return unprintableString; }
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
template<>
|
|
@@ -1102,9 +1674,6 @@ namespace Detail {
|
|
|
|
|
|
} // end namespace Detail
|
|
|
|
|
|
-template<typename T>
|
|
|
-std::string toString( T const& value );
|
|
|
-
|
|
|
template<typename T>
|
|
|
struct StringMaker :
|
|
|
Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
|
|
@@ -1114,7 +1683,7 @@ struct StringMaker<T*> {
|
|
|
template<typename U>
|
|
|
static std::string convert( U* p ) {
|
|
|
if( !p )
|
|
|
- return INTERNAL_CATCH_STRINGIFY( NULL );
|
|
|
+ return "NULL";
|
|
|
else
|
|
|
return Detail::rawMemoryToString( p );
|
|
|
}
|
|
@@ -1124,7 +1693,7 @@ template<typename R, typename C>
|
|
|
struct StringMaker<R C::*> {
|
|
|
static std::string convert( R C::* p ) {
|
|
|
if( !p )
|
|
|
- return INTERNAL_CATCH_STRINGIFY( NULL );
|
|
|
+ return "NULL";
|
|
|
else
|
|
|
return Detail::rawMemoryToString( p );
|
|
|
}
|
|
@@ -1135,59 +1704,78 @@ namespace Detail {
|
|
|
std::string rangeToString( InputIterator first, InputIterator last );
|
|
|
}
|
|
|
|
|
|
+//template<typename T, typename Allocator>
|
|
|
+//struct StringMaker<std::vector<T, Allocator> > {
|
|
|
+// static std::string convert( std::vector<T,Allocator> const& v ) {
|
|
|
+// return Detail::rangeToString( v.begin(), v.end() );
|
|
|
+// }
|
|
|
+//};
|
|
|
+
|
|
|
template<typename T, typename Allocator>
|
|
|
-struct StringMaker<std::vector<T, Allocator> > {
|
|
|
- static std::string convert( std::vector<T,Allocator> const& v ) {
|
|
|
- return Detail::rangeToString( v.begin(), v.end() );
|
|
|
- }
|
|
|
-};
|
|
|
+std::string toString( std::vector<T,Allocator> const& v ) {
|
|
|
+ return Detail::rangeToString( v.begin(), v.end() );
|
|
|
+}
|
|
|
|
|
|
-namespace Detail {
|
|
|
- template<typename T>
|
|
|
- std::string makeString( T const& value ) {
|
|
|
- return StringMaker<T>::convert( value );
|
|
|
- }
|
|
|
-} // end namespace Detail
|
|
|
+#ifdef CATCH_CONFIG_CPP11_TUPLE
|
|
|
+
|
|
|
+// toString for tuples
|
|
|
+namespace TupleDetail {
|
|
|
+ template<
|
|
|
+ typename Tuple,
|
|
|
+ std::size_t N = 0,
|
|
|
+ bool = (N < std::tuple_size<Tuple>::value)
|
|
|
+ >
|
|
|
+ struct ElementPrinter {
|
|
|
+ static void print( const Tuple& tuple, std::ostream& os )
|
|
|
+ {
|
|
|
+ os << ( N ? ", " : " " )
|
|
|
+ << Catch::toString(std::get<N>(tuple));
|
|
|
+ ElementPrinter<Tuple,N+1>::print(tuple,os);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<
|
|
|
+ typename Tuple,
|
|
|
+ std::size_t N
|
|
|
+ >
|
|
|
+ struct ElementPrinter<Tuple,N,false> {
|
|
|
+ static void print( const Tuple&, std::ostream& ) {}
|
|
|
+ };
|
|
|
|
|
|
-/// \brief converts any type to a string
|
|
|
-///
|
|
|
-/// The default template forwards on to ostringstream - except when an
|
|
|
-/// ostringstream overload does not exist - in which case it attempts to detect
|
|
|
-/// that and writes {?}.
|
|
|
-/// Overload (not specialise) this template for custom typs that you don't want
|
|
|
-/// to provide an ostream overload for.
|
|
|
-template<typename T>
|
|
|
-std::string toString( T const& value ) {
|
|
|
- return StringMaker<T>::convert( value );
|
|
|
}
|
|
|
|
|
|
-// Built in overloads
|
|
|
+template<typename ...Types>
|
|
|
+struct StringMaker<std::tuple<Types...>> {
|
|
|
|
|
|
-std::string toString( std::string const& value );
|
|
|
-std::string toString( std::wstring const& value );
|
|
|
-std::string toString( const char* const value );
|
|
|
-std::string toString( char* const value );
|
|
|
-std::string toString( const wchar_t* const value );
|
|
|
-std::string toString( wchar_t* const value );
|
|
|
-std::string toString( int value );
|
|
|
-std::string toString( unsigned long value );
|
|
|
-std::string toString( unsigned int value );
|
|
|
-std::string toString( const double value );
|
|
|
-std::string toString( const float value );
|
|
|
-std::string toString( bool value );
|
|
|
-std::string toString( char value );
|
|
|
-std::string toString( signed char value );
|
|
|
-std::string toString( unsigned char value );
|
|
|
-
|
|
|
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
|
|
-std::string toString( std::nullptr_t );
|
|
|
-#endif
|
|
|
+ static std::string convert( const std::tuple<Types...>& tuple )
|
|
|
+ {
|
|
|
+ std::ostringstream os;
|
|
|
+ os << '{';
|
|
|
+ TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os );
|
|
|
+ os << " }";
|
|
|
+ return os.str();
|
|
|
+ }
|
|
|
+};
|
|
|
+#endif // CATCH_CONFIG_CPP11_TUPLE
|
|
|
|
|
|
-#ifdef __OBJC__
|
|
|
- std::string toString( NSString const * const& nsstring );
|
|
|
- std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
|
|
|
- std::string toString( NSObject* const& nsObject );
|
|
|
-#endif
|
|
|
+namespace Detail {
|
|
|
+ template<typename T>
|
|
|
+ std::string makeString( T const& value ) {
|
|
|
+ return StringMaker<T>::convert( value );
|
|
|
+ }
|
|
|
+} // end namespace Detail
|
|
|
+
|
|
|
+/// \brief converts any type to a string
|
|
|
+///
|
|
|
+/// The default template forwards on to ostringstream - except when an
|
|
|
+/// ostringstream overload does not exist - in which case it attempts to detect
|
|
|
+/// that and writes {?}.
|
|
|
+/// Overload (not specialise) this template for custom typs that you don't want
|
|
|
+/// to provide an ostream overload for.
|
|
|
+template<typename T>
|
|
|
+std::string toString( T const& value ) {
|
|
|
+ return StringMaker<T>::convert( value );
|
|
|
+}
|
|
|
|
|
|
namespace Detail {
|
|
|
template<typename InputIterator>
|
|
@@ -1195,10 +1783,9 @@ std::string toString( std::nullptr_t );
|
|
|
std::ostringstream oss;
|
|
|
oss << "{ ";
|
|
|
if( first != last ) {
|
|
|
- oss << toString( *first );
|
|
|
- for( ++first ; first != last ; ++first ) {
|
|
|
- oss << ", " << toString( *first );
|
|
|
- }
|
|
|
+ oss << Catch::toString( *first );
|
|
|
+ for( ++first ; first != last ; ++first )
|
|
|
+ oss << ", " << Catch::toString( *first );
|
|
|
}
|
|
|
oss << " }";
|
|
|
return oss.str();
|
|
@@ -1214,13 +1801,13 @@ namespace Catch {
|
|
|
template<typename T>
|
|
|
class ExpressionLhs {
|
|
|
ExpressionLhs& operator = ( ExpressionLhs const& );
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
|
|
|
# endif
|
|
|
|
|
|
public:
|
|
|
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
ExpressionLhs( ExpressionLhs const& ) = default;
|
|
|
ExpressionLhs( ExpressionLhs && ) = default;
|
|
|
# endif
|
|
@@ -1301,11 +1888,11 @@ private:
|
|
|
namespace Catch {
|
|
|
|
|
|
template<typename T>
|
|
|
- inline ExpressionLhs<T const&> ResultBuilder::operator->* ( T const& operand ) {
|
|
|
+ inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
|
|
|
return ExpressionLhs<T const&>( *this, operand );
|
|
|
}
|
|
|
|
|
|
- inline ExpressionLhs<bool> ResultBuilder::operator->* ( bool value ) {
|
|
|
+ inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) {
|
|
|
return ExpressionLhs<bool>( *this, value );
|
|
|
}
|
|
|
|
|
@@ -1378,6 +1965,7 @@ namespace Catch {
|
|
|
class AssertionResult;
|
|
|
struct AssertionInfo;
|
|
|
struct SectionInfo;
|
|
|
+ struct SectionEndInfo;
|
|
|
struct MessageInfo;
|
|
|
class ScopedMessageBuilder;
|
|
|
struct Counts;
|
|
@@ -1389,12 +1977,15 @@ namespace Catch {
|
|
|
virtual void assertionEnded( AssertionResult const& result ) = 0;
|
|
|
virtual bool sectionStarted( SectionInfo const& sectionInfo,
|
|
|
Counts& assertions ) = 0;
|
|
|
- virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
|
|
|
+ virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
|
|
+ virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
|
|
|
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
|
|
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
|
|
|
|
|
virtual std::string getCurrentTestName() const = 0;
|
|
|
virtual const AssertionResult* getLastResult() const = 0;
|
|
|
+
|
|
|
+ virtual void handleFatalErrorCondition( std::string const& message ) = 0;
|
|
|
};
|
|
|
|
|
|
IResultCapture& getResultCapture();
|
|
@@ -1475,13 +2066,14 @@ namespace Catch {
|
|
|
do { \
|
|
|
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
|
|
try { \
|
|
|
- ( __catchResult->*expr ).endExpression(); \
|
|
|
+ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
|
|
+ ( __catchResult <= expr ).endExpression(); \
|
|
|
} \
|
|
|
catch( ... ) { \
|
|
|
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
|
|
|
} \
|
|
|
INTERNAL_CATCH_REACT( __catchResult ) \
|
|
|
- } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
|
|
|
+ } while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
|
|
@@ -1508,16 +2100,16 @@ namespace Catch {
|
|
|
} while( Catch::alwaysFalse() )
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
-#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \
|
|
|
+#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \
|
|
|
do { \
|
|
|
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
|
|
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
|
|
|
if( __catchResult.allowThrows() ) \
|
|
|
try { \
|
|
|
expr; \
|
|
|
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
|
|
} \
|
|
|
catch( ... ) { \
|
|
|
- __catchResult.captureResult( Catch::ResultWas::Ok ); \
|
|
|
+ __catchResult.captureExpectedException( matcher ); \
|
|
|
} \
|
|
|
else \
|
|
|
__catchResult.captureResult( Catch::ResultWas::Ok ); \
|
|
@@ -1570,14 +2162,14 @@ namespace Catch {
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
|
|
|
do { \
|
|
|
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
|
|
|
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
|
|
|
try { \
|
|
|
- std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \
|
|
|
+ std::string matcherAsString = (matcher).toString(); \
|
|
|
__catchResult \
|
|
|
.setLhs( Catch::toString( arg ) ) \
|
|
|
- .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \
|
|
|
+ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
|
|
|
.setOp( "matches" ) \
|
|
|
- .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
|
|
|
+ .setResultType( (matcher).match( arg ) ); \
|
|
|
__catchResult.captureExpression(); \
|
|
|
} catch( ... ) { \
|
|
|
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
|
|
@@ -1591,21 +2183,6 @@ namespace Catch {
|
|
|
// #included from: catch_section_info.h
|
|
|
#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
|
|
|
|
|
|
-namespace Catch {
|
|
|
-
|
|
|
- struct SectionInfo {
|
|
|
- SectionInfo
|
|
|
- ( SourceLineInfo const& _lineInfo,
|
|
|
- std::string const& _name,
|
|
|
- std::string const& _description = std::string() );
|
|
|
-
|
|
|
- std::string name;
|
|
|
- std::string description;
|
|
|
- SourceLineInfo lineInfo;
|
|
|
- };
|
|
|
-
|
|
|
-} // end namespace Catch
|
|
|
-
|
|
|
// #included from: catch_totals.hpp
|
|
|
#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
|
|
|
|
|
@@ -1636,6 +2213,9 @@ namespace Catch {
|
|
|
bool allPassed() const {
|
|
|
return failed == 0 && failedButOk == 0;
|
|
|
}
|
|
|
+ bool allOk() const {
|
|
|
+ return failed == 0;
|
|
|
+ }
|
|
|
|
|
|
std::size_t passed;
|
|
|
std::size_t failed;
|
|
@@ -1673,6 +2253,31 @@ namespace Catch {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+namespace Catch {
|
|
|
+
|
|
|
+ struct SectionInfo {
|
|
|
+ SectionInfo
|
|
|
+ ( SourceLineInfo const& _lineInfo,
|
|
|
+ std::string const& _name,
|
|
|
+ std::string const& _description = std::string() );
|
|
|
+
|
|
|
+ std::string name;
|
|
|
+ std::string description;
|
|
|
+ SourceLineInfo lineInfo;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct SectionEndInfo {
|
|
|
+ SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
|
|
|
+ : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
|
|
|
+ {}
|
|
|
+
|
|
|
+ SectionInfo sectionInfo;
|
|
|
+ Counts prevAssertions;
|
|
|
+ double durationInSeconds;
|
|
|
+ };
|
|
|
+
|
|
|
+} // end namespace Catch
|
|
|
+
|
|
|
// #included from: catch_timer.h
|
|
|
#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
|
|
|
|
|
@@ -1688,7 +2293,7 @@ namespace Catch {
|
|
|
public:
|
|
|
Timer() : m_ticks( 0 ) {}
|
|
|
void start();
|
|
|
- unsigned int getElapsedNanoseconds() const;
|
|
|
+ unsigned int getElapsedMicroseconds() const;
|
|
|
unsigned int getElapsedMilliseconds() const;
|
|
|
double getElapsedSeconds() const;
|
|
|
|
|
@@ -1702,7 +2307,7 @@ namespace Catch {
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
- class Section {
|
|
|
+ class Section : NonCopyable {
|
|
|
public:
|
|
|
Section( SectionInfo const& info );
|
|
|
~Section();
|
|
@@ -1711,15 +2316,6 @@ namespace Catch {
|
|
|
operator bool() const;
|
|
|
|
|
|
private:
|
|
|
-#ifdef CATCH_CPP11_OR_GREATER
|
|
|
- Section( Section const& ) = delete;
|
|
|
- Section( Section && ) = delete;
|
|
|
- Section& operator = ( Section const& ) = delete;
|
|
|
- Section& operator = ( Section && ) = delete;
|
|
|
-#else
|
|
|
- Section( Section const& info );
|
|
|
- Section& operator = ( Section const& );
|
|
|
-#endif
|
|
|
SectionInfo m_info;
|
|
|
|
|
|
std::string m_name;
|
|
@@ -1922,6 +2518,8 @@ using namespace Generators;
|
|
|
#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
|
|
|
|
|
|
#include <string>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
// #included from: catch_interfaces_registry_hub.h
|
|
|
#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
|
|
|
|
|
@@ -1946,7 +2544,8 @@ namespace Catch {
|
|
|
|
|
|
struct IMutableRegistryHub {
|
|
|
virtual ~IMutableRegistryHub();
|
|
|
- virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0;
|
|
|
+ virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
|
|
|
+ virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
|
|
|
virtual void registerTest( TestCase const& testInfo ) = 0;
|
|
|
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
|
|
|
};
|
|
@@ -1958,14 +2557,16 @@ namespace Catch {
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
namespace Catch {
|
|
|
|
|
|
typedef std::string(*exceptionTranslateFunction)();
|
|
|
|
|
|
+ struct IExceptionTranslator;
|
|
|
+ typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
|
|
|
+
|
|
|
struct IExceptionTranslator {
|
|
|
virtual ~IExceptionTranslator();
|
|
|
- virtual std::string translate() const = 0;
|
|
|
+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
|
|
|
};
|
|
|
|
|
|
struct IExceptionTranslatorRegistry {
|
|
@@ -1983,9 +2584,12 @@ namespace Catch {
|
|
|
: m_translateFunction( translateFunction )
|
|
|
{}
|
|
|
|
|
|
- virtual std::string translate() const {
|
|
|
+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
|
|
|
try {
|
|
|
- throw;
|
|
|
+ if( it == itEnd )
|
|
|
+ throw;
|
|
|
+ else
|
|
|
+ return (*it)->translate( it+1, itEnd );
|
|
|
}
|
|
|
catch( T& ex ) {
|
|
|
return m_translateFunction( ex );
|
|
@@ -2006,10 +2610,12 @@ namespace Catch {
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
-#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
|
|
|
- static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
|
|
|
- namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
|
|
|
- static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
|
|
|
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
|
|
|
+ static std::string translatorName( signature ); \
|
|
|
+ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
|
|
|
+ static std::string translatorName( signature )
|
|
|
+
|
|
|
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
|
|
|
|
|
// #included from: internal/catch_approx.hpp
|
|
|
#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
|
|
@@ -2043,279 +2649,54 @@ namespace Detail {
|
|
|
approx.epsilon( m_epsilon );
|
|
|
approx.scale( m_scale );
|
|
|
return approx;
|
|
|
- }
|
|
|
-
|
|
|
- friend bool operator == ( double lhs, Approx const& rhs ) {
|
|
|
- // Thanks to Richard Harris for his help refining this formula
|
|
|
- return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
|
|
|
- }
|
|
|
-
|
|
|
- friend bool operator == ( Approx const& lhs, double rhs ) {
|
|
|
- return operator==( rhs, lhs );
|
|
|
- }
|
|
|
-
|
|
|
- friend bool operator != ( double lhs, Approx const& rhs ) {
|
|
|
- return !operator==( lhs, rhs );
|
|
|
- }
|
|
|
-
|
|
|
- friend bool operator != ( Approx const& lhs, double rhs ) {
|
|
|
- return !operator==( rhs, lhs );
|
|
|
- }
|
|
|
-
|
|
|
- Approx& epsilon( double newEpsilon ) {
|
|
|
- m_epsilon = newEpsilon;
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
- Approx& scale( double newScale ) {
|
|
|
- m_scale = newScale;
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
- std::string toString() const {
|
|
|
- std::ostringstream oss;
|
|
|
- oss << "Approx( " << Catch::toString( m_value ) << " )";
|
|
|
- return oss.str();
|
|
|
- }
|
|
|
-
|
|
|
- private:
|
|
|
- double m_epsilon;
|
|
|
- double m_scale;
|
|
|
- double m_value;
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-template<>
|
|
|
-inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
|
|
|
- return value.toString();
|
|
|
-}
|
|
|
-
|
|
|
-} // end namespace Catch
|
|
|
-
|
|
|
-// #included from: internal/catch_matchers.hpp
|
|
|
-#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
|
|
-
|
|
|
-namespace Catch {
|
|
|
-namespace Matchers {
|
|
|
- namespace Impl {
|
|
|
-
|
|
|
- template<typename ExpressionT>
|
|
|
- struct Matcher : SharedImpl<IShared>
|
|
|
- {
|
|
|
- typedef ExpressionT ExpressionType;
|
|
|
-
|
|
|
- virtual ~Matcher() {}
|
|
|
- virtual Ptr<Matcher> clone() const = 0;
|
|
|
- virtual bool match( ExpressionT const& expr ) const = 0;
|
|
|
- virtual std::string toString() const = 0;
|
|
|
- };
|
|
|
-
|
|
|
- template<typename DerivedT, typename ExpressionT>
|
|
|
- struct MatcherImpl : Matcher<ExpressionT> {
|
|
|
-
|
|
|
- virtual Ptr<Matcher<ExpressionT> > clone() const {
|
|
|
- return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- namespace Generic {
|
|
|
-
|
|
|
- template<typename ExpressionT>
|
|
|
- class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
|
|
|
- public:
|
|
|
-
|
|
|
- AllOf() {}
|
|
|
- AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
|
|
|
-
|
|
|
- AllOf& add( Matcher<ExpressionT> const& matcher ) {
|
|
|
- m_matchers.push_back( matcher.clone() );
|
|
|
- return *this;
|
|
|
- }
|
|
|
- virtual bool match( ExpressionT const& expr ) const
|
|
|
- {
|
|
|
- for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
|
|
- if( !m_matchers[i]->match( expr ) )
|
|
|
- return false;
|
|
|
- return true;
|
|
|
- }
|
|
|
- virtual std::string toString() const {
|
|
|
- std::ostringstream oss;
|
|
|
- oss << "( ";
|
|
|
- for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
|
|
- if( i != 0 )
|
|
|
- oss << " and ";
|
|
|
- oss << m_matchers[i]->toString();
|
|
|
- }
|
|
|
- oss << " )";
|
|
|
- return oss.str();
|
|
|
- }
|
|
|
-
|
|
|
- private:
|
|
|
- std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
|
|
- };
|
|
|
-
|
|
|
- template<typename ExpressionT>
|
|
|
- class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
|
|
|
- public:
|
|
|
-
|
|
|
- AnyOf() {}
|
|
|
- AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
|
|
|
-
|
|
|
- AnyOf& add( Matcher<ExpressionT> const& matcher ) {
|
|
|
- m_matchers.push_back( matcher.clone() );
|
|
|
- return *this;
|
|
|
- }
|
|
|
- virtual bool match( ExpressionT const& expr ) const
|
|
|
- {
|
|
|
- for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
|
|
- if( m_matchers[i]->match( expr ) )
|
|
|
- return true;
|
|
|
- return false;
|
|
|
- }
|
|
|
- virtual std::string toString() const {
|
|
|
- std::ostringstream oss;
|
|
|
- oss << "( ";
|
|
|
- for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
|
|
- if( i != 0 )
|
|
|
- oss << " or ";
|
|
|
- oss << m_matchers[i]->toString();
|
|
|
- }
|
|
|
- oss << " )";
|
|
|
- return oss.str();
|
|
|
- }
|
|
|
-
|
|
|
- private:
|
|
|
- std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
|
|
- };
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- namespace StdString {
|
|
|
-
|
|
|
- inline std::string makeString( std::string const& str ) { return str; }
|
|
|
- inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
|
|
|
-
|
|
|
- struct Equals : MatcherImpl<Equals, std::string> {
|
|
|
- Equals( std::string const& str ) : m_str( str ){}
|
|
|
- Equals( Equals const& other ) : m_str( other.m_str ){}
|
|
|
-
|
|
|
- virtual ~Equals();
|
|
|
-
|
|
|
- virtual bool match( std::string const& expr ) const {
|
|
|
- return m_str == expr;
|
|
|
- }
|
|
|
- virtual std::string toString() const {
|
|
|
- return "equals: \"" + m_str + "\"";
|
|
|
- }
|
|
|
-
|
|
|
- std::string m_str;
|
|
|
- };
|
|
|
-
|
|
|
- struct Contains : MatcherImpl<Contains, std::string> {
|
|
|
- Contains( std::string const& substr ) : m_substr( substr ){}
|
|
|
- Contains( Contains const& other ) : m_substr( other.m_substr ){}
|
|
|
-
|
|
|
- virtual ~Contains();
|
|
|
-
|
|
|
- virtual bool match( std::string const& expr ) const {
|
|
|
- return expr.find( m_substr ) != std::string::npos;
|
|
|
- }
|
|
|
- virtual std::string toString() const {
|
|
|
- return "contains: \"" + m_substr + "\"";
|
|
|
- }
|
|
|
-
|
|
|
- std::string m_substr;
|
|
|
- };
|
|
|
-
|
|
|
- struct StartsWith : MatcherImpl<StartsWith, std::string> {
|
|
|
- StartsWith( std::string const& substr ) : m_substr( substr ){}
|
|
|
- StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){}
|
|
|
-
|
|
|
- virtual ~StartsWith();
|
|
|
-
|
|
|
- virtual bool match( std::string const& expr ) const {
|
|
|
- return expr.find( m_substr ) == 0;
|
|
|
- }
|
|
|
- virtual std::string toString() const {
|
|
|
- return "starts with: \"" + m_substr + "\"";
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- std::string m_substr;
|
|
|
- };
|
|
|
+ friend bool operator == ( double lhs, Approx const& rhs ) {
|
|
|
+ // Thanks to Richard Harris for his help refining this formula
|
|
|
+ return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
|
|
|
+ }
|
|
|
|
|
|
- struct EndsWith : MatcherImpl<EndsWith, std::string> {
|
|
|
- EndsWith( std::string const& substr ) : m_substr( substr ){}
|
|
|
- EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){}
|
|
|
+ friend bool operator == ( Approx const& lhs, double rhs ) {
|
|
|
+ return operator==( rhs, lhs );
|
|
|
+ }
|
|
|
|
|
|
- virtual ~EndsWith();
|
|
|
+ friend bool operator != ( double lhs, Approx const& rhs ) {
|
|
|
+ return !operator==( lhs, rhs );
|
|
|
+ }
|
|
|
|
|
|
- virtual bool match( std::string const& expr ) const {
|
|
|
- return expr.find( m_substr ) == expr.size() - m_substr.size();
|
|
|
- }
|
|
|
- virtual std::string toString() const {
|
|
|
- return "ends with: \"" + m_substr + "\"";
|
|
|
- }
|
|
|
+ friend bool operator != ( Approx const& lhs, double rhs ) {
|
|
|
+ return !operator==( rhs, lhs );
|
|
|
+ }
|
|
|
|
|
|
- std::string m_substr;
|
|
|
- };
|
|
|
- } // namespace StdString
|
|
|
- } // namespace Impl
|
|
|
+ Approx& epsilon( double newEpsilon ) {
|
|
|
+ m_epsilon = newEpsilon;
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
|
|
|
- // The following functions create the actual matcher objects.
|
|
|
- // This allows the types to be inferred
|
|
|
- template<typename ExpressionT>
|
|
|
- inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
|
|
- Impl::Matcher<ExpressionT> const& m2 ) {
|
|
|
- return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
|
|
|
- }
|
|
|
- template<typename ExpressionT>
|
|
|
- inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
|
|
- Impl::Matcher<ExpressionT> const& m2,
|
|
|
- Impl::Matcher<ExpressionT> const& m3 ) {
|
|
|
- return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
|
|
- }
|
|
|
- template<typename ExpressionT>
|
|
|
- inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
|
|
- Impl::Matcher<ExpressionT> const& m2 ) {
|
|
|
- return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
|
|
|
- }
|
|
|
- template<typename ExpressionT>
|
|
|
- inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
|
|
- Impl::Matcher<ExpressionT> const& m2,
|
|
|
- Impl::Matcher<ExpressionT> const& m3 ) {
|
|
|
- return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
|
|
- }
|
|
|
+ Approx& scale( double newScale ) {
|
|
|
+ m_scale = newScale;
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
|
|
|
- inline Impl::StdString::Equals Equals( std::string const& str ) {
|
|
|
- return Impl::StdString::Equals( str );
|
|
|
- }
|
|
|
- inline Impl::StdString::Equals Equals( const char* str ) {
|
|
|
- return Impl::StdString::Equals( Impl::StdString::makeString( str ) );
|
|
|
- }
|
|
|
- inline Impl::StdString::Contains Contains( std::string const& substr ) {
|
|
|
- return Impl::StdString::Contains( substr );
|
|
|
- }
|
|
|
- inline Impl::StdString::Contains Contains( const char* substr ) {
|
|
|
- return Impl::StdString::Contains( Impl::StdString::makeString( substr ) );
|
|
|
- }
|
|
|
- inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
|
|
|
- return Impl::StdString::StartsWith( substr );
|
|
|
- }
|
|
|
- inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
|
|
|
- return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
|
|
|
- }
|
|
|
- inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
|
|
|
- return Impl::StdString::EndsWith( substr );
|
|
|
- }
|
|
|
- inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
|
|
|
- return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
|
|
|
- }
|
|
|
+ std::string toString() const {
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << "Approx( " << Catch::toString( m_value ) << " )";
|
|
|
+ return oss.str();
|
|
|
+ }
|
|
|
|
|
|
-} // namespace Matchers
|
|
|
+ private:
|
|
|
+ double m_epsilon;
|
|
|
+ double m_scale;
|
|
|
+ double m_value;
|
|
|
+ };
|
|
|
+}
|
|
|
|
|
|
-using namespace Matchers;
|
|
|
+template<>
|
|
|
+inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
|
|
|
+ return value.toString();
|
|
|
+}
|
|
|
|
|
|
-} // namespace Catch
|
|
|
+} // end namespace Catch
|
|
|
|
|
|
// #included from: internal/catch_interfaces_tag_alias_registry.h
|
|
|
#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
|
|
@@ -2350,12 +2731,12 @@ namespace Catch {
|
|
|
template<typename T>
|
|
|
class Option {
|
|
|
public:
|
|
|
- Option() : nullableValue( NULL ) {}
|
|
|
+ Option() : nullableValue( CATCH_NULL ) {}
|
|
|
Option( T const& _value )
|
|
|
: nullableValue( new( storage ) T( _value ) )
|
|
|
{}
|
|
|
Option( Option const& _other )
|
|
|
- : nullableValue( _other ? new( storage ) T( *_other ) : NULL )
|
|
|
+ : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL )
|
|
|
{}
|
|
|
|
|
|
~Option() {
|
|
@@ -2379,7 +2760,7 @@ namespace Catch {
|
|
|
void reset() {
|
|
|
if( nullableValue )
|
|
|
nullableValue->~T();
|
|
|
- nullableValue = NULL;
|
|
|
+ nullableValue = CATCH_NULL;
|
|
|
}
|
|
|
|
|
|
T& operator*() { return *nullableValue; }
|
|
@@ -2391,10 +2772,10 @@ namespace Catch {
|
|
|
return nullableValue ? *nullableValue : defaultValue;
|
|
|
}
|
|
|
|
|
|
- bool some() const { return nullableValue != NULL; }
|
|
|
- bool none() const { return nullableValue == NULL; }
|
|
|
+ bool some() const { return nullableValue != CATCH_NULL; }
|
|
|
+ bool none() const { return nullableValue == CATCH_NULL; }
|
|
|
|
|
|
- bool operator !() const { return nullableValue == NULL; }
|
|
|
+ bool operator !() const { return nullableValue == CATCH_NULL; }
|
|
|
operator SafeBool::type() const {
|
|
|
return SafeBool::makeSafe( some() );
|
|
|
}
|
|
@@ -2452,6 +2833,8 @@ namespace Catch {
|
|
|
|
|
|
TestCaseInfo( TestCaseInfo const& other );
|
|
|
|
|
|
+ friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
|
|
|
+
|
|
|
bool isHidden() const;
|
|
|
bool throws() const;
|
|
|
bool okToFail() const;
|
|
@@ -2564,7 +2947,7 @@ namespace Catch {
|
|
|
|
|
|
inline size_t registerTestMethods() {
|
|
|
size_t noTestMethods = 0;
|
|
|
- int noClasses = objc_getClassList( NULL, 0 );
|
|
|
+ int noClasses = objc_getClassList( CATCH_NULL, 0 );
|
|
|
|
|
|
Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
|
|
|
objc_getClassList( classes, noClasses );
|
|
@@ -2694,7 +3077,7 @@ return @ desc; \
|
|
|
|
|
|
#endif
|
|
|
|
|
|
-#ifdef CATCH_CONFIG_RUNNER
|
|
|
+#ifdef CATCH_IMPL
|
|
|
// #included from: internal/catch_impl.hpp
|
|
|
#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
|
|
|
|
|
@@ -2706,7 +3089,7 @@ return @ desc; \
|
|
|
#pragma clang diagnostic ignored "-Wweak-vtables"
|
|
|
#endif
|
|
|
|
|
|
-// #included from: catch_runner.hpp
|
|
|
+// #included from: ../catch_session.hpp
|
|
|
#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
|
|
|
|
|
|
// #included from: internal/catch_commandline.hpp
|
|
@@ -2731,6 +3114,67 @@ return @ desc; \
|
|
|
#pragma clang diagnostic ignored "-Wpadded"
|
|
|
#endif
|
|
|
|
|
|
+// #included from: catch_wildcard_pattern.hpp
|
|
|
+#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
|
|
|
+
|
|
|
+namespace Catch
|
|
|
+{
|
|
|
+ class WildcardPattern {
|
|
|
+ enum WildcardPosition {
|
|
|
+ NoWildcard = 0,
|
|
|
+ WildcardAtStart = 1,
|
|
|
+ WildcardAtEnd = 2,
|
|
|
+ WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
|
|
|
+ };
|
|
|
+
|
|
|
+ public:
|
|
|
+
|
|
|
+ WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity )
|
|
|
+ : m_caseSensitivity( caseSensitivity ),
|
|
|
+ m_wildcard( NoWildcard ),
|
|
|
+ m_pattern( adjustCase( pattern ) )
|
|
|
+ {
|
|
|
+ if( startsWith( m_pattern, "*" ) ) {
|
|
|
+ m_pattern = m_pattern.substr( 1 );
|
|
|
+ m_wildcard = WildcardAtStart;
|
|
|
+ }
|
|
|
+ if( endsWith( m_pattern, "*" ) ) {
|
|
|
+ m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
|
|
|
+ m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ virtual ~WildcardPattern();
|
|
|
+ virtual bool matches( std::string const& str ) const {
|
|
|
+ switch( m_wildcard ) {
|
|
|
+ case NoWildcard:
|
|
|
+ return m_pattern == adjustCase( str );
|
|
|
+ case WildcardAtStart:
|
|
|
+ return endsWith( adjustCase( str ), m_pattern );
|
|
|
+ case WildcardAtEnd:
|
|
|
+ return startsWith( adjustCase( str ), m_pattern );
|
|
|
+ case WildcardAtBothEnds:
|
|
|
+ return contains( adjustCase( str ), m_pattern );
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef __clang__
|
|
|
+#pragma clang diagnostic push
|
|
|
+#pragma clang diagnostic ignored "-Wunreachable-code"
|
|
|
+#endif
|
|
|
+ throw std::logic_error( "Unknown enum" );
|
|
|
+#ifdef __clang__
|
|
|
+#pragma clang diagnostic pop
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ std::string adjustCase( std::string const& str ) const {
|
|
|
+ return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
|
|
|
+ }
|
|
|
+ CaseSensitive::Choice m_caseSensitivity;
|
|
|
+ WildcardPosition m_wildcard;
|
|
|
+ std::string m_pattern;
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
#include <string>
|
|
|
#include <vector>
|
|
|
|
|
@@ -2742,50 +3186,18 @@ namespace Catch {
|
|
|
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
|
|
|
};
|
|
|
class NamePattern : public Pattern {
|
|
|
- enum WildcardPosition {
|
|
|
- NoWildcard = 0,
|
|
|
- WildcardAtStart = 1,
|
|
|
- WildcardAtEnd = 2,
|
|
|
- WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
|
|
|
- };
|
|
|
-
|
|
|
public:
|
|
|
- NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) {
|
|
|
- if( startsWith( m_name, "*" ) ) {
|
|
|
- m_name = m_name.substr( 1 );
|
|
|
- m_wildcard = WildcardAtStart;
|
|
|
- }
|
|
|
- if( endsWith( m_name, "*" ) ) {
|
|
|
- m_name = m_name.substr( 0, m_name.size()-1 );
|
|
|
- m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
|
|
|
- }
|
|
|
- }
|
|
|
+ NamePattern( std::string const& name )
|
|
|
+ : m_wildcardPattern( toLower( name ), CaseSensitive::No )
|
|
|
+ {}
|
|
|
virtual ~NamePattern();
|
|
|
virtual bool matches( TestCaseInfo const& testCase ) const {
|
|
|
- switch( m_wildcard ) {
|
|
|
- case NoWildcard:
|
|
|
- return m_name == toLower( testCase.name );
|
|
|
- case WildcardAtStart:
|
|
|
- return endsWith( toLower( testCase.name ), m_name );
|
|
|
- case WildcardAtEnd:
|
|
|
- return startsWith( toLower( testCase.name ), m_name );
|
|
|
- case WildcardAtBothEnds:
|
|
|
- return contains( toLower( testCase.name ), m_name );
|
|
|
- }
|
|
|
-
|
|
|
-#ifdef __clang__
|
|
|
-#pragma clang diagnostic push
|
|
|
-#pragma clang diagnostic ignored "-Wunreachable-code"
|
|
|
-#endif
|
|
|
- throw std::logic_error( "Unknown enum" );
|
|
|
-#ifdef __clang__
|
|
|
-#pragma clang diagnostic pop
|
|
|
-#endif
|
|
|
+ return m_wildcardPattern.matches( toLower( testCase.name ) );
|
|
|
}
|
|
|
private:
|
|
|
- std::string m_name;
|
|
|
- WildcardPosition m_wildcard;
|
|
|
+ WildcardPattern m_wildcardPattern;
|
|
|
};
|
|
|
+
|
|
|
class TagPattern : public Pattern {
|
|
|
public:
|
|
|
TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
|
|
@@ -2796,6 +3208,7 @@ namespace Catch {
|
|
|
private:
|
|
|
std::string m_tag;
|
|
|
};
|
|
|
+
|
|
|
class ExcludedPattern : public Pattern {
|
|
|
public:
|
|
|
ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
|
|
@@ -2810,10 +3223,11 @@ namespace Catch {
|
|
|
|
|
|
bool matches( TestCaseInfo const& testCase ) const {
|
|
|
// All patterns in a filter must match for the filter to be a match
|
|
|
- for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
|
|
|
+ for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
|
|
|
if( !(*it)->matches( testCase ) )
|
|
|
return false;
|
|
|
- return true;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -2962,6 +3376,16 @@ namespace Catch {
|
|
|
Always,
|
|
|
Never
|
|
|
}; };
|
|
|
+ struct RunTests { enum InWhatOrder {
|
|
|
+ InDeclarationOrder,
|
|
|
+ InLexicographicalOrder,
|
|
|
+ InRandomOrder
|
|
|
+ }; };
|
|
|
+ struct UseColour { enum YesOrNo {
|
|
|
+ Auto,
|
|
|
+ Yes,
|
|
|
+ No
|
|
|
+ }; };
|
|
|
|
|
|
class TestSpec;
|
|
|
|
|
@@ -2979,30 +3403,70 @@ namespace Catch {
|
|
|
virtual bool showInvisibles() const = 0;
|
|
|
virtual ShowDurations::OrNot showDurations() const = 0;
|
|
|
virtual TestSpec const& testSpec() const = 0;
|
|
|
+ virtual RunTests::InWhatOrder runOrder() const = 0;
|
|
|
+ virtual unsigned int rngSeed() const = 0;
|
|
|
+ virtual UseColour::YesOrNo useColour() const = 0;
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// #included from: catch_stream.h
|
|
|
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
|
|
|
|
|
|
+// #included from: catch_streambuf.h
|
|
|
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
|
|
|
+
|
|
|
#include <streambuf>
|
|
|
|
|
|
-#ifdef __clang__
|
|
|
-#pragma clang diagnostic ignored "-Wpadded"
|
|
|
-#endif
|
|
|
+namespace Catch {
|
|
|
+
|
|
|
+ class StreamBufBase : public std::streambuf {
|
|
|
+ public:
|
|
|
+ virtual ~StreamBufBase() CATCH_NOEXCEPT;
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+#include <streambuf>
|
|
|
+#include <ostream>
|
|
|
+#include <fstream>
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
- class Stream {
|
|
|
+ std::ostream& cout();
|
|
|
+ std::ostream& cerr();
|
|
|
+
|
|
|
+ struct IStream {
|
|
|
+ virtual ~IStream() CATCH_NOEXCEPT;
|
|
|
+ virtual std::ostream& stream() const = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ class FileStream : public IStream {
|
|
|
+ mutable std::ofstream m_ofs;
|
|
|
+ public:
|
|
|
+ FileStream( std::string const& filename );
|
|
|
+ virtual ~FileStream() CATCH_NOEXCEPT;
|
|
|
+ public: // IStream
|
|
|
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
|
|
|
+ };
|
|
|
+
|
|
|
+ class CoutStream : public IStream {
|
|
|
+ mutable std::ostream m_os;
|
|
|
public:
|
|
|
- Stream();
|
|
|
- Stream( std::streambuf* _streamBuf, bool _isOwned );
|
|
|
- void release();
|
|
|
+ CoutStream();
|
|
|
+ virtual ~CoutStream() CATCH_NOEXCEPT;
|
|
|
|
|
|
- std::streambuf* streamBuf;
|
|
|
+ public: // IStream
|
|
|
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
|
|
|
+ };
|
|
|
|
|
|
- private:
|
|
|
- bool isOwned;
|
|
|
+ class DebugOutStream : public IStream {
|
|
|
+ CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
|
|
|
+ mutable std::ostream m_os;
|
|
|
+ public:
|
|
|
+ DebugOutStream();
|
|
|
+ virtual ~DebugOutStream() CATCH_NOEXCEPT;
|
|
|
+
|
|
|
+ public: // IStream
|
|
|
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -3010,6 +3474,7 @@ namespace Catch {
|
|
|
#include <vector>
|
|
|
#include <string>
|
|
|
#include <iostream>
|
|
|
+#include <ctime>
|
|
|
|
|
|
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
|
|
|
#define CATCH_CONFIG_CONSOLE_WIDTH 80
|
|
@@ -3029,10 +3494,14 @@ namespace Catch {
|
|
|
noThrow( false ),
|
|
|
showHelp( false ),
|
|
|
showInvisibles( false ),
|
|
|
+ filenamesAsTags( false ),
|
|
|
abortAfter( -1 ),
|
|
|
+ rngSeed( 0 ),
|
|
|
verbosity( Verbosity::Normal ),
|
|
|
warnings( WarnAbout::Nothing ),
|
|
|
- showDurations( ShowDurations::DefaultForReporter )
|
|
|
+ showDurations( ShowDurations::DefaultForReporter ),
|
|
|
+ runOrder( RunTests::InDeclarationOrder ),
|
|
|
+ useColour( UseColour::Auto )
|
|
|
{}
|
|
|
|
|
|
bool listTests;
|
|
@@ -3045,18 +3514,22 @@ namespace Catch {
|
|
|
bool noThrow;
|
|
|
bool showHelp;
|
|
|
bool showInvisibles;
|
|
|
+ bool filenamesAsTags;
|
|
|
|
|
|
int abortAfter;
|
|
|
+ unsigned int rngSeed;
|
|
|
|
|
|
Verbosity::Level verbosity;
|
|
|
WarnAbout::What warnings;
|
|
|
ShowDurations::OrNot showDurations;
|
|
|
+ RunTests::InWhatOrder runOrder;
|
|
|
+ UseColour::YesOrNo useColour;
|
|
|
|
|
|
- std::string reporterName;
|
|
|
std::string outputFilename;
|
|
|
std::string name;
|
|
|
std::string processName;
|
|
|
|
|
|
+ std::vector<std::string> reporterNames;
|
|
|
std::vector<std::string> testsOrTags;
|
|
|
};
|
|
|
|
|
@@ -3068,12 +3541,11 @@ namespace Catch {
|
|
|
public:
|
|
|
|
|
|
Config()
|
|
|
- : m_os( std::cout.rdbuf() )
|
|
|
{}
|
|
|
|
|
|
Config( ConfigData const& data )
|
|
|
: m_data( data ),
|
|
|
- m_os( std::cout.rdbuf() )
|
|
|
+ m_stream( openStream() )
|
|
|
{
|
|
|
if( !data.testsOrTags.empty() ) {
|
|
|
TestSpecParser parser( ITagAliasRegistry::get() );
|
|
@@ -3084,12 +3556,6 @@ namespace Catch {
|
|
|
}
|
|
|
|
|
|
virtual ~Config() {
|
|
|
- m_os.rdbuf( std::cout.rdbuf() );
|
|
|
- m_stream.release();
|
|
|
- }
|
|
|
-
|
|
|
- void setFilename( std::string const& filename ) {
|
|
|
- m_data.outputFilename = filename;
|
|
|
}
|
|
|
|
|
|
std::string const& getFilename() const {
|
|
@@ -3105,18 +3571,7 @@ namespace Catch {
|
|
|
|
|
|
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
|
|
|
|
|
- void setStreamBuf( std::streambuf* buf ) {
|
|
|
- m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
|
|
|
- }
|
|
|
-
|
|
|
- void useStream( std::string const& streamName ) {
|
|
|
- Stream stream = createStream( streamName );
|
|
|
- setStreamBuf( stream.streamBuf );
|
|
|
- m_stream.release();
|
|
|
- m_stream = stream;
|
|
|
- }
|
|
|
-
|
|
|
- std::string getReporterName() const { return m_data.reporterName; }
|
|
|
+ std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
|
|
|
|
|
|
int abortAfter() const { return m_data.abortAfter; }
|
|
|
|
|
@@ -3127,17 +3582,32 @@ namespace Catch {
|
|
|
|
|
|
// IConfig interface
|
|
|
virtual bool allowThrows() const { return !m_data.noThrow; }
|
|
|
- virtual std::ostream& stream() const { return m_os; }
|
|
|
+ virtual std::ostream& stream() const { return m_stream->stream(); }
|
|
|
virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
|
|
virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
|
|
virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
|
|
|
virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
|
|
|
+ virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; }
|
|
|
+ virtual unsigned int rngSeed() const { return m_data.rngSeed; }
|
|
|
+ virtual UseColour::YesOrNo useColour() const { return m_data.useColour; }
|
|
|
|
|
|
private:
|
|
|
+
|
|
|
+ IStream const* openStream() {
|
|
|
+ if( m_data.outputFilename.empty() )
|
|
|
+ return new CoutStream();
|
|
|
+ else if( m_data.outputFilename[0] == '%' ) {
|
|
|
+ if( m_data.outputFilename == "%debug" )
|
|
|
+ return new DebugOutStream();
|
|
|
+ else
|
|
|
+ throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return new FileStream( m_data.outputFilename );
|
|
|
+ }
|
|
|
ConfigData m_data;
|
|
|
|
|
|
- Stream m_stream;
|
|
|
- mutable std::ostream m_os;
|
|
|
+ CATCH_AUTO_PTR( IStream const ) m_stream;
|
|
|
TestSpec m_testSpec;
|
|
|
};
|
|
|
|
|
@@ -3157,6 +3627,8 @@ namespace Catch {
|
|
|
#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
|
|
|
// #included from: ../external/clara.h
|
|
|
|
|
|
+// Version 0.0.2.4
|
|
|
+
|
|
|
// Only use header guard if we are not using an outer namespace
|
|
|
#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
|
|
|
|
|
@@ -3181,6 +3653,7 @@ namespace Catch {
|
|
|
#include <string>
|
|
|
#include <vector>
|
|
|
#include <sstream>
|
|
|
+#include <algorithm>
|
|
|
|
|
|
// Use optional outer namespace
|
|
|
#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
|
@@ -3308,22 +3781,172 @@ namespace Tbc {
|
|
|
|
|
|
} // end namespace Tbc
|
|
|
|
|
|
-#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
|
|
-} // end outer namespace
|
|
|
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
|
|
+} // end outer namespace
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
|
|
|
+
|
|
|
+// ----------- end of #include from tbc_text_format.h -----------
|
|
|
+// ........... back in clara.h
|
|
|
+
|
|
|
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
|
|
|
+
|
|
|
+// ----------- #included from clara_compilers.h -----------
|
|
|
+
|
|
|
+#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
|
|
|
+#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
|
|
|
+
|
|
|
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
|
|
|
+// The following features are defined:
|
|
|
+//
|
|
|
+// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported?
|
|
|
+// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
|
|
|
+// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
|
|
|
+// CLARA_CONFIG_CPP11_OVERRIDE : is override supported?
|
|
|
+// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
|
|
|
+
|
|
|
+// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
|
|
|
+
|
|
|
+// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported?
|
|
|
+
|
|
|
+// In general each macro has a _NO_<feature name> form
|
|
|
+// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
|
|
|
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
|
|
|
+// can be combined, en-mass, with the _NO_ forms later.
|
|
|
+
|
|
|
+// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11
|
|
|
+
|
|
|
+#ifdef __clang__
|
|
|
+
|
|
|
+#if __has_feature(cxx_nullptr)
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
|
|
|
+#endif
|
|
|
+
|
|
|
+#if __has_feature(cxx_noexcept)
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif // __clang__
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////////////////
|
|
|
+// GCC
|
|
|
+#ifdef __GNUC__
|
|
|
+
|
|
|
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
|
|
|
+#endif
|
|
|
+
|
|
|
+// - otherwise more recent versions define __cplusplus >= 201103L
|
|
|
+// and will get picked up below
|
|
|
+
|
|
|
+#endif // __GNUC__
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////////////////
|
|
|
+// Visual C++
|
|
|
+#ifdef _MSC_VER
|
|
|
+
|
|
|
+#if (_MSC_VER >= 1600)
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
|
|
+#endif
|
|
|
+
|
|
|
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif // _MSC_VER
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////////////////
|
|
|
+// C++ language feature support
|
|
|
+
|
|
|
+// catch all support for C++11
|
|
|
+#if defined(__cplusplus) && __cplusplus >= 201103L
|
|
|
+
|
|
|
+#define CLARA_CPP11_OR_GREATER
|
|
|
+
|
|
|
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR)
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
|
|
+#endif
|
|
|
+
|
|
|
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE)
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE
|
|
|
+#endif
|
|
|
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
|
|
|
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif // __cplusplus >= 201103L
|
|
|
+
|
|
|
+// Now set the actual defines based on the above + anything the user has configured
|
|
|
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11)
|
|
|
+#define CLARA_CONFIG_CPP11_NULLPTR
|
|
|
+#endif
|
|
|
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11)
|
|
|
+#define CLARA_CONFIG_CPP11_NOEXCEPT
|
|
|
+#endif
|
|
|
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11)
|
|
|
+#define CLARA_CONFIG_CPP11_GENERATED_METHODS
|
|
|
+#endif
|
|
|
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11)
|
|
|
+#define CLARA_CONFIG_CPP11_OVERRIDE
|
|
|
+#endif
|
|
|
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11)
|
|
|
+#define CLARA_CONFIG_CPP11_UNIQUE_PTR
|
|
|
+#endif
|
|
|
+
|
|
|
+// noexcept support:
|
|
|
+#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT)
|
|
|
+#define CLARA_NOEXCEPT noexcept
|
|
|
+# define CLARA_NOEXCEPT_IS(x) noexcept(x)
|
|
|
+#else
|
|
|
+#define CLARA_NOEXCEPT throw()
|
|
|
+# define CLARA_NOEXCEPT_IS(x)
|
|
|
+#endif
|
|
|
+
|
|
|
+// nullptr support
|
|
|
+#ifdef CLARA_CONFIG_CPP11_NULLPTR
|
|
|
+#define CLARA_NULL nullptr
|
|
|
+#else
|
|
|
+#define CLARA_NULL NULL
|
|
|
+#endif
|
|
|
+
|
|
|
+// override support
|
|
|
+#ifdef CLARA_CONFIG_CPP11_OVERRIDE
|
|
|
+#define CLARA_OVERRIDE override
|
|
|
+#else
|
|
|
+#define CLARA_OVERRIDE
|
|
|
#endif
|
|
|
|
|
|
-#endif // TBC_TEXT_FORMAT_H_INCLUDED
|
|
|
+// unique_ptr support
|
|
|
+#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR
|
|
|
+# define CLARA_AUTO_PTR( T ) std::unique_ptr<T>
|
|
|
+#else
|
|
|
+# define CLARA_AUTO_PTR( T ) std::auto_ptr<T>
|
|
|
+#endif
|
|
|
|
|
|
-// ----------- end of #include from tbc_text_format.h -----------
|
|
|
-// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
|
|
|
+#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
|
|
|
|
|
|
-#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
|
|
|
+// ----------- end of #include from clara_compilers.h -----------
|
|
|
+// ........... back in clara.h
|
|
|
|
|
|
#include <map>
|
|
|
-#include <algorithm>
|
|
|
#include <stdexcept>
|
|
|
#include <memory>
|
|
|
|
|
|
+#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
|
|
+#define CLARA_PLATFORM_WINDOWS
|
|
|
+#endif
|
|
|
+
|
|
|
// Use optional outer namespace
|
|
|
#ifdef STITCH_CLARA_OPEN_NAMESPACE
|
|
|
STITCH_CLARA_OPEN_NAMESPACE
|
|
@@ -3382,23 +4005,15 @@ namespace Clara {
|
|
|
else
|
|
|
throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
|
|
|
}
|
|
|
- inline void convertInto( bool _source, bool& _dest ) {
|
|
|
- _dest = _source;
|
|
|
- }
|
|
|
- template<typename T>
|
|
|
- inline void convertInto( bool, T& ) {
|
|
|
- throw std::runtime_error( "Invalid conversion" );
|
|
|
- }
|
|
|
|
|
|
template<typename ConfigT>
|
|
|
struct IArgFunction {
|
|
|
virtual ~IArgFunction() {}
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS
|
|
|
IArgFunction() = default;
|
|
|
IArgFunction( IArgFunction const& ) = default;
|
|
|
-# endif
|
|
|
+#endif
|
|
|
virtual void set( ConfigT& config, std::string const& value ) const = 0;
|
|
|
- virtual void setFlag( ConfigT& config ) const = 0;
|
|
|
virtual bool takesArg() const = 0;
|
|
|
virtual IArgFunction* clone() const = 0;
|
|
|
};
|
|
@@ -3406,11 +4021,11 @@ namespace Clara {
|
|
|
template<typename ConfigT>
|
|
|
class BoundArgFunction {
|
|
|
public:
|
|
|
- BoundArgFunction() : functionObj( NULL ) {}
|
|
|
+ BoundArgFunction() : functionObj( CLARA_NULL ) {}
|
|
|
BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
|
|
|
- BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {}
|
|
|
+ BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {}
|
|
|
BoundArgFunction& operator = ( BoundArgFunction const& other ) {
|
|
|
- IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL;
|
|
|
+ IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL;
|
|
|
delete functionObj;
|
|
|
functionObj = newFunctionObj;
|
|
|
return *this;
|
|
@@ -3420,13 +4035,10 @@ namespace Clara {
|
|
|
void set( ConfigT& config, std::string const& value ) const {
|
|
|
functionObj->set( config, value );
|
|
|
}
|
|
|
- void setFlag( ConfigT& config ) const {
|
|
|
- functionObj->setFlag( config );
|
|
|
- }
|
|
|
bool takesArg() const { return functionObj->takesArg(); }
|
|
|
|
|
|
bool isSet() const {
|
|
|
- return functionObj != NULL;
|
|
|
+ return functionObj != CLARA_NULL;
|
|
|
}
|
|
|
private:
|
|
|
IArgFunction<ConfigT>* functionObj;
|
|
@@ -3435,7 +4047,6 @@ namespace Clara {
|
|
|
template<typename C>
|
|
|
struct NullBinder : IArgFunction<C>{
|
|
|
virtual void set( C&, std::string const& ) const {}
|
|
|
- virtual void setFlag( C& ) const {}
|
|
|
virtual bool takesArg() const { return true; }
|
|
|
virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
|
|
|
};
|
|
@@ -3446,9 +4057,6 @@ namespace Clara {
|
|
|
virtual void set( C& p, std::string const& stringValue ) const {
|
|
|
convertInto( stringValue, p.*member );
|
|
|
}
|
|
|
- virtual void setFlag( C& p ) const {
|
|
|
- convertInto( true, p.*member );
|
|
|
- }
|
|
|
virtual bool takesArg() const { return !IsBool<M>::value; }
|
|
|
virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
|
|
|
M C::* member;
|
|
@@ -3461,11 +4069,6 @@ namespace Clara {
|
|
|
convertInto( stringValue, value );
|
|
|
(p.*member)( value );
|
|
|
}
|
|
|
- virtual void setFlag( C& p ) const {
|
|
|
- typename RemoveConstRef<M>::type value;
|
|
|
- convertInto( true, value );
|
|
|
- (p.*member)( value );
|
|
|
- }
|
|
|
virtual bool takesArg() const { return !IsBool<M>::value; }
|
|
|
virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
|
|
|
void (C::*member)( M );
|
|
@@ -3479,9 +4082,6 @@ namespace Clara {
|
|
|
if( value )
|
|
|
(p.*member)();
|
|
|
}
|
|
|
- virtual void setFlag( C& p ) const {
|
|
|
- (p.*member)();
|
|
|
- }
|
|
|
virtual bool takesArg() const { return false; }
|
|
|
virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
|
|
|
void (C::*member)();
|
|
@@ -3496,9 +4096,6 @@ namespace Clara {
|
|
|
if( value )
|
|
|
function( obj );
|
|
|
}
|
|
|
- virtual void setFlag( C& p ) const {
|
|
|
- function( p );
|
|
|
- }
|
|
|
virtual bool takesArg() const { return false; }
|
|
|
virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
|
|
|
void (*function)( C& );
|
|
@@ -3512,11 +4109,6 @@ namespace Clara {
|
|
|
convertInto( stringValue, value );
|
|
|
function( obj, value );
|
|
|
}
|
|
|
- virtual void setFlag( C& obj ) const {
|
|
|
- typename RemoveConstRef<T>::type value;
|
|
|
- convertInto( true, value );
|
|
|
- function( obj, value );
|
|
|
- }
|
|
|
virtual bool takesArg() const { return !IsBool<T>::value; }
|
|
|
virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
|
|
|
void (*function)( C&, T );
|
|
@@ -3524,8 +4116,20 @@ namespace Clara {
|
|
|
|
|
|
} // namespace Detail
|
|
|
|
|
|
- struct Parser {
|
|
|
- Parser() : separators( " \t=:" ) {}
|
|
|
+ inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
|
|
|
+ std::vector<std::string> args( static_cast<std::size_t>( argc ) );
|
|
|
+ for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
|
|
|
+ args[i] = argv[i];
|
|
|
+
|
|
|
+ return args;
|
|
|
+ }
|
|
|
+
|
|
|
+ class Parser {
|
|
|
+ enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
|
|
|
+ Mode mode;
|
|
|
+ std::size_t from;
|
|
|
+ bool inQuotes;
|
|
|
+ public:
|
|
|
|
|
|
struct Token {
|
|
|
enum Type { Positional, ShortOpt, LongOpt };
|
|
@@ -3534,38 +4138,75 @@ namespace Clara {
|
|
|
std::string data;
|
|
|
};
|
|
|
|
|
|
- void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
|
|
|
+ Parser() : mode( None ), from( 0 ), inQuotes( false ){}
|
|
|
+
|
|
|
+ void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
|
|
|
const std::string doubleDash = "--";
|
|
|
- for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
|
|
|
- parseIntoTokens( argv[i] , tokens);
|
|
|
- }
|
|
|
- void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
|
|
|
- while( !arg.empty() ) {
|
|
|
- Parser::Token token( Parser::Token::Positional, arg );
|
|
|
- arg = "";
|
|
|
- if( token.data[0] == '-' ) {
|
|
|
- if( token.data.size() > 1 && token.data[1] == '-' ) {
|
|
|
- token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
|
|
|
- }
|
|
|
- else {
|
|
|
- token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
|
|
|
- if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
|
|
|
- arg = "-" + token.data.substr( 1 );
|
|
|
- token.data = token.data.substr( 0, 1 );
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if( token.type != Parser::Token::Positional ) {
|
|
|
- std::size_t pos = token.data.find_first_of( separators );
|
|
|
- if( pos != std::string::npos ) {
|
|
|
- arg = token.data.substr( pos+1 );
|
|
|
- token.data = token.data.substr( 0, pos );
|
|
|
- }
|
|
|
- }
|
|
|
- tokens.push_back( token );
|
|
|
+ for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
|
|
|
+ parseIntoTokens( args[i], tokens);
|
|
|
+ }
|
|
|
+
|
|
|
+ void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
|
|
|
+ for( std::size_t i = 0; i <= arg.size(); ++i ) {
|
|
|
+ char c = arg[i];
|
|
|
+ if( c == '"' )
|
|
|
+ inQuotes = !inQuotes;
|
|
|
+ mode = handleMode( i, c, arg, tokens );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
|
|
+ switch( mode ) {
|
|
|
+ case None: return handleNone( i, c );
|
|
|
+ case MaybeShortOpt: return handleMaybeShortOpt( i, c );
|
|
|
+ case ShortOpt:
|
|
|
+ case LongOpt:
|
|
|
+ case SlashOpt: return handleOpt( i, c, arg, tokens );
|
|
|
+ case Positional: return handlePositional( i, c, arg, tokens );
|
|
|
+ default: throw std::logic_error( "Unknown mode" );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Mode handleNone( std::size_t i, char c ) {
|
|
|
+ if( inQuotes ) {
|
|
|
+ from = i;
|
|
|
+ return Positional;
|
|
|
}
|
|
|
+ switch( c ) {
|
|
|
+ case '-': return MaybeShortOpt;
|
|
|
+#ifdef CLARA_PLATFORM_WINDOWS
|
|
|
+ case '/': from = i+1; return SlashOpt;
|
|
|
+#endif
|
|
|
+ default: from = i; return Positional;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Mode handleMaybeShortOpt( std::size_t i, char c ) {
|
|
|
+ switch( c ) {
|
|
|
+ case '-': from = i+1; return LongOpt;
|
|
|
+ default: from = i; return ShortOpt;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
|
|
+ if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
|
|
|
+ return mode;
|
|
|
+
|
|
|
+ std::string optName = arg.substr( from, i-from );
|
|
|
+ if( mode == ShortOpt )
|
|
|
+ for( std::size_t j = 0; j < optName.size(); ++j )
|
|
|
+ tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
|
|
|
+ else if( mode == SlashOpt && optName.size() == 1 )
|
|
|
+ tokens.push_back( Token( Token::ShortOpt, optName ) );
|
|
|
+ else
|
|
|
+ tokens.push_back( Token( Token::LongOpt, optName ) );
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+ Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
|
|
+ if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
|
|
|
+ return mode;
|
|
|
+
|
|
|
+ std::string data = arg.substr( from, i-from );
|
|
|
+ tokens.push_back( Token( Token::Positional, data ) );
|
|
|
+ return None;
|
|
|
}
|
|
|
- std::string separators;
|
|
|
};
|
|
|
|
|
|
template<typename ConfigT>
|
|
@@ -3644,12 +4285,7 @@ namespace Clara {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // NOTE: std::auto_ptr is deprecated in c++11/c++0x
|
|
|
-#if defined(__cplusplus) && __cplusplus > 199711L
|
|
|
- typedef std::unique_ptr<Arg> ArgAutoPtr;
|
|
|
-#else
|
|
|
- typedef std::auto_ptr<Arg> ArgAutoPtr;
|
|
|
-#endif
|
|
|
+ typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr;
|
|
|
|
|
|
friend void addOptName( Arg& arg, std::string const& optName )
|
|
|
{
|
|
@@ -3760,7 +4396,7 @@ namespace Clara {
|
|
|
m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
|
|
|
{
|
|
|
if( other.m_floatingArg.get() )
|
|
|
- m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) );
|
|
|
+ m_floatingArg.reset( new Arg( *other.m_floatingArg ) );
|
|
|
}
|
|
|
|
|
|
CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
|
|
@@ -3788,7 +4424,7 @@ namespace Clara {
|
|
|
ArgBuilder operator[]( UnpositionalTag ) {
|
|
|
if( m_floatingArg.get() )
|
|
|
throw std::logic_error( "Only one unpositional argument can be added" );
|
|
|
- m_floatingArg = ArgAutoPtr( new Arg() );
|
|
|
+ m_floatingArg.reset( new Arg() );
|
|
|
ArgBuilder builder( m_floatingArg.get() );
|
|
|
return builder;
|
|
|
}
|
|
@@ -3873,21 +4509,21 @@ namespace Clara {
|
|
|
return oss.str();
|
|
|
}
|
|
|
|
|
|
- ConfigT parse( int argc, char const * const * argv ) const {
|
|
|
+ ConfigT parse( std::vector<std::string> const& args ) const {
|
|
|
ConfigT config;
|
|
|
- parseInto( argc, argv, config );
|
|
|
+ parseInto( args, config );
|
|
|
return config;
|
|
|
}
|
|
|
|
|
|
- std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
|
|
|
- std::string processName = argv[0];
|
|
|
+ std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
|
|
|
+ std::string processName = args[0];
|
|
|
std::size_t lastSlash = processName.find_last_of( "/\\" );
|
|
|
if( lastSlash != std::string::npos )
|
|
|
processName = processName.substr( lastSlash+1 );
|
|
|
m_boundProcessName.set( config, processName );
|
|
|
std::vector<Parser::Token> tokens;
|
|
|
Parser parser;
|
|
|
- parser.parseIntoTokens( argc, argv, tokens );
|
|
|
+ parser.parseIntoTokens( args, tokens );
|
|
|
return populate( tokens, config );
|
|
|
}
|
|
|
|
|
@@ -3918,7 +4554,7 @@ namespace Clara {
|
|
|
arg.boundField.set( config, tokens[++i].data );
|
|
|
}
|
|
|
else {
|
|
|
- arg.boundField.setFlag( config );
|
|
|
+ arg.boundField.set( config, "true" );
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -3930,7 +4566,7 @@ namespace Clara {
|
|
|
if( it == itEnd ) {
|
|
|
if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
|
|
|
unusedTokens.push_back( token );
|
|
|
- else if( m_throwOnUnrecognisedTokens )
|
|
|
+ else if( errors.empty() && m_throwOnUnrecognisedTokens )
|
|
|
errors.push_back( "unrecognised option: " + token.data );
|
|
|
}
|
|
|
}
|
|
@@ -4022,13 +4658,35 @@ namespace Catch {
|
|
|
config.abortAfter = x;
|
|
|
}
|
|
|
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
|
|
|
+ inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
|
|
|
|
|
|
inline void addWarning( ConfigData& config, std::string const& _warning ) {
|
|
|
if( _warning == "NoAssertions" )
|
|
|
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
|
|
|
else
|
|
|
throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
|
|
|
-
|
|
|
+ }
|
|
|
+ inline void setOrder( ConfigData& config, std::string const& order ) {
|
|
|
+ if( startsWith( "declared", order ) )
|
|
|
+ config.runOrder = RunTests::InDeclarationOrder;
|
|
|
+ else if( startsWith( "lexical", order ) )
|
|
|
+ config.runOrder = RunTests::InLexicographicalOrder;
|
|
|
+ else if( startsWith( "random", order ) )
|
|
|
+ config.runOrder = RunTests::InRandomOrder;
|
|
|
+ else
|
|
|
+ throw std::runtime_error( "Unrecognised ordering: '" + order + "'" );
|
|
|
+ }
|
|
|
+ inline void setRngSeed( ConfigData& config, std::string const& seed ) {
|
|
|
+ if( seed == "time" ) {
|
|
|
+ config.rngSeed = static_cast<unsigned int>( std::time(0) );
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ std::stringstream ss;
|
|
|
+ ss << seed;
|
|
|
+ ss >> config.rngSeed;
|
|
|
+ if( ss.fail() )
|
|
|
+ throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" );
|
|
|
+ }
|
|
|
}
|
|
|
inline void setVerbosity( ConfigData& config, int level ) {
|
|
|
// !TBD: accept strings?
|
|
@@ -4039,6 +4697,21 @@ namespace Catch {
|
|
|
? ShowDurations::Always
|
|
|
: ShowDurations::Never;
|
|
|
}
|
|
|
+ inline void setUseColour( ConfigData& config, std::string const& value ) {
|
|
|
+ std::string mode = toLower( value );
|
|
|
+
|
|
|
+ if( mode == "yes" )
|
|
|
+ config.useColour = UseColour::Yes;
|
|
|
+ else if( mode == "no" )
|
|
|
+ config.useColour = UseColour::No;
|
|
|
+ else if( mode == "auto" )
|
|
|
+ config.useColour = UseColour::Auto;
|
|
|
+ else
|
|
|
+ throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
|
|
|
+ }
|
|
|
+ inline void forceColour( ConfigData& config ) {
|
|
|
+ config.useColour = UseColour::Yes;
|
|
|
+ }
|
|
|
inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
|
|
|
std::ifstream f( _filename.c_str() );
|
|
|
if( !f.is_open() )
|
|
@@ -4047,8 +4720,11 @@ namespace Catch {
|
|
|
std::string line;
|
|
|
while( std::getline( f, line ) ) {
|
|
|
line = trim(line);
|
|
|
- if( !line.empty() && !startsWith( line, "#" ) )
|
|
|
- addTestOrTags( config, "\"" + line + "\"," );
|
|
|
+ if( !line.empty() && !startsWith( line, "#" ) ) {
|
|
|
+ if( !startsWith( line, "\"" ) )
|
|
|
+ line = "\"" + line + "\"";
|
|
|
+ addTestOrTags( config, line + "," );
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -4094,7 +4770,7 @@ namespace Catch {
|
|
|
cli["-r"]["--reporter"]
|
|
|
// .placeholder( "name[:filename]" )
|
|
|
.describe( "reporter to use (defaults to console)" )
|
|
|
- .bind( &ConfigData::reporterName, "name" );
|
|
|
+ .bind( &addReporterName, "name" );
|
|
|
|
|
|
cli["-n"]["--name"]
|
|
|
.describe( "suite name" )
|
|
@@ -4125,12 +4801,16 @@ namespace Catch {
|
|
|
|
|
|
cli["-d"]["--durations"]
|
|
|
.describe( "show test durations" )
|
|
|
- .bind( &setShowDurations, "yes/no" );
|
|
|
+ .bind( &setShowDurations, "yes|no" );
|
|
|
|
|
|
cli["-f"]["--input-file"]
|
|
|
.describe( "load test names to run from a file" )
|
|
|
.bind( &loadTestNamesFromFile, "filename" );
|
|
|
|
|
|
+ cli["-#"]["--filenames-as-tags"]
|
|
|
+ .describe( "adds a tag for the filename" )
|
|
|
+ .bind( &ConfigData::filenamesAsTags );
|
|
|
+
|
|
|
// Less common commands which don't have a short form
|
|
|
cli["--list-test-names-only"]
|
|
|
.describe( "list all/matching test cases names only" )
|
|
@@ -4140,6 +4820,22 @@ namespace Catch {
|
|
|
.describe( "list all reporters" )
|
|
|
.bind( &ConfigData::listReporters );
|
|
|
|
|
|
+ cli["--order"]
|
|
|
+ .describe( "test case order (defaults to decl)" )
|
|
|
+ .bind( &setOrder, "decl|lex|rand" );
|
|
|
+
|
|
|
+ cli["--rng-seed"]
|
|
|
+ .describe( "set a specific seed for random numbers" )
|
|
|
+ .bind( &setRngSeed, "'time'|number" );
|
|
|
+
|
|
|
+ cli["--force-colour"]
|
|
|
+ .describe( "force colourised output (deprecated)" )
|
|
|
+ .bind( &forceColour );
|
|
|
+
|
|
|
+ cli["--use-colour"]
|
|
|
+ .describe( "should output be colourised" )
|
|
|
+ .bind( &setUseColour, "yes|no" );
|
|
|
+
|
|
|
return cli;
|
|
|
}
|
|
|
|
|
@@ -4313,10 +5009,6 @@ namespace Catch {
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
- namespace Detail {
|
|
|
- struct IColourImpl;
|
|
|
- }
|
|
|
-
|
|
|
struct Colour {
|
|
|
enum Code {
|
|
|
None = 0,
|
|
@@ -4362,7 +5054,6 @@ namespace Catch {
|
|
|
static void use( Code _colourCode );
|
|
|
|
|
|
private:
|
|
|
- static Detail::IColourImpl* impl();
|
|
|
bool m_moved;
|
|
|
};
|
|
|
|
|
@@ -4381,18 +5072,18 @@ namespace Catch {
|
|
|
namespace Catch
|
|
|
{
|
|
|
struct ReporterConfig {
|
|
|
- explicit ReporterConfig( Ptr<IConfig> const& _fullConfig )
|
|
|
+ explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
|
|
|
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
|
|
|
|
|
|
- ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream )
|
|
|
+ ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
|
|
|
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
|
|
|
|
|
|
std::ostream& stream() const { return *m_stream; }
|
|
|
- Ptr<IConfig> fullConfig() const { return m_fullConfig; }
|
|
|
+ Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
|
|
|
|
|
|
private:
|
|
|
std::ostream* m_stream;
|
|
|
- Ptr<IConfig> m_fullConfig;
|
|
|
+ Ptr<IConfig const> m_fullConfig;
|
|
|
};
|
|
|
|
|
|
struct ReporterPreferences {
|
|
@@ -4456,7 +5147,7 @@ namespace Catch
|
|
|
}
|
|
|
virtual ~AssertionStats();
|
|
|
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
AssertionStats( AssertionStats const& ) = default;
|
|
|
AssertionStats( AssertionStats && ) = default;
|
|
|
AssertionStats& operator = ( AssertionStats const& ) = default;
|
|
@@ -4479,7 +5170,7 @@ namespace Catch
|
|
|
missingAssertions( _missingAssertions )
|
|
|
{}
|
|
|
virtual ~SectionStats();
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
SectionStats( SectionStats const& ) = default;
|
|
|
SectionStats( SectionStats && ) = default;
|
|
|
SectionStats& operator = ( SectionStats const& ) = default;
|
|
@@ -4506,7 +5197,7 @@ namespace Catch
|
|
|
{}
|
|
|
virtual ~TestCaseStats();
|
|
|
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
TestCaseStats( TestCaseStats const& ) = default;
|
|
|
TestCaseStats( TestCaseStats && ) = default;
|
|
|
TestCaseStats& operator = ( TestCaseStats const& ) = default;
|
|
@@ -4534,7 +5225,7 @@ namespace Catch
|
|
|
{}
|
|
|
virtual ~TestGroupStats();
|
|
|
|
|
|
-# ifdef CATCH_CPP11_OR_GREATER
|
|
|
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
TestGroupStats( TestGroupStats const& ) = default;
|
|
|
TestGroupStats( TestGroupStats && ) = default;
|
|
|
TestGroupStats& operator = ( TestGroupStats const& ) = default;
|
|
@@ -4556,7 +5247,7 @@ namespace Catch
|
|
|
{}
|
|
|
virtual ~TestRunStats();
|
|
|
|
|
|
-# ifndef CATCH_CPP11_OR_GREATER
|
|
|
+# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
|
TestRunStats( TestRunStats const& _other )
|
|
|
: runInfo( _other.runInfo ),
|
|
|
totals( _other.totals ),
|
|
@@ -4574,6 +5265,8 @@ namespace Catch
|
|
|
bool aborting;
|
|
|
};
|
|
|
|
|
|
+ class MultipleReporters;
|
|
|
+
|
|
|
struct IStreamingReporter : IShared {
|
|
|
virtual ~IStreamingReporter();
|
|
|
|
|
@@ -4592,27 +5285,37 @@ namespace Catch
|
|
|
|
|
|
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
|
|
|
|
|
|
+ // The return value indicates if the messages buffer should be cleared:
|
|
|
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
|
|
|
+
|
|
|
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
|
|
|
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
|
|
|
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
|
|
|
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
|
|
|
+
|
|
|
+ virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
|
|
|
+
|
|
|
+ virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
|
|
|
};
|
|
|
|
|
|
- struct IReporterFactory {
|
|
|
+ struct IReporterFactory : IShared {
|
|
|
virtual ~IReporterFactory();
|
|
|
virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
|
|
|
virtual std::string getDescription() const = 0;
|
|
|
};
|
|
|
|
|
|
struct IReporterRegistry {
|
|
|
- typedef std::map<std::string, IReporterFactory*> FactoryMap;
|
|
|
+ typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
|
|
|
+ typedef std::vector<Ptr<IReporterFactory> > Listeners;
|
|
|
|
|
|
virtual ~IReporterRegistry();
|
|
|
- virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0;
|
|
|
+ virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
|
|
|
virtual FactoryMap const& getFactories() const = 0;
|
|
|
+ virtual Listeners const& getListeners() const = 0;
|
|
|
};
|
|
|
|
|
|
+ Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
#include <limits>
|
|
@@ -4624,9 +5327,9 @@ namespace Catch {
|
|
|
|
|
|
TestSpec testSpec = config.testSpec();
|
|
|
if( config.testSpec().hasFilters() )
|
|
|
- std::cout << "Matching test cases:\n";
|
|
|
+ Catch::cout() << "Matching test cases:\n";
|
|
|
else {
|
|
|
- std::cout << "All available test cases:\n";
|
|
|
+ Catch::cout() << "All available test cases:\n";
|
|
|
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
|
|
}
|
|
|
|
|
@@ -4635,8 +5338,7 @@ namespace Catch {
|
|
|
nameAttr.setInitialIndent( 2 ).setIndent( 4 );
|
|
|
tagsAttr.setIndent( 6 );
|
|
|
|
|
|
- std::vector<TestCase> matchedTestCases;
|
|
|
- getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
|
|
|
+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
|
|
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
|
|
|
it != itEnd;
|
|
|
++it ) {
|
|
@@ -4647,15 +5349,15 @@ namespace Catch {
|
|
|
: Colour::None;
|
|
|
Colour colourGuard( colour );
|
|
|
|
|
|
- std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl;
|
|
|
+ Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
|
|
|
if( !testCaseInfo.tags.empty() )
|
|
|
- std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
|
|
|
+ Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
|
|
|
}
|
|
|
|
|
|
if( !config.testSpec().hasFilters() )
|
|
|
- std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
|
|
|
+ Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
|
|
|
else
|
|
|
- std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
|
|
|
+ Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
|
|
|
return matchedTests;
|
|
|
}
|
|
|
|
|
@@ -4664,14 +5366,16 @@ namespace Catch {
|
|
|
if( !config.testSpec().hasFilters() )
|
|
|
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
|
|
std::size_t matchedTests = 0;
|
|
|
- std::vector<TestCase> matchedTestCases;
|
|
|
- getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
|
|
|
+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
|
|
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
|
|
|
it != itEnd;
|
|
|
++it ) {
|
|
|
matchedTests++;
|
|
|
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
|
|
- std::cout << testCaseInfo.name << std::endl;
|
|
|
+ if( startsWith( testCaseInfo.name, "#" ) )
|
|
|
+ Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
|
|
|
+ else
|
|
|
+ Catch::cout() << testCaseInfo.name << std::endl;
|
|
|
}
|
|
|
return matchedTests;
|
|
|
}
|
|
@@ -4697,16 +5401,15 @@ namespace Catch {
|
|
|
inline std::size_t listTags( Config const& config ) {
|
|
|
TestSpec testSpec = config.testSpec();
|
|
|
if( config.testSpec().hasFilters() )
|
|
|
- std::cout << "Tags for matching test cases:\n";
|
|
|
+ Catch::cout() << "Tags for matching test cases:\n";
|
|
|
else {
|
|
|
- std::cout << "All available tags:\n";
|
|
|
+ Catch::cout() << "All available tags:\n";
|
|
|
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
|
|
}
|
|
|
|
|
|
std::map<std::string, TagInfo> tagCounts;
|
|
|
|
|
|
- std::vector<TestCase> matchedTestCases;
|
|
|
- getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
|
|
|
+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
|
|
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
|
|
|
it != itEnd;
|
|
|
++it ) {
|
|
@@ -4733,14 +5436,14 @@ namespace Catch {
|
|
|
.setInitialIndent( 0 )
|
|
|
.setIndent( oss.str().size() )
|
|
|
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
|
|
|
- std::cout << oss.str() << wrapper << "\n";
|
|
|
+ Catch::cout() << oss.str() << wrapper << "\n";
|
|
|
}
|
|
|
- std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
|
|
|
+ Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
|
|
|
return tagCounts.size();
|
|
|
}
|
|
|
|
|
|
inline std::size_t listReporters( Config const& /*config*/ ) {
|
|
|
- std::cout << "Available reports:\n";
|
|
|
+ Catch::cout() << "Available reporters:\n";
|
|
|
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
|
|
|
IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
|
|
|
std::size_t maxNameLen = 0;
|
|
@@ -4752,13 +5455,13 @@ namespace Catch {
|
|
|
.setInitialIndent( 0 )
|
|
|
.setIndent( 7+maxNameLen )
|
|
|
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
|
|
|
- std::cout << " "
|
|
|
+ Catch::cout() << " "
|
|
|
<< it->first
|
|
|
<< ":"
|
|
|
<< std::string( maxNameLen - it->first.size() + 2, ' ' )
|
|
|
<< wrapper << "\n";
|
|
|
}
|
|
|
- std::cout << std::endl;
|
|
|
+ Catch::cout() << std::endl;
|
|
|
return factories.size();
|
|
|
}
|
|
|
|
|
@@ -4777,7 +5480,7 @@ namespace Catch {
|
|
|
|
|
|
} // end namespace Catch
|
|
|
|
|
|
-// #included from: internal/catch_runner_impl.hpp
|
|
|
+// #included from: internal/catch_run_context.hpp
|
|
|
#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
|
|
|
|
|
|
// #included from: catch_test_case_tracker.hpp
|
|
@@ -4786,135 +5489,392 @@ namespace Catch {
|
|
|
#include <map>
|
|
|
#include <string>
|
|
|
#include <assert.h>
|
|
|
+#include <vector>
|
|
|
|
|
|
namespace Catch {
|
|
|
-namespace SectionTracking {
|
|
|
+namespace TestCaseTracking {
|
|
|
|
|
|
- class TrackedSection {
|
|
|
+ struct ITracker : SharedImpl<> {
|
|
|
+ virtual ~ITracker();
|
|
|
|
|
|
- typedef std::map<std::string, TrackedSection> TrackedSections;
|
|
|
+ // static queries
|
|
|
+ virtual std::string name() const = 0;
|
|
|
+
|
|
|
+ // dynamic queries
|
|
|
+ virtual bool isComplete() const = 0; // Successfully completed or failed
|
|
|
+ virtual bool isSuccessfullyCompleted() const = 0;
|
|
|
+ virtual bool isOpen() const = 0; // Started but not complete
|
|
|
+ virtual bool hasChildren() const = 0;
|
|
|
+
|
|
|
+ virtual ITracker& parent() = 0;
|
|
|
+
|
|
|
+ // actions
|
|
|
+ virtual void close() = 0; // Successfully complete
|
|
|
+ virtual void fail() = 0;
|
|
|
+ virtual void markAsNeedingAnotherRun() = 0;
|
|
|
+
|
|
|
+ virtual void addChild( Ptr<ITracker> const& child ) = 0;
|
|
|
+ virtual ITracker* findChild( std::string const& name ) = 0;
|
|
|
+ virtual void openChild() = 0;
|
|
|
+
|
|
|
+ // Debug/ checking
|
|
|
+ virtual bool isSectionTracker() const = 0;
|
|
|
+ virtual bool isIndexTracker() const = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ class TrackerContext {
|
|
|
|
|
|
- public:
|
|
|
enum RunState {
|
|
|
NotStarted,
|
|
|
Executing,
|
|
|
- ExecutingChildren,
|
|
|
- Completed
|
|
|
+ CompletedCycle
|
|
|
};
|
|
|
|
|
|
- TrackedSection( std::string const& name, TrackedSection* parent )
|
|
|
- : m_name( name ), m_runState( NotStarted ), m_parent( parent )
|
|
|
+ Ptr<ITracker> m_rootTracker;
|
|
|
+ ITracker* m_currentTracker;
|
|
|
+ RunState m_runState;
|
|
|
+
|
|
|
+ public:
|
|
|
+
|
|
|
+ static TrackerContext& instance() {
|
|
|
+ static TrackerContext s_instance;
|
|
|
+ return s_instance;
|
|
|
+ }
|
|
|
+
|
|
|
+ TrackerContext()
|
|
|
+ : m_currentTracker( CATCH_NULL ),
|
|
|
+ m_runState( NotStarted )
|
|
|
{}
|
|
|
|
|
|
- RunState runState() const { return m_runState; }
|
|
|
+ ITracker& startRun();
|
|
|
|
|
|
- TrackedSection* findChild( std::string const& childName ) {
|
|
|
- TrackedSections::iterator it = m_children.find( childName );
|
|
|
- return it != m_children.end()
|
|
|
- ? &it->second
|
|
|
- : NULL;
|
|
|
+ void endRun() {
|
|
|
+ m_rootTracker.reset();
|
|
|
+ m_currentTracker = CATCH_NULL;
|
|
|
+ m_runState = NotStarted;
|
|
|
}
|
|
|
- TrackedSection* acquireChild( std::string const& childName ) {
|
|
|
- if( TrackedSection* child = findChild( childName ) )
|
|
|
- return child;
|
|
|
- m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) );
|
|
|
- return findChild( childName );
|
|
|
+
|
|
|
+ void startCycle() {
|
|
|
+ m_currentTracker = m_rootTracker.get();
|
|
|
+ m_runState = Executing;
|
|
|
}
|
|
|
- void enter() {
|
|
|
- if( m_runState == NotStarted )
|
|
|
- m_runState = Executing;
|
|
|
+ void completeCycle() {
|
|
|
+ m_runState = CompletedCycle;
|
|
|
}
|
|
|
- void leave() {
|
|
|
- for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end();
|
|
|
- it != itEnd;
|
|
|
- ++it )
|
|
|
- if( it->second.runState() != Completed ) {
|
|
|
- m_runState = ExecutingChildren;
|
|
|
- return;
|
|
|
- }
|
|
|
- m_runState = Completed;
|
|
|
+
|
|
|
+ bool completedCycle() const {
|
|
|
+ return m_runState == CompletedCycle;
|
|
|
}
|
|
|
- TrackedSection* getParent() {
|
|
|
- return m_parent;
|
|
|
+ ITracker& currentTracker() {
|
|
|
+ return *m_currentTracker;
|
|
|
}
|
|
|
- bool hasChildren() const {
|
|
|
- return !m_children.empty();
|
|
|
+ void setCurrentTracker( ITracker* tracker ) {
|
|
|
+ m_currentTracker = tracker;
|
|
|
}
|
|
|
-
|
|
|
- private:
|
|
|
- std::string m_name;
|
|
|
- RunState m_runState;
|
|
|
- TrackedSections m_children;
|
|
|
- TrackedSection* m_parent;
|
|
|
-
|
|
|
};
|
|
|
|
|
|
- class TestCaseTracker {
|
|
|
+ class TrackerBase : public ITracker {
|
|
|
+ protected:
|
|
|
+ enum CycleState {
|
|
|
+ NotStarted,
|
|
|
+ Executing,
|
|
|
+ ExecutingChildren,
|
|
|
+ NeedsAnotherRun,
|
|
|
+ CompletedSuccessfully,
|
|
|
+ Failed
|
|
|
+ };
|
|
|
+ class TrackerHasName {
|
|
|
+ std::string m_name;
|
|
|
+ public:
|
|
|
+ TrackerHasName( std::string const& name ) : m_name( name ) {}
|
|
|
+ bool operator ()( Ptr<ITracker> const& tracker ) {
|
|
|
+ return tracker->name() == m_name;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ typedef std::vector<Ptr<ITracker> > Children;
|
|
|
+ std::string m_name;
|
|
|
+ TrackerContext& m_ctx;
|
|
|
+ ITracker* m_parent;
|
|
|
+ Children m_children;
|
|
|
+ CycleState m_runState;
|
|
|
public:
|
|
|
- TestCaseTracker( std::string const& testCaseName )
|
|
|
- : m_testCase( testCaseName, NULL ),
|
|
|
- m_currentSection( &m_testCase ),
|
|
|
- m_completedASectionThisRun( false )
|
|
|
+ TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent )
|
|
|
+ : m_name( name ),
|
|
|
+ m_ctx( ctx ),
|
|
|
+ m_parent( parent ),
|
|
|
+ m_runState( NotStarted )
|
|
|
{}
|
|
|
+ virtual ~TrackerBase();
|
|
|
|
|
|
- bool enterSection( std::string const& name ) {
|
|
|
- TrackedSection* child = m_currentSection->acquireChild( name );
|
|
|
- if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed )
|
|
|
- return false;
|
|
|
+ virtual std::string name() const CATCH_OVERRIDE {
|
|
|
+ return m_name;
|
|
|
+ }
|
|
|
+ virtual bool isComplete() const CATCH_OVERRIDE {
|
|
|
+ return m_runState == CompletedSuccessfully || m_runState == Failed;
|
|
|
+ }
|
|
|
+ virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE {
|
|
|
+ return m_runState == CompletedSuccessfully;
|
|
|
+ }
|
|
|
+ virtual bool isOpen() const CATCH_OVERRIDE {
|
|
|
+ return m_runState != NotStarted && !isComplete();
|
|
|
+ }
|
|
|
+ virtual bool hasChildren() const CATCH_OVERRIDE {
|
|
|
+ return !m_children.empty();
|
|
|
+ }
|
|
|
|
|
|
- m_currentSection = child;
|
|
|
- m_currentSection->enter();
|
|
|
- return true;
|
|
|
+ virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
|
|
|
+ m_children.push_back( child );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE {
|
|
|
+ Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) );
|
|
|
+ return( it != m_children.end() )
|
|
|
+ ? it->get()
|
|
|
+ : CATCH_NULL;
|
|
|
}
|
|
|
- void leaveSection() {
|
|
|
- m_currentSection->leave();
|
|
|
- m_currentSection = m_currentSection->getParent();
|
|
|
- assert( m_currentSection != NULL );
|
|
|
- m_completedASectionThisRun = true;
|
|
|
+ virtual ITracker& parent() CATCH_OVERRIDE {
|
|
|
+ assert( m_parent ); // Should always be non-null except for root
|
|
|
+ return *m_parent;
|
|
|
}
|
|
|
|
|
|
- bool currentSectionHasChildren() const {
|
|
|
- return m_currentSection->hasChildren();
|
|
|
+ virtual void openChild() CATCH_OVERRIDE {
|
|
|
+ if( m_runState != ExecutingChildren ) {
|
|
|
+ m_runState = ExecutingChildren;
|
|
|
+ if( m_parent )
|
|
|
+ m_parent->openChild();
|
|
|
+ }
|
|
|
}
|
|
|
- bool isCompleted() const {
|
|
|
- return m_testCase.runState() == TrackedSection::Completed;
|
|
|
+
|
|
|
+ virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
|
|
|
+ virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
|
|
|
+
|
|
|
+ void open() {
|
|
|
+ m_runState = Executing;
|
|
|
+ moveToThis();
|
|
|
+ if( m_parent )
|
|
|
+ m_parent->openChild();
|
|
|
}
|
|
|
|
|
|
- class Guard {
|
|
|
- public:
|
|
|
- Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) {
|
|
|
- m_tracker.enterTestCase();
|
|
|
+ virtual void close() CATCH_OVERRIDE {
|
|
|
+
|
|
|
+ // Close any still open children (e.g. generators)
|
|
|
+ while( &m_ctx.currentTracker() != this )
|
|
|
+ m_ctx.currentTracker().close();
|
|
|
+
|
|
|
+ switch( m_runState ) {
|
|
|
+ case NotStarted:
|
|
|
+ case CompletedSuccessfully:
|
|
|
+ case Failed:
|
|
|
+ throw std::logic_error( "Illogical state" );
|
|
|
+
|
|
|
+ case NeedsAnotherRun:
|
|
|
+ break;;
|
|
|
+
|
|
|
+ case Executing:
|
|
|
+ m_runState = CompletedSuccessfully;
|
|
|
+ break;
|
|
|
+ case ExecutingChildren:
|
|
|
+ if( m_children.empty() || m_children.back()->isComplete() )
|
|
|
+ m_runState = CompletedSuccessfully;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ throw std::logic_error( "Unexpected state" );
|
|
|
+ }
|
|
|
+ moveToParent();
|
|
|
+ m_ctx.completeCycle();
|
|
|
+ }
|
|
|
+ virtual void fail() CATCH_OVERRIDE {
|
|
|
+ m_runState = Failed;
|
|
|
+ if( m_parent )
|
|
|
+ m_parent->markAsNeedingAnotherRun();
|
|
|
+ moveToParent();
|
|
|
+ m_ctx.completeCycle();
|
|
|
+ }
|
|
|
+ virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE {
|
|
|
+ m_runState = NeedsAnotherRun;
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ void moveToParent() {
|
|
|
+ assert( m_parent );
|
|
|
+ m_ctx.setCurrentTracker( m_parent );
|
|
|
+ }
|
|
|
+ void moveToThis() {
|
|
|
+ m_ctx.setCurrentTracker( this );
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ class SectionTracker : public TrackerBase {
|
|
|
+ public:
|
|
|
+ SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent )
|
|
|
+ : TrackerBase( name, ctx, parent )
|
|
|
+ {}
|
|
|
+ virtual ~SectionTracker();
|
|
|
+
|
|
|
+ virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
|
|
|
+
|
|
|
+ static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
|
|
|
+ SectionTracker* section = CATCH_NULL;
|
|
|
+
|
|
|
+ ITracker& currentTracker = ctx.currentTracker();
|
|
|
+ if( ITracker* childTracker = currentTracker.findChild( name ) ) {
|
|
|
+ assert( childTracker );
|
|
|
+ assert( childTracker->isSectionTracker() );
|
|
|
+ section = static_cast<SectionTracker*>( childTracker );
|
|
|
}
|
|
|
- ~Guard() {
|
|
|
- m_tracker.leaveTestCase();
|
|
|
+ else {
|
|
|
+ section = new SectionTracker( name, ctx, ¤tTracker );
|
|
|
+ currentTracker.addChild( section );
|
|
|
}
|
|
|
- private:
|
|
|
- Guard( Guard const& );
|
|
|
- void operator = ( Guard const& );
|
|
|
- TestCaseTracker& m_tracker;
|
|
|
- };
|
|
|
+ if( !ctx.completedCycle() && !section->isComplete() ) {
|
|
|
|
|
|
- private:
|
|
|
- void enterTestCase() {
|
|
|
- m_currentSection = &m_testCase;
|
|
|
- m_completedASectionThisRun = false;
|
|
|
- m_testCase.enter();
|
|
|
+ section->open();
|
|
|
+ }
|
|
|
+ return *section;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ class IndexTracker : public TrackerBase {
|
|
|
+ int m_size;
|
|
|
+ int m_index;
|
|
|
+ public:
|
|
|
+ IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size )
|
|
|
+ : TrackerBase( name, ctx, parent ),
|
|
|
+ m_size( size ),
|
|
|
+ m_index( -1 )
|
|
|
+ {}
|
|
|
+ virtual ~IndexTracker();
|
|
|
+
|
|
|
+ virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
|
|
|
+
|
|
|
+ static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
|
|
|
+ IndexTracker* tracker = CATCH_NULL;
|
|
|
+
|
|
|
+ ITracker& currentTracker = ctx.currentTracker();
|
|
|
+ if( ITracker* childTracker = currentTracker.findChild( name ) ) {
|
|
|
+ assert( childTracker );
|
|
|
+ assert( childTracker->isIndexTracker() );
|
|
|
+ tracker = static_cast<IndexTracker*>( childTracker );
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ tracker = new IndexTracker( name, ctx, ¤tTracker, size );
|
|
|
+ currentTracker.addChild( tracker );
|
|
|
+ }
|
|
|
+
|
|
|
+ if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
|
|
+ if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
|
|
|
+ tracker->moveNext();
|
|
|
+ tracker->open();
|
|
|
+ }
|
|
|
+
|
|
|
+ return *tracker;
|
|
|
}
|
|
|
- void leaveTestCase() {
|
|
|
- m_testCase.leave();
|
|
|
+
|
|
|
+ int index() const { return m_index; }
|
|
|
+
|
|
|
+ void moveNext() {
|
|
|
+ m_index++;
|
|
|
+ m_children.clear();
|
|
|
}
|
|
|
|
|
|
- TrackedSection m_testCase;
|
|
|
- TrackedSection* m_currentSection;
|
|
|
- bool m_completedASectionThisRun;
|
|
|
+ virtual void close() CATCH_OVERRIDE {
|
|
|
+ TrackerBase::close();
|
|
|
+ if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
|
|
|
+ m_runState = Executing;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
-} // namespace SectionTracking
|
|
|
+ inline ITracker& TrackerContext::startRun() {
|
|
|
+ m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL );
|
|
|
+ m_currentTracker = CATCH_NULL;
|
|
|
+ m_runState = Executing;
|
|
|
+ return *m_rootTracker;
|
|
|
+ }
|
|
|
+
|
|
|
+} // namespace TestCaseTracking
|
|
|
+
|
|
|
+using TestCaseTracking::ITracker;
|
|
|
+using TestCaseTracking::TrackerContext;
|
|
|
+using TestCaseTracking::SectionTracker;
|
|
|
+using TestCaseTracking::IndexTracker;
|
|
|
+
|
|
|
+} // namespace Catch
|
|
|
+
|
|
|
+// #included from: catch_fatal_condition.hpp
|
|
|
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
|
|
+
|
|
|
+namespace Catch {
|
|
|
+
|
|
|
+ // Report the error condition then exit the process
|
|
|
+ inline void fatal( std::string const& message, int exitCode ) {
|
|
|
+ IContext& context = Catch::getCurrentContext();
|
|
|
+ IResultCapture* resultCapture = context.getResultCapture();
|
|
|
+ resultCapture->handleFatalErrorCondition( message );
|
|
|
+
|
|
|
+ if( Catch::alwaysTrue() ) // avoids "no return" warnings
|
|
|
+ exit( exitCode );
|
|
|
+ }
|
|
|
+
|
|
|
+} // namespace Catch
|
|
|
+
|
|
|
+#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
|
|
+
|
|
|
+namespace Catch {
|
|
|
+
|
|
|
+ struct FatalConditionHandler {
|
|
|
+ void reset() {}
|
|
|
+ };
|
|
|
+
|
|
|
+} // namespace Catch
|
|
|
+
|
|
|
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
|
|
+
|
|
|
+#include <signal.h>
|
|
|
|
|
|
-using SectionTracking::TestCaseTracker;
|
|
|
+namespace Catch {
|
|
|
+
|
|
|
+ struct SignalDefs { int id; const char* name; };
|
|
|
+ extern SignalDefs signalDefs[];
|
|
|
+ SignalDefs signalDefs[] = {
|
|
|
+ { SIGINT, "SIGINT - Terminal interrupt signal" },
|
|
|
+ { SIGILL, "SIGILL - Illegal instruction signal" },
|
|
|
+ { SIGFPE, "SIGFPE - Floating point error signal" },
|
|
|
+ { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
|
|
|
+ { SIGTERM, "SIGTERM - Termination request signal" },
|
|
|
+ { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct FatalConditionHandler {
|
|
|
+
|
|
|
+ static void handleSignal( int sig ) {
|
|
|
+ for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
|
|
|
+ if( sig == signalDefs[i].id )
|
|
|
+ fatal( signalDefs[i].name, -sig );
|
|
|
+ fatal( "<unknown signal>", -sig );
|
|
|
+ }
|
|
|
+
|
|
|
+ FatalConditionHandler() : m_isSet( true ) {
|
|
|
+ for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
|
|
|
+ signal( signalDefs[i].id, handleSignal );
|
|
|
+ }
|
|
|
+ ~FatalConditionHandler() {
|
|
|
+ reset();
|
|
|
+ }
|
|
|
+ void reset() {
|
|
|
+ if( m_isSet ) {
|
|
|
+ for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
|
|
|
+ signal( signalDefs[i].id, SIG_DFL );
|
|
|
+ m_isSet = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bool m_isSet;
|
|
|
+ };
|
|
|
|
|
|
} // namespace Catch
|
|
|
|
|
|
+#endif // not Windows
|
|
|
+
|
|
|
#include <set>
|
|
|
#include <string>
|
|
|
|
|
@@ -4952,15 +5912,12 @@ namespace Catch {
|
|
|
|
|
|
public:
|
|
|
|
|
|
- explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter )
|
|
|
- : m_runInfo( config->name() ),
|
|
|
+ explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter )
|
|
|
+ : m_runInfo( _config->name() ),
|
|
|
m_context( getCurrentMutableContext() ),
|
|
|
- m_activeTestCase( NULL ),
|
|
|
- m_config( config ),
|
|
|
- m_reporter( reporter ),
|
|
|
- m_prevRunner( m_context.getRunner() ),
|
|
|
- m_prevResultCapture( m_context.getResultCapture() ),
|
|
|
- m_prevConfig( m_context.getConfig() )
|
|
|
+ m_activeTestCase( CATCH_NULL ),
|
|
|
+ m_config( _config ),
|
|
|
+ m_reporter( reporter )
|
|
|
{
|
|
|
m_context.setRunner( this );
|
|
|
m_context.setConfig( m_config );
|
|
@@ -4970,10 +5927,6 @@ namespace Catch {
|
|
|
|
|
|
virtual ~RunContext() {
|
|
|
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
|
|
|
- m_context.setRunner( m_prevRunner );
|
|
|
- m_context.setConfig( NULL );
|
|
|
- m_context.setResultCapture( m_prevResultCapture );
|
|
|
- m_context.setConfig( m_prevConfig );
|
|
|
}
|
|
|
|
|
|
void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
|
|
@@ -4994,17 +5947,25 @@ namespace Catch {
|
|
|
m_reporter->testCaseStarting( testInfo );
|
|
|
|
|
|
m_activeTestCase = &testCase;
|
|
|
- m_testCaseTracker = TestCaseTracker( testInfo.name );
|
|
|
|
|
|
do {
|
|
|
+ m_trackerContext.startRun();
|
|
|
do {
|
|
|
+ m_trackerContext.startCycle();
|
|
|
+ m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name );
|
|
|
runCurrentTest( redirectedCout, redirectedCerr );
|
|
|
}
|
|
|
- while( !m_testCaseTracker->isCompleted() && !aborting() );
|
|
|
+ while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
|
|
|
}
|
|
|
+ // !TBD: deprecated - this will be replaced by indexed trackers
|
|
|
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
|
|
|
|
|
|
Totals deltaTotals = m_totals.delta( prevTotals );
|
|
|
+ if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
|
|
|
+ deltaTotals.assertions.failed++;
|
|
|
+ deltaTotals.testCases.passed--;
|
|
|
+ deltaTotals.testCases.failed++;
|
|
|
+ }
|
|
|
m_totals.testCases += deltaTotals.testCases;
|
|
|
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
|
|
deltaTotals,
|
|
@@ -5012,8 +5973,8 @@ namespace Catch {
|
|
|
redirectedCerr,
|
|
|
aborting() ) );
|
|
|
|
|
|
- m_activeTestCase = NULL;
|
|
|
- m_testCaseTracker.reset();
|
|
|
+ m_activeTestCase = CATCH_NULL;
|
|
|
+ m_testCaseTracker = CATCH_NULL;
|
|
|
|
|
|
return deltaTotals;
|
|
|
}
|
|
@@ -5048,8 +6009,10 @@ namespace Catch {
|
|
|
std::ostringstream oss;
|
|
|
oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
|
|
|
|
|
|
- if( !m_testCaseTracker->enterSection( oss.str() ) )
|
|
|
+ ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() );
|
|
|
+ if( !sectionTracker.isOpen() )
|
|
|
return false;
|
|
|
+ m_activeSections.push_back( §ionTracker );
|
|
|
|
|
|
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
|
|
|
|
|
@@ -5060,30 +6023,40 @@ namespace Catch {
|
|
|
return true;
|
|
|
}
|
|
|
bool testForMissingAssertions( Counts& assertions ) {
|
|
|
- if( assertions.total() != 0 ||
|
|
|
- !m_config->warnAboutMissingAssertions() ||
|
|
|
- m_testCaseTracker->currentSectionHasChildren() )
|
|
|
+ if( assertions.total() != 0 )
|
|
|
+ return false;
|
|
|
+ if( !m_config->warnAboutMissingAssertions() )
|
|
|
+ return false;
|
|
|
+ if( m_trackerContext.currentTracker().hasChildren() )
|
|
|
return false;
|
|
|
m_totals.assertions.failed++;
|
|
|
assertions.failed++;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
|
|
|
- if( std::uncaught_exception() ) {
|
|
|
- m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- Counts assertions = m_totals.assertions - prevAssertions;
|
|
|
+ virtual void sectionEnded( SectionEndInfo const& endInfo ) {
|
|
|
+ Counts assertions = m_totals.assertions - endInfo.prevAssertions;
|
|
|
bool missingAssertions = testForMissingAssertions( assertions );
|
|
|
|
|
|
- m_testCaseTracker->leaveSection();
|
|
|
+ if( !m_activeSections.empty() ) {
|
|
|
+ m_activeSections.back()->close();
|
|
|
+ m_activeSections.pop_back();
|
|
|
+ }
|
|
|
|
|
|
- m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
|
|
|
+ m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
|
|
|
m_messages.clear();
|
|
|
}
|
|
|
|
|
|
+ virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
|
|
|
+ if( m_unfinishedSections.empty() )
|
|
|
+ m_activeSections.back()->fail();
|
|
|
+ else
|
|
|
+ m_activeSections.back()->close();
|
|
|
+ m_activeSections.pop_back();
|
|
|
+
|
|
|
+ m_unfinishedSections.push_back( endInfo );
|
|
|
+ }
|
|
|
+
|
|
|
virtual void pushScopedMessage( MessageInfo const& message ) {
|
|
|
m_messages.push_back( message );
|
|
|
}
|
|
@@ -5102,6 +6075,37 @@ namespace Catch {
|
|
|
return &m_lastResult;
|
|
|
}
|
|
|
|
|
|
+ virtual void handleFatalErrorCondition( std::string const& message ) {
|
|
|
+ ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
|
|
|
+ resultBuilder.setResultType( ResultWas::FatalErrorCondition );
|
|
|
+ resultBuilder << message;
|
|
|
+ resultBuilder.captureExpression();
|
|
|
+
|
|
|
+ handleUnfinishedSections();
|
|
|
+
|
|
|
+ // Recreate section for test case (as we will lose the one that was in scope)
|
|
|
+ TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
|
|
+ SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
|
|
|
+
|
|
|
+ Counts assertions;
|
|
|
+ assertions.failed = 1;
|
|
|
+ SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
|
|
|
+ m_reporter->sectionEnded( testCaseSectionStats );
|
|
|
+
|
|
|
+ TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
|
|
|
+
|
|
|
+ Totals deltaTotals;
|
|
|
+ deltaTotals.testCases.failed = 1;
|
|
|
+ m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
|
|
+ deltaTotals,
|
|
|
+ "",
|
|
|
+ "",
|
|
|
+ false ) );
|
|
|
+ m_totals.testCases.failed++;
|
|
|
+ testGroupEnded( "", m_totals, 1, 1 );
|
|
|
+ m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
|
|
|
+ }
|
|
|
+
|
|
|
public:
|
|
|
// !TBD We need to do this another way!
|
|
|
bool aborting() const {
|
|
@@ -5118,17 +6122,18 @@ namespace Catch {
|
|
|
double duration = 0;
|
|
|
try {
|
|
|
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
|
|
|
- TestCaseTracker::Guard guard( *m_testCaseTracker );
|
|
|
+
|
|
|
+ seedRng( *m_config );
|
|
|
|
|
|
Timer timer;
|
|
|
timer.start();
|
|
|
if( m_reporter->getPreferences().shouldRedirectStdOut ) {
|
|
|
- StreamRedirect coutRedir( std::cout, redirectedCout );
|
|
|
- StreamRedirect cerrRedir( std::cerr, redirectedCerr );
|
|
|
- m_activeTestCase->invoke();
|
|
|
+ StreamRedirect coutRedir( Catch::cout(), redirectedCout );
|
|
|
+ StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
|
|
|
+ invokeActiveTestCase();
|
|
|
}
|
|
|
else {
|
|
|
- m_activeTestCase->invoke();
|
|
|
+ invokeActiveTestCase();
|
|
|
}
|
|
|
duration = timer.getElapsedSeconds();
|
|
|
}
|
|
@@ -5136,20 +6141,10 @@ namespace Catch {
|
|
|
// This just means the test was aborted due to failure
|
|
|
}
|
|
|
catch(...) {
|
|
|
- ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(),
|
|
|
- m_lastAssertionInfo.lineInfo,
|
|
|
- m_lastAssertionInfo.capturedExpression.c_str(),
|
|
|
- m_lastAssertionInfo.resultDisposition );
|
|
|
- exResult.useActiveException();
|
|
|
+ makeUnexpectedResultBuilder().useActiveException();
|
|
|
}
|
|
|
- // If sections ended prematurely due to an exception we stored their
|
|
|
- // infos here so we can tear them down outside the unwind process.
|
|
|
- for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
|
|
|
- itEnd = m_unfinishedSections.rend();
|
|
|
- it != itEnd;
|
|
|
- ++it )
|
|
|
- sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
|
|
|
- m_unfinishedSections.clear();
|
|
|
+ m_testCaseTracker->close();
|
|
|
+ handleUnfinishedSections();
|
|
|
m_messages.clear();
|
|
|
|
|
|
Counts assertions = m_totals.assertions - prevAssertions;
|
|
@@ -5165,32 +6160,47 @@ namespace Catch {
|
|
|
m_reporter->sectionEnded( testCaseSectionStats );
|
|
|
}
|
|
|
|
|
|
+ void invokeActiveTestCase() {
|
|
|
+ FatalConditionHandler fatalConditionHandler; // Handle signals
|
|
|
+ m_activeTestCase->invoke();
|
|
|
+ fatalConditionHandler.reset();
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
- struct UnfinishedSections {
|
|
|
- UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
|
|
|
- : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
|
|
|
- {}
|
|
|
|
|
|
- SectionInfo info;
|
|
|
- Counts prevAssertions;
|
|
|
- double durationInSeconds;
|
|
|
- };
|
|
|
+ ResultBuilder makeUnexpectedResultBuilder() const {
|
|
|
+ return ResultBuilder( m_lastAssertionInfo.macroName.c_str(),
|
|
|
+ m_lastAssertionInfo.lineInfo,
|
|
|
+ m_lastAssertionInfo.capturedExpression.c_str(),
|
|
|
+ m_lastAssertionInfo.resultDisposition );
|
|
|
+ }
|
|
|
+
|
|
|
+ void handleUnfinishedSections() {
|
|
|
+ // If sections ended prematurely due to an exception we stored their
|
|
|
+ // infos here so we can tear them down outside the unwind process.
|
|
|
+ for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
|
|
|
+ itEnd = m_unfinishedSections.rend();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ sectionEnded( *it );
|
|
|
+ m_unfinishedSections.clear();
|
|
|
+ }
|
|
|
|
|
|
TestRunInfo m_runInfo;
|
|
|
IMutableContext& m_context;
|
|
|
TestCase const* m_activeTestCase;
|
|
|
- Option<TestCaseTracker> m_testCaseTracker;
|
|
|
+ ITracker* m_testCaseTracker;
|
|
|
+ ITracker* m_currentSectionTracker;
|
|
|
AssertionResult m_lastResult;
|
|
|
|
|
|
Ptr<IConfig const> m_config;
|
|
|
Totals m_totals;
|
|
|
Ptr<IStreamingReporter> m_reporter;
|
|
|
std::vector<MessageInfo> m_messages;
|
|
|
- IRunner* m_prevRunner;
|
|
|
- IResultCapture* m_prevResultCapture;
|
|
|
- Ptr<IConfig const> m_prevConfig;
|
|
|
AssertionInfo m_lastAssertionInfo;
|
|
|
- std::vector<UnfinishedSections> m_unfinishedSections;
|
|
|
+ std::vector<SectionEndInfo> m_unfinishedSections;
|
|
|
+ std::vector<ITracker*> m_activeSections;
|
|
|
+ TrackerContext m_trackerContext;
|
|
|
};
|
|
|
|
|
|
IResultCapture& getResultCapture() {
|
|
@@ -5211,18 +6221,19 @@ namespace Catch {
|
|
|
struct Version {
|
|
|
Version( unsigned int _majorVersion,
|
|
|
unsigned int _minorVersion,
|
|
|
- unsigned int _buildNumber,
|
|
|
- char const* const _branchName )
|
|
|
- : majorVersion( _majorVersion ),
|
|
|
- minorVersion( _minorVersion ),
|
|
|
- buildNumber( _buildNumber ),
|
|
|
- branchName( _branchName )
|
|
|
- {}
|
|
|
+ unsigned int _patchNumber,
|
|
|
+ std::string const& _branchName,
|
|
|
+ unsigned int _buildNumber );
|
|
|
|
|
|
unsigned int const majorVersion;
|
|
|
unsigned int const minorVersion;
|
|
|
+ unsigned int const patchNumber;
|
|
|
+
|
|
|
+ // buildNumber is only used if branchName is not null
|
|
|
+ std::string const branchName;
|
|
|
unsigned int const buildNumber;
|
|
|
- char const* const branchName;
|
|
|
+
|
|
|
+ friend std::ostream& operator << ( std::ostream& os, Version const& version );
|
|
|
|
|
|
private:
|
|
|
void operator=( Version const& );
|
|
@@ -5237,83 +6248,89 @@ namespace Catch {
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
- class Runner {
|
|
|
-
|
|
|
- public:
|
|
|
- Runner( Ptr<Config> const& config )
|
|
|
- : m_config( config )
|
|
|
- {
|
|
|
- openStream();
|
|
|
- makeReporter();
|
|
|
+ Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
|
|
|
+ Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() );
|
|
|
+ if( !reporter ) {
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << "No reporter registered with name: '" << reporterName << "'";
|
|
|
+ throw std::domain_error( oss.str() );
|
|
|
}
|
|
|
+ return reporter;
|
|
|
+ }
|
|
|
|
|
|
- Totals runTests() {
|
|
|
+ Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
|
|
|
+ std::vector<std::string> reporters = config->getReporterNames();
|
|
|
+ if( reporters.empty() )
|
|
|
+ reporters.push_back( "console" );
|
|
|
|
|
|
- RunContext context( m_config.get(), m_reporter );
|
|
|
+ Ptr<IStreamingReporter> reporter;
|
|
|
+ for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ reporter = addReporter( reporter, createReporter( *it, config ) );
|
|
|
+ return reporter;
|
|
|
+ }
|
|
|
+ Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
|
|
|
+ IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
|
|
|
+ for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
|
|
|
+ return reporters;
|
|
|
+ }
|
|
|
|
|
|
- Totals totals;
|
|
|
+ Totals runTests( Ptr<Config> const& config ) {
|
|
|
|
|
|
- context.testGroupStarting( "", 1, 1 ); // deprecated?
|
|
|
+ Ptr<IConfig const> iconfig = config.get();
|
|
|
|
|
|
- TestSpec testSpec = m_config->testSpec();
|
|
|
- if( !testSpec.hasFilters() )
|
|
|
- testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
|
|
|
+ Ptr<IStreamingReporter> reporter = makeReporter( config );
|
|
|
+ reporter = addListeners( iconfig, reporter );
|
|
|
|
|
|
- std::vector<TestCase> testCases;
|
|
|
- getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
|
|
|
+ RunContext context( iconfig, reporter );
|
|
|
|
|
|
- int testsRunForGroup = 0;
|
|
|
- for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
|
|
|
- it != itEnd;
|
|
|
- ++it ) {
|
|
|
- testsRunForGroup++;
|
|
|
- if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
|
|
|
+ Totals totals;
|
|
|
|
|
|
- if( context.aborting() )
|
|
|
- break;
|
|
|
+ context.testGroupStarting( config->name(), 1, 1 );
|
|
|
|
|
|
- totals += context.runTest( *it );
|
|
|
- m_testsAlreadyRun.insert( *it );
|
|
|
- }
|
|
|
- }
|
|
|
- context.testGroupEnded( "", totals, 1, 1 );
|
|
|
- return totals;
|
|
|
- }
|
|
|
+ TestSpec testSpec = config->testSpec();
|
|
|
+ if( !testSpec.hasFilters() )
|
|
|
+ testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
|
|
|
|
|
|
- private:
|
|
|
- void openStream() {
|
|
|
- // Open output file, if specified
|
|
|
- if( !m_config->getFilename().empty() ) {
|
|
|
- m_ofs.open( m_config->getFilename().c_str() );
|
|
|
- if( m_ofs.fail() ) {
|
|
|
- std::ostringstream oss;
|
|
|
- oss << "Unable to open file: '" << m_config->getFilename() << "'";
|
|
|
- throw std::domain_error( oss.str() );
|
|
|
- }
|
|
|
- m_config->setStreamBuf( m_ofs.rdbuf() );
|
|
|
- }
|
|
|
+ std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
|
|
|
+ for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it ) {
|
|
|
+ if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
|
|
|
+ totals += context.runTest( *it );
|
|
|
+ else
|
|
|
+ reporter->skipTest( *it );
|
|
|
}
|
|
|
- void makeReporter() {
|
|
|
- std::string reporterName = m_config->getReporterName().empty()
|
|
|
- ? "console"
|
|
|
- : m_config->getReporterName();
|
|
|
|
|
|
- m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
|
|
|
- if( !m_reporter ) {
|
|
|
- std::ostringstream oss;
|
|
|
- oss << "No reporter registered with name: '" << reporterName << "'";
|
|
|
- throw std::domain_error( oss.str() );
|
|
|
- }
|
|
|
- }
|
|
|
+ context.testGroupEnded( iconfig->name(), totals, 1, 1 );
|
|
|
+ return totals;
|
|
|
+ }
|
|
|
|
|
|
- private:
|
|
|
- Ptr<Config> m_config;
|
|
|
- std::ofstream m_ofs;
|
|
|
- Ptr<IStreamingReporter> m_reporter;
|
|
|
- std::set<TestCase> m_testsAlreadyRun;
|
|
|
- };
|
|
|
+ void applyFilenamesAsTags( IConfig const& config ) {
|
|
|
+ std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
|
|
|
+ for(std::size_t i = 0; i < tests.size(); ++i ) {
|
|
|
+ TestCase& test = const_cast<TestCase&>( tests[i] );
|
|
|
+ std::set<std::string> tags = test.tags;
|
|
|
+
|
|
|
+ std::string filename = test.lineInfo.file;
|
|
|
+ std::string::size_type lastSlash = filename.find_last_of( "\\/" );
|
|
|
+ if( lastSlash != std::string::npos )
|
|
|
+ filename = filename.substr( lastSlash+1 );
|
|
|
|
|
|
- class Session {
|
|
|
+ std::string::size_type lastDot = filename.find_last_of( "." );
|
|
|
+ if( lastDot != std::string::npos )
|
|
|
+ filename = filename.substr( 0, lastDot );
|
|
|
+
|
|
|
+ tags.insert( "#" + filename );
|
|
|
+ setTags( test, tags );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class Session : NonCopyable {
|
|
|
static bool alreadyInstantiated;
|
|
|
|
|
|
public:
|
|
@@ -5324,7 +6341,7 @@ namespace Catch {
|
|
|
: m_cli( makeCommandLineParser() ) {
|
|
|
if( alreadyInstantiated ) {
|
|
|
std::string msg = "Only one instance of Catch::Session can ever be used";
|
|
|
- std::cerr << msg << std::endl;
|
|
|
+ Catch::cerr() << msg << std::endl;
|
|
|
throw std::logic_error( msg );
|
|
|
}
|
|
|
alreadyInstantiated = true;
|
|
@@ -5334,21 +6351,16 @@ namespace Catch {
|
|
|
}
|
|
|
|
|
|
void showHelp( std::string const& processName ) {
|
|
|
- std::cout << "\nCatch v" << libraryVersion.majorVersion << "."
|
|
|
- << libraryVersion.minorVersion << " build "
|
|
|
- << libraryVersion.buildNumber;
|
|
|
- if( libraryVersion.branchName != std::string( "master" ) )
|
|
|
- std::cout << " (" << libraryVersion.branchName << " branch)";
|
|
|
- std::cout << "\n";
|
|
|
+ Catch::cout() << "\nCatch v" << libraryVersion << "\n";
|
|
|
|
|
|
- m_cli.usage( std::cout, processName );
|
|
|
- std::cout << "For more detail usage please see the project docs\n" << std::endl;
|
|
|
+ m_cli.usage( Catch::cout(), processName );
|
|
|
+ Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
|
|
|
}
|
|
|
|
|
|
- int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
|
|
+ int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
|
|
try {
|
|
|
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
|
|
|
- m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
|
|
|
+ m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
|
|
|
if( m_configData.showHelp )
|
|
|
showHelp( m_configData.processName );
|
|
|
m_config.reset();
|
|
@@ -5356,11 +6368,12 @@ namespace Catch {
|
|
|
catch( std::exception& ex ) {
|
|
|
{
|
|
|
Colour colourGuard( Colour::Red );
|
|
|
- std::cerr << "\nError(s) in input:\n"
|
|
|
- << Text( ex.what(), TextAttributes().setIndent(2) )
|
|
|
- << "\n\n";
|
|
|
+ Catch::cerr()
|
|
|
+ << "\nError(s) in input:\n"
|
|
|
+ << Text( ex.what(), TextAttributes().setIndent(2) )
|
|
|
+ << "\n\n";
|
|
|
}
|
|
|
- m_cli.usage( std::cout, m_configData.processName );
|
|
|
+ m_cli.usage( Catch::cout(), m_configData.processName );
|
|
|
return (std::numeric_limits<int>::max)();
|
|
|
}
|
|
|
return 0;
|
|
@@ -5371,7 +6384,7 @@ namespace Catch {
|
|
|
m_config.reset();
|
|
|
}
|
|
|
|
|
|
- int run( int argc, char* const argv[] ) {
|
|
|
+ int run( int argc, char const* const* const argv ) {
|
|
|
|
|
|
int returnCode = applyCommandLine( argc, argv );
|
|
|
if( returnCode == 0 )
|
|
@@ -5386,16 +6399,20 @@ namespace Catch {
|
|
|
try
|
|
|
{
|
|
|
config(); // Force config to be constructed
|
|
|
- Runner runner( m_config );
|
|
|
+
|
|
|
+ seedRng( *m_config );
|
|
|
+
|
|
|
+ if( m_configData.filenamesAsTags )
|
|
|
+ applyFilenamesAsTags( *m_config );
|
|
|
|
|
|
// Handle list request
|
|
|
if( Option<std::size_t> listed = list( config() ) )
|
|
|
return static_cast<int>( *listed );
|
|
|
|
|
|
- return static_cast<int>( runner.runTests().assertions.failed );
|
|
|
+ return static_cast<int>( runTests( m_config ).assertions.failed );
|
|
|
}
|
|
|
catch( std::exception& ex ) {
|
|
|
- std::cerr << ex.what() << std::endl;
|
|
|
+ Catch::cerr() << ex.what() << std::endl;
|
|
|
return (std::numeric_limits<int>::max)();
|
|
|
}
|
|
|
}
|
|
@@ -5414,7 +6431,6 @@ namespace Catch {
|
|
|
m_config = new Config( m_configData );
|
|
|
return *m_config;
|
|
|
}
|
|
|
-
|
|
|
private:
|
|
|
Clara::CommandLine<ConfigData> m_cli;
|
|
|
std::vector<Clara::Parser::Token> m_unusedTokens;
|
|
@@ -5436,12 +6452,98 @@ namespace Catch {
|
|
|
#include <set>
|
|
|
#include <sstream>
|
|
|
#include <iostream>
|
|
|
+#include <algorithm>
|
|
|
+
|
|
|
+#ifdef CATCH_CPP14_OR_GREATER
|
|
|
+#include <random>
|
|
|
+#endif
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
+ struct RandomNumberGenerator {
|
|
|
+ typedef int result_type;
|
|
|
+
|
|
|
+ result_type operator()( result_type n ) const { return std::rand() % n; }
|
|
|
+
|
|
|
+#ifdef CATCH_CPP14_OR_GREATER
|
|
|
+ static constexpr result_type min() { return 0; }
|
|
|
+ static constexpr result_type max() { return 1000000; }
|
|
|
+ result_type operator()() const { return std::rand() % max(); }
|
|
|
+#endif
|
|
|
+ template<typename V>
|
|
|
+ static void shuffle( V& vector ) {
|
|
|
+ RandomNumberGenerator rng;
|
|
|
+#ifdef CATCH_CPP14_OR_GREATER
|
|
|
+ std::shuffle( vector.begin(), vector.end(), rng );
|
|
|
+#else
|
|
|
+ std::random_shuffle( vector.begin(), vector.end(), rng );
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
|
|
|
+
|
|
|
+ std::vector<TestCase> sorted = unsortedTestCases;
|
|
|
+
|
|
|
+ switch( config.runOrder() ) {
|
|
|
+ case RunTests::InLexicographicalOrder:
|
|
|
+ std::sort( sorted.begin(), sorted.end() );
|
|
|
+ break;
|
|
|
+ case RunTests::InRandomOrder:
|
|
|
+ {
|
|
|
+ seedRng( config );
|
|
|
+ RandomNumberGenerator::shuffle( sorted );
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case RunTests::InDeclarationOrder:
|
|
|
+ // already in declaration order
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return sorted;
|
|
|
+ }
|
|
|
+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
|
|
|
+ return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
|
|
|
+ }
|
|
|
+
|
|
|
+ void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
|
|
|
+ std::set<TestCase> seenFunctions;
|
|
|
+ for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it ) {
|
|
|
+ std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
|
|
|
+ if( !prev.second ) {
|
|
|
+ std::ostringstream ss;
|
|
|
+
|
|
|
+ ss << Colour( Colour::Red )
|
|
|
+ << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
|
|
+ << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
|
|
|
+ << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
|
|
+
|
|
|
+ throw std::runtime_error(ss.str());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
|
|
|
+ std::vector<TestCase> filtered;
|
|
|
+ filtered.reserve( testCases.size() );
|
|
|
+ for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ if( matchTest( *it, testSpec, config ) )
|
|
|
+ filtered.push_back( *it );
|
|
|
+ return filtered;
|
|
|
+ }
|
|
|
+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
|
|
|
+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
|
|
|
+ }
|
|
|
+
|
|
|
class TestRegistry : public ITestCaseRegistry {
|
|
|
public:
|
|
|
- TestRegistry() : m_unnamedCount( 0 ) {}
|
|
|
+ TestRegistry()
|
|
|
+ : m_currentSortOrder( RunTests::InDeclarationOrder ),
|
|
|
+ m_unnamedCount( 0 )
|
|
|
+ {}
|
|
|
virtual ~TestRegistry();
|
|
|
|
|
|
virtual void registerTest( TestCase const& testCase ) {
|
|
@@ -5451,49 +6553,29 @@ namespace Catch {
|
|
|
oss << "Anonymous test case " << ++m_unnamedCount;
|
|
|
return registerTest( testCase.withName( oss.str() ) );
|
|
|
}
|
|
|
-
|
|
|
- if( m_functions.find( testCase ) == m_functions.end() ) {
|
|
|
- m_functions.insert( testCase );
|
|
|
- m_functionsInOrder.push_back( testCase );
|
|
|
- if( !testCase.isHidden() )
|
|
|
- m_nonHiddenFunctions.push_back( testCase );
|
|
|
- }
|
|
|
- else {
|
|
|
- TestCase const& prev = *m_functions.find( testCase );
|
|
|
- {
|
|
|
- Colour colourGuard( Colour::Red );
|
|
|
- std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
|
|
|
- << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
|
|
|
- << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
|
|
|
- }
|
|
|
- exit(1);
|
|
|
- }
|
|
|
+ m_functions.push_back( testCase );
|
|
|
}
|
|
|
|
|
|
virtual std::vector<TestCase> const& getAllTests() const {
|
|
|
- return m_functionsInOrder;
|
|
|
+ return m_functions;
|
|
|
}
|
|
|
+ virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const {
|
|
|
+ if( m_sortedFunctions.empty() )
|
|
|
+ enforceNoDuplicateTestCases( m_functions );
|
|
|
|
|
|
- virtual std::vector<TestCase> const& getAllNonHiddenTests() const {
|
|
|
- return m_nonHiddenFunctions;
|
|
|
- }
|
|
|
-
|
|
|
- virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const {
|
|
|
- for( std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(),
|
|
|
- itEnd = m_functionsInOrder.end();
|
|
|
- it != itEnd;
|
|
|
- ++it ) {
|
|
|
- if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) )
|
|
|
- matchingTestCases.push_back( *it );
|
|
|
+ if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
|
|
|
+ m_sortedFunctions = sortTests( config, m_functions );
|
|
|
+ m_currentSortOrder = config.runOrder();
|
|
|
}
|
|
|
+ return m_sortedFunctions;
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
-
|
|
|
- std::set<TestCase> m_functions;
|
|
|
- std::vector<TestCase> m_functionsInOrder;
|
|
|
- std::vector<TestCase> m_nonHiddenFunctions;
|
|
|
+ std::vector<TestCase> m_functions;
|
|
|
+ mutable RunTests::InWhatOrder m_currentSortOrder;
|
|
|
+ mutable std::vector<TestCase> m_sortedFunctions;
|
|
|
size_t m_unnamedCount;
|
|
|
+ std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
|
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
@@ -5526,29 +6608,38 @@ namespace Catch {
|
|
|
return className;
|
|
|
}
|
|
|
|
|
|
- ///////////////////////////////////////////////////////////////////////////
|
|
|
+ void registerTestCase
|
|
|
+ ( ITestCase* testCase,
|
|
|
+ char const* classOrQualifiedMethodName,
|
|
|
+ NameAndDesc const& nameAndDesc,
|
|
|
+ SourceLineInfo const& lineInfo ) {
|
|
|
|
|
|
- AutoReg::AutoReg( TestFunction function,
|
|
|
- SourceLineInfo const& lineInfo,
|
|
|
- NameAndDesc const& nameAndDesc ) {
|
|
|
+ getMutableRegistryHub().registerTest
|
|
|
+ ( makeTestCase
|
|
|
+ ( testCase,
|
|
|
+ extractClassName( classOrQualifiedMethodName ),
|
|
|
+ nameAndDesc.name,
|
|
|
+ nameAndDesc.description,
|
|
|
+ lineInfo ) );
|
|
|
+ }
|
|
|
+ void registerTestCaseFunction
|
|
|
+ ( TestFunction function,
|
|
|
+ SourceLineInfo const& lineInfo,
|
|
|
+ NameAndDesc const& nameAndDesc ) {
|
|
|
registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
|
|
|
}
|
|
|
|
|
|
- AutoReg::~AutoReg() {}
|
|
|
-
|
|
|
- void AutoReg::registerTestCase( ITestCase* testCase,
|
|
|
- char const* classOrQualifiedMethodName,
|
|
|
- NameAndDesc const& nameAndDesc,
|
|
|
- SourceLineInfo const& lineInfo ) {
|
|
|
+ ///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
- getMutableRegistryHub().registerTest
|
|
|
- ( makeTestCase( testCase,
|
|
|
- extractClassName( classOrQualifiedMethodName ),
|
|
|
- nameAndDesc.name,
|
|
|
- nameAndDesc.description,
|
|
|
- lineInfo ) );
|
|
|
+ AutoReg::AutoReg
|
|
|
+ ( TestFunction function,
|
|
|
+ SourceLineInfo const& lineInfo,
|
|
|
+ NameAndDesc const& nameAndDesc ) {
|
|
|
+ registerTestCaseFunction( function, lineInfo, nameAndDesc );
|
|
|
}
|
|
|
|
|
|
+ AutoReg::~AutoReg() {}
|
|
|
+
|
|
|
} // end namespace Catch
|
|
|
|
|
|
// #included from: catch_reporter_registry.hpp
|
|
@@ -5562,27 +6653,32 @@ namespace Catch {
|
|
|
|
|
|
public:
|
|
|
|
|
|
- virtual ~ReporterRegistry() {
|
|
|
- deleteAllValues( m_factories );
|
|
|
- }
|
|
|
+ virtual ~ReporterRegistry() CATCH_OVERRIDE {}
|
|
|
|
|
|
- virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const {
|
|
|
+ virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
|
|
|
FactoryMap::const_iterator it = m_factories.find( name );
|
|
|
if( it == m_factories.end() )
|
|
|
- return NULL;
|
|
|
+ return CATCH_NULL;
|
|
|
return it->second->create( ReporterConfig( config ) );
|
|
|
}
|
|
|
|
|
|
- void registerReporter( std::string const& name, IReporterFactory* factory ) {
|
|
|
+ void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
|
|
|
m_factories.insert( std::make_pair( name, factory ) );
|
|
|
}
|
|
|
+ void registerListener( Ptr<IReporterFactory> const& factory ) {
|
|
|
+ m_listeners.push_back( factory );
|
|
|
+ }
|
|
|
|
|
|
- FactoryMap const& getFactories() const {
|
|
|
+ virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
|
|
|
return m_factories;
|
|
|
}
|
|
|
+ virtual Listeners const& getListeners() const CATCH_OVERRIDE {
|
|
|
+ return m_listeners;
|
|
|
+ }
|
|
|
|
|
|
private:
|
|
|
FactoryMap m_factories;
|
|
|
+ Listeners m_listeners;
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -5610,13 +6706,13 @@ namespace Catch {
|
|
|
#ifdef __OBJC__
|
|
|
// In Objective-C try objective-c exceptions first
|
|
|
@try {
|
|
|
- throw;
|
|
|
+ return tryTranslators();
|
|
|
}
|
|
|
@catch (NSException *exception) {
|
|
|
- return toString( [exception description] );
|
|
|
+ return Catch::toString( [exception description] );
|
|
|
}
|
|
|
#else
|
|
|
- throw;
|
|
|
+ return tryTranslators();
|
|
|
#endif
|
|
|
}
|
|
|
catch( TestFailureException& ) {
|
|
@@ -5632,20 +6728,15 @@ namespace Catch {
|
|
|
return msg;
|
|
|
}
|
|
|
catch(...) {
|
|
|
- return tryTranslators( m_translators.begin() );
|
|
|
+ return "Unknown exception";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
|
|
|
- if( it == m_translators.end() )
|
|
|
- return "Unknown exception";
|
|
|
-
|
|
|
- try {
|
|
|
- return (*it)->translate();
|
|
|
- }
|
|
|
- catch(...) {
|
|
|
- return tryTranslators( it+1 );
|
|
|
- }
|
|
|
+ std::string tryTranslators() const {
|
|
|
+ if( m_translators.empty() )
|
|
|
+ throw;
|
|
|
+ else
|
|
|
+ return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
|
|
|
}
|
|
|
|
|
|
private:
|
|
@@ -5665,24 +6756,27 @@ namespace Catch {
|
|
|
public: // IRegistryHub
|
|
|
RegistryHub() {
|
|
|
}
|
|
|
- virtual IReporterRegistry const& getReporterRegistry() const {
|
|
|
+ virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
|
|
|
return m_reporterRegistry;
|
|
|
}
|
|
|
- virtual ITestCaseRegistry const& getTestCaseRegistry() const {
|
|
|
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
|
|
|
return m_testCaseRegistry;
|
|
|
}
|
|
|
- virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
|
|
|
+ virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
|
|
|
return m_exceptionTranslatorRegistry;
|
|
|
}
|
|
|
|
|
|
public: // IMutableRegistryHub
|
|
|
- virtual void registerReporter( std::string const& name, IReporterFactory* factory ) {
|
|
|
+ virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
|
|
|
m_reporterRegistry.registerReporter( name, factory );
|
|
|
}
|
|
|
- virtual void registerTest( TestCase const& testInfo ) {
|
|
|
+ virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
|
|
|
+ m_reporterRegistry.registerListener( factory );
|
|
|
+ }
|
|
|
+ virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
|
|
|
m_testCaseRegistry.registerTest( testInfo );
|
|
|
}
|
|
|
- virtual void registerTranslator( const IExceptionTranslator* translator ) {
|
|
|
+ virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
|
|
|
m_exceptionTranslatorRegistry.registerTranslator( translator );
|
|
|
}
|
|
|
|
|
@@ -5694,7 +6788,7 @@ namespace Catch {
|
|
|
|
|
|
// Single, global, instance
|
|
|
inline RegistryHub*& getTheRegistryHub() {
|
|
|
- static RegistryHub* theRegistryHub = NULL;
|
|
|
+ static RegistryHub* theRegistryHub = CATCH_NULL;
|
|
|
if( !theRegistryHub )
|
|
|
theRegistryHub = new RegistryHub();
|
|
|
return theRegistryHub;
|
|
@@ -5709,7 +6803,7 @@ namespace Catch {
|
|
|
}
|
|
|
void cleanUp() {
|
|
|
delete getTheRegistryHub();
|
|
|
- getTheRegistryHub() = NULL;
|
|
|
+ getTheRegistryHub() = CATCH_NULL;
|
|
|
cleanUpContext();
|
|
|
}
|
|
|
std::string translateActiveException() {
|
|
@@ -5745,21 +6839,9 @@ namespace Catch {
|
|
|
// #included from: catch_stream.hpp
|
|
|
#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
|
|
|
|
|
|
-// #included from: catch_streambuf.h
|
|
|
-#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
|
|
|
-
|
|
|
-#include <streambuf>
|
|
|
-
|
|
|
-namespace Catch {
|
|
|
-
|
|
|
- class StreamBufBase : public std::streambuf {
|
|
|
- public:
|
|
|
- virtual ~StreamBufBase() CATCH_NOEXCEPT;
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
#include <stdexcept>
|
|
|
#include <cstdio>
|
|
|
+#include <iostream>
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
@@ -5801,6 +6883,19 @@ namespace Catch {
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
+ FileStream::FileStream( std::string const& filename ) {
|
|
|
+ m_ofs.open( filename.c_str() );
|
|
|
+ if( m_ofs.fail() ) {
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << "Unable to open file: '" << filename << "'";
|
|
|
+ throw std::domain_error( oss.str() );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ std::ostream& FileStream::stream() const {
|
|
|
+ return m_ofs;
|
|
|
+ }
|
|
|
+
|
|
|
struct OutputDebugWriter {
|
|
|
|
|
|
void operator()( std::string const&str ) {
|
|
@@ -5808,28 +6903,40 @@ namespace Catch {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- Stream::Stream()
|
|
|
- : streamBuf( NULL ), isOwned( false )
|
|
|
+ DebugOutStream::DebugOutStream()
|
|
|
+ : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
|
|
|
+ m_os( m_streamBuf.get() )
|
|
|
{}
|
|
|
|
|
|
- Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
|
|
|
- : streamBuf( _streamBuf ), isOwned( _isOwned )
|
|
|
+ std::ostream& DebugOutStream::stream() const {
|
|
|
+ return m_os;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Store the streambuf from cout up-front because
|
|
|
+ // cout may get redirected when running tests
|
|
|
+ CoutStream::CoutStream()
|
|
|
+ : m_os( Catch::cout().rdbuf() )
|
|
|
{}
|
|
|
|
|
|
- void Stream::release() {
|
|
|
- if( isOwned ) {
|
|
|
- delete streamBuf;
|
|
|
- streamBuf = NULL;
|
|
|
- isOwned = false;
|
|
|
- }
|
|
|
+ std::ostream& CoutStream::stream() const {
|
|
|
+ return m_os;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
|
|
|
+ std::ostream& cout() {
|
|
|
+ return std::cout;
|
|
|
+ }
|
|
|
+ std::ostream& cerr() {
|
|
|
+ return std::cerr;
|
|
|
}
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
class Context : public IMutableContext {
|
|
|
|
|
|
- Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {}
|
|
|
+ Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {}
|
|
|
Context( Context const& );
|
|
|
void operator=( Context const& );
|
|
|
|
|
@@ -5872,10 +6979,10 @@ namespace Catch {
|
|
|
std::string testName = getResultCapture()->getCurrentTestName();
|
|
|
|
|
|
std::map<std::string, IGeneratorsForTest*>::const_iterator it =
|
|
|
- m_generatorsByTestName.find( testName );
|
|
|
+ m_generatorsByTestName.find( testName );
|
|
|
return it != m_generatorsByTestName.end()
|
|
|
? it->second
|
|
|
- : NULL;
|
|
|
+ : CATCH_NULL;
|
|
|
}
|
|
|
|
|
|
IGeneratorsForTest& getGeneratorsForCurrentTest() {
|
|
@@ -5896,7 +7003,7 @@ namespace Catch {
|
|
|
};
|
|
|
|
|
|
namespace {
|
|
|
- Context* currentContext = NULL;
|
|
|
+ Context* currentContext = CATCH_NULL;
|
|
|
}
|
|
|
IMutableContext& getCurrentMutableContext() {
|
|
|
if( !currentContext )
|
|
@@ -5907,31 +7014,44 @@ namespace Catch {
|
|
|
return getCurrentMutableContext();
|
|
|
}
|
|
|
|
|
|
- Stream createStream( std::string const& streamName ) {
|
|
|
- if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false );
|
|
|
- if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false );
|
|
|
- if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
|
|
|
-
|
|
|
- throw std::domain_error( "Unknown stream: " + streamName );
|
|
|
- }
|
|
|
-
|
|
|
void cleanUpContext() {
|
|
|
delete currentContext;
|
|
|
- currentContext = NULL;
|
|
|
+ currentContext = CATCH_NULL;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// #included from: catch_console_colour_impl.hpp
|
|
|
#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
|
|
|
|
|
|
-namespace Catch { namespace Detail {
|
|
|
- struct IColourImpl {
|
|
|
- virtual ~IColourImpl() {}
|
|
|
- virtual void use( Colour::Code _colourCode ) = 0;
|
|
|
- };
|
|
|
-}}
|
|
|
+namespace Catch {
|
|
|
+ namespace {
|
|
|
|
|
|
-#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
|
|
+ struct IColourImpl {
|
|
|
+ virtual ~IColourImpl() {}
|
|
|
+ virtual void use( Colour::Code _colourCode ) = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct NoColourImpl : IColourImpl {
|
|
|
+ void use( Colour::Code ) {}
|
|
|
+
|
|
|
+ static IColourImpl* instance() {
|
|
|
+ static NoColourImpl s_instance;
|
|
|
+ return &s_instance;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ } // anon namespace
|
|
|
+} // namespace Catch
|
|
|
+
|
|
|
+#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
|
|
|
+# ifdef CATCH_PLATFORM_WINDOWS
|
|
|
+# define CATCH_CONFIG_COLOUR_WINDOWS
|
|
|
+# else
|
|
|
+# define CATCH_CONFIG_COLOUR_ANSI
|
|
|
+# endif
|
|
|
+#endif
|
|
|
+
|
|
|
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
|
|
|
|
|
|
#ifndef NOMINMAX
|
|
|
#define NOMINMAX
|
|
@@ -5946,18 +7066,19 @@ namespace Catch { namespace Detail {
|
|
|
namespace Catch {
|
|
|
namespace {
|
|
|
|
|
|
- class Win32ColourImpl : public Detail::IColourImpl {
|
|
|
+ class Win32ColourImpl : public IColourImpl {
|
|
|
public:
|
|
|
Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
|
|
|
{
|
|
|
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
|
|
|
GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
|
|
|
- originalAttributes = csbiInfo.wAttributes;
|
|
|
+ originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
|
|
|
+ originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
|
|
|
}
|
|
|
|
|
|
virtual void use( Colour::Code _colourCode ) {
|
|
|
switch( _colourCode ) {
|
|
|
- case Colour::None: return setTextAttribute( originalAttributes );
|
|
|
+ case Colour::None: return setTextAttribute( originalForegroundAttributes );
|
|
|
case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
|
|
|
case Colour::Red: return setTextAttribute( FOREGROUND_RED );
|
|
|
case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
|
|
@@ -5977,25 +7098,33 @@ namespace {
|
|
|
|
|
|
private:
|
|
|
void setTextAttribute( WORD _textAttribute ) {
|
|
|
- SetConsoleTextAttribute( stdoutHandle, _textAttribute );
|
|
|
+ SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
|
|
|
}
|
|
|
HANDLE stdoutHandle;
|
|
|
- WORD originalAttributes;
|
|
|
+ WORD originalForegroundAttributes;
|
|
|
+ WORD originalBackgroundAttributes;
|
|
|
};
|
|
|
|
|
|
- inline bool shouldUseColourForPlatform() {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- static Detail::IColourImpl* platformColourInstance() {
|
|
|
+ IColourImpl* platformColourInstance() {
|
|
|
static Win32ColourImpl s_instance;
|
|
|
- return &s_instance;
|
|
|
+
|
|
|
+ Ptr<IConfig const> config = getCurrentContext().getConfig();
|
|
|
+ UseColour::YesOrNo colourMode = config
|
|
|
+ ? config->useColour()
|
|
|
+ : UseColour::Auto;
|
|
|
+ if( colourMode == UseColour::Auto )
|
|
|
+ colourMode = !isDebuggerActive()
|
|
|
+ ? UseColour::Yes
|
|
|
+ : UseColour::No;
|
|
|
+ return colourMode == UseColour::Yes
|
|
|
+ ? &s_instance
|
|
|
+ : NoColourImpl::instance();
|
|
|
}
|
|
|
|
|
|
} // end anon namespace
|
|
|
} // end namespace Catch
|
|
|
|
|
|
-#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
|
|
+#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
@@ -6006,7 +7135,7 @@ namespace {
|
|
|
// Thanks to Adam Strzelecki for original contribution
|
|
|
// (http://github.com/nanoant)
|
|
|
// https://github.com/philsquared/Catch/pull/131
|
|
|
- class PosixColourImpl : public Detail::IColourImpl {
|
|
|
+ class PosixColourImpl : public IColourImpl {
|
|
|
public:
|
|
|
virtual void use( Colour::Code _colourCode ) {
|
|
|
switch( _colourCode ) {
|
|
@@ -6027,53 +7156,53 @@ namespace {
|
|
|
case Colour::Bright: throw std::logic_error( "not a colour" );
|
|
|
}
|
|
|
}
|
|
|
+ static IColourImpl* instance() {
|
|
|
+ static PosixColourImpl s_instance;
|
|
|
+ return &s_instance;
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
void setColour( const char* _escapeCode ) {
|
|
|
- std::cout << '\033' << _escapeCode;
|
|
|
+ Catch::cout() << '\033' << _escapeCode;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- inline bool shouldUseColourForPlatform() {
|
|
|
- return isatty(STDOUT_FILENO);
|
|
|
- }
|
|
|
-
|
|
|
- static Detail::IColourImpl* platformColourInstance() {
|
|
|
- static PosixColourImpl s_instance;
|
|
|
- return &s_instance;
|
|
|
+ IColourImpl* platformColourInstance() {
|
|
|
+ Ptr<IConfig const> config = getCurrentContext().getConfig();
|
|
|
+ UseColour::YesOrNo colourMode = config
|
|
|
+ ? config->useColour()
|
|
|
+ : UseColour::Auto;
|
|
|
+ if( colourMode == UseColour::Auto )
|
|
|
+ colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
|
|
|
+ ? UseColour::Yes
|
|
|
+ : UseColour::No;
|
|
|
+ return colourMode == UseColour::Yes
|
|
|
+ ? PosixColourImpl::instance()
|
|
|
+ : NoColourImpl::instance();
|
|
|
}
|
|
|
|
|
|
} // end anon namespace
|
|
|
} // end namespace Catch
|
|
|
|
|
|
-#endif // not Windows
|
|
|
+#else // not Windows or ANSI ///////////////////////////////////////////////
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
- namespace {
|
|
|
- struct NoColourImpl : Detail::IColourImpl {
|
|
|
- void use( Colour::Code ) {}
|
|
|
+ static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
|
|
|
|
|
|
- static IColourImpl* instance() {
|
|
|
- static NoColourImpl s_instance;
|
|
|
- return &s_instance;
|
|
|
- }
|
|
|
- };
|
|
|
- static bool shouldUseColour() {
|
|
|
- return shouldUseColourForPlatform() && !isDebuggerActive();
|
|
|
- }
|
|
|
- }
|
|
|
+} // end namespace Catch
|
|
|
+
|
|
|
+#endif // Windows/ ANSI/ None
|
|
|
+
|
|
|
+namespace Catch {
|
|
|
|
|
|
Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
|
|
|
Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
|
|
|
Colour::~Colour(){ if( !m_moved ) use( None ); }
|
|
|
- void Colour::use( Code _colourCode ) {
|
|
|
- impl()->use( _colourCode );
|
|
|
- }
|
|
|
|
|
|
- Detail::IColourImpl* Colour::impl() {
|
|
|
- return shouldUseColour()
|
|
|
- ? platformColourInstance()
|
|
|
- : NoColourImpl::instance();
|
|
|
+ void Colour::use( Code _colourCode ) {
|
|
|
+ static IColourImpl* impl = platformColourInstance();
|
|
|
+ impl->use( _colourCode );
|
|
|
}
|
|
|
|
|
|
} // end namespace Catch
|
|
@@ -6238,7 +7367,7 @@ namespace Catch {
|
|
|
namespace Catch {
|
|
|
|
|
|
inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
|
|
|
- if( tag == "." ||
|
|
|
+ if( startsWith( tag, "." ) ||
|
|
|
tag == "hide" ||
|
|
|
tag == "!hide" )
|
|
|
return TestCaseInfo::IsHidden;
|
|
@@ -6258,13 +7387,13 @@ namespace Catch {
|
|
|
if( isReservedTag( tag ) ) {
|
|
|
{
|
|
|
Colour colourGuard( Colour::Red );
|
|
|
- std::cerr
|
|
|
+ Catch::cerr()
|
|
|
<< "Tag name [" << tag << "] not allowed.\n"
|
|
|
<< "Tag names starting with non alpha-numeric characters are reserved\n";
|
|
|
}
|
|
|
{
|
|
|
Colour colourGuard( Colour::FileName );
|
|
|
- std::cerr << _lineInfo << std::endl;
|
|
|
+ Catch::cerr() << _lineInfo << std::endl;
|
|
|
}
|
|
|
exit(1);
|
|
|
}
|
|
@@ -6292,14 +7421,15 @@ namespace Catch {
|
|
|
}
|
|
|
else {
|
|
|
if( c == ']' ) {
|
|
|
- enforceNotReservedTag( tag, _lineInfo );
|
|
|
-
|
|
|
- inTag = false;
|
|
|
- if( tag == "hide" || tag == "." )
|
|
|
+ TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
|
|
|
+ if( prop == TestCaseInfo::IsHidden )
|
|
|
isHidden = true;
|
|
|
- else
|
|
|
- tags.insert( tag );
|
|
|
+ else if( prop == TestCaseInfo::None )
|
|
|
+ enforceNotReservedTag( tag, _lineInfo );
|
|
|
+
|
|
|
+ tags.insert( tag );
|
|
|
tag.clear();
|
|
|
+ inTag = false;
|
|
|
}
|
|
|
else
|
|
|
tag += c;
|
|
@@ -6314,6 +7444,21 @@ namespace Catch {
|
|
|
return TestCase( _testCase, info );
|
|
|
}
|
|
|
|
|
|
+ void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags )
|
|
|
+ {
|
|
|
+ testCaseInfo.tags = tags;
|
|
|
+ testCaseInfo.lcaseTags.clear();
|
|
|
+
|
|
|
+ std::ostringstream oss;
|
|
|
+ for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
|
|
|
+ oss << "[" << *it << "]";
|
|
|
+ std::string lcaseTag = toLower( *it );
|
|
|
+ testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
|
|
|
+ testCaseInfo.lcaseTags.insert( lcaseTag );
|
|
|
+ }
|
|
|
+ testCaseInfo.tagsAsString = oss.str();
|
|
|
+ }
|
|
|
+
|
|
|
TestCaseInfo::TestCaseInfo( std::string const& _name,
|
|
|
std::string const& _className,
|
|
|
std::string const& _description,
|
|
@@ -6322,18 +7467,10 @@ namespace Catch {
|
|
|
: name( _name ),
|
|
|
className( _className ),
|
|
|
description( _description ),
|
|
|
- tags( _tags ),
|
|
|
lineInfo( _lineInfo ),
|
|
|
properties( None )
|
|
|
{
|
|
|
- std::ostringstream oss;
|
|
|
- for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) {
|
|
|
- oss << "[" << *it << "]";
|
|
|
- std::string lcaseTag = toLower( *it );
|
|
|
- properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) );
|
|
|
- lcaseTags.insert( lcaseTag );
|
|
|
- }
|
|
|
- tagsAsString = oss.str();
|
|
|
+ setTags( *this, _tags );
|
|
|
}
|
|
|
|
|
|
TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
|
|
@@ -6416,8 +7553,33 @@ namespace Catch {
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
- // These numbers are maintained by a script
|
|
|
- Version libraryVersion( 1, 0, 53, "master" );
|
|
|
+ Version::Version
|
|
|
+ ( unsigned int _majorVersion,
|
|
|
+ unsigned int _minorVersion,
|
|
|
+ unsigned int _patchNumber,
|
|
|
+ std::string const& _branchName,
|
|
|
+ unsigned int _buildNumber )
|
|
|
+ : majorVersion( _majorVersion ),
|
|
|
+ minorVersion( _minorVersion ),
|
|
|
+ patchNumber( _patchNumber ),
|
|
|
+ branchName( _branchName ),
|
|
|
+ buildNumber( _buildNumber )
|
|
|
+ {}
|
|
|
+
|
|
|
+ std::ostream& operator << ( std::ostream& os, Version const& version ) {
|
|
|
+ os << version.majorVersion << "."
|
|
|
+ << version.minorVersion << "."
|
|
|
+ << version.patchNumber;
|
|
|
+
|
|
|
+ if( !version.branchName.empty() ) {
|
|
|
+ os << "-" << version.branchName
|
|
|
+ << "." << version.buildNumber;
|
|
|
+ }
|
|
|
+ return os;
|
|
|
+ }
|
|
|
+
|
|
|
+ Version libraryVersion( 1, 5, 7, "", 0 );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// #included from: catch_message.hpp
|
|
@@ -6501,6 +7663,7 @@ namespace Catch
|
|
|
virtual void testCaseEnded( TestCaseStats const& testCaseStats );
|
|
|
virtual void testGroupEnded( TestGroupStats const& testGroupStats );
|
|
|
virtual void testRunEnded( TestRunStats const& testRunStats );
|
|
|
+ virtual void skipTest( TestCaseInfo const& );
|
|
|
|
|
|
private:
|
|
|
Ptr<IReporter> m_legacyReporter;
|
|
@@ -6574,6 +7737,8 @@ namespace Catch
|
|
|
void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
|
|
|
m_legacyReporter->EndTesting( testRunStats.totals );
|
|
|
}
|
|
|
+ void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// #included from: catch_timer.hpp
|
|
@@ -6596,17 +7761,17 @@ namespace Catch {
|
|
|
uint64_t getCurrentTicks() {
|
|
|
static uint64_t hz=0, hzo=0;
|
|
|
if (!hz) {
|
|
|
- QueryPerformanceFrequency((LARGE_INTEGER*)&hz);
|
|
|
- QueryPerformanceCounter((LARGE_INTEGER*)&hzo);
|
|
|
+ QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
|
|
|
+ QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
|
|
|
}
|
|
|
uint64_t t;
|
|
|
- QueryPerformanceCounter((LARGE_INTEGER*)&t);
|
|
|
+ QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
|
|
|
return ((t-hzo)*1000000)/hz;
|
|
|
}
|
|
|
#else
|
|
|
uint64_t getCurrentTicks() {
|
|
|
timeval t;
|
|
|
- gettimeofday(&t,NULL);
|
|
|
+ gettimeofday(&t,CATCH_NULL);
|
|
|
return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
|
|
|
}
|
|
|
#endif
|
|
@@ -6615,14 +7780,14 @@ namespace Catch {
|
|
|
void Timer::start() {
|
|
|
m_ticks = getCurrentTicks();
|
|
|
}
|
|
|
- unsigned int Timer::getElapsedNanoseconds() const {
|
|
|
+ unsigned int Timer::getElapsedMicroseconds() const {
|
|
|
return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
|
|
|
}
|
|
|
unsigned int Timer::getElapsedMilliseconds() const {
|
|
|
- return static_cast<unsigned int>((getCurrentTicks() - m_ticks)/1000);
|
|
|
+ return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
|
|
|
}
|
|
|
double Timer::getElapsedSeconds() const {
|
|
|
- return (getCurrentTicks() - m_ticks)/1000000.0;
|
|
|
+ return getElapsedMicroseconds()/1000000.0;
|
|
|
}
|
|
|
|
|
|
} // namespace Catch
|
|
@@ -6660,6 +7825,20 @@ namespace Catch {
|
|
|
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
|
|
|
}
|
|
|
|
|
|
+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
|
|
|
+ bool replaced = false;
|
|
|
+ std::size_t i = str.find( replaceThis );
|
|
|
+ while( i != std::string::npos ) {
|
|
|
+ replaced = true;
|
|
|
+ str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
|
|
|
+ if( i < str.size()-withThis.size() )
|
|
|
+ i = str.find( replaceThis, i+withThis.size() );
|
|
|
+ else
|
|
|
+ i = std::string::npos;
|
|
|
+ }
|
|
|
+ return replaced;
|
|
|
+ }
|
|
|
+
|
|
|
pluralise::pluralise( std::size_t count, std::string const& label )
|
|
|
: m_count( count ),
|
|
|
m_label( label )
|
|
@@ -6687,6 +7866,17 @@ namespace Catch {
|
|
|
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
|
|
|
return line == other.line && file == other.file;
|
|
|
}
|
|
|
+ bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
|
|
|
+ return line < other.line || ( line == other.line && file < other.file );
|
|
|
+ }
|
|
|
+
|
|
|
+ void seedRng( IConfig const& config ) {
|
|
|
+ if( config.rngSeed() != 0 )
|
|
|
+ std::srand( config.rngSeed() );
|
|
|
+ }
|
|
|
+ unsigned int rngSeed() {
|
|
|
+ return getCurrentContext().getConfig()->rngSeed();
|
|
|
+ }
|
|
|
|
|
|
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
|
|
#ifndef __GNUG__
|
|
@@ -6727,8 +7917,13 @@ namespace Catch {
|
|
|
}
|
|
|
|
|
|
Section::~Section() {
|
|
|
- if( m_sectionIncluded )
|
|
|
- getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
|
|
|
+ if( m_sectionIncluded ) {
|
|
|
+ SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
|
|
|
+ if( std::uncaught_exception() )
|
|
|
+ getResultCapture().sectionEndedEarly( endInfo );
|
|
|
+ else
|
|
|
+ getResultCapture().sectionEnded( endInfo );
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// This indicates whether the section should be executed or not
|
|
@@ -6780,8 +7975,8 @@ namespace Catch {
|
|
|
// Call sysctl.
|
|
|
|
|
|
size = sizeof(info);
|
|
|
- if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) {
|
|
|
- std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
|
|
|
+ if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) {
|
|
|
+ Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -6822,7 +8017,7 @@ namespace Catch {
|
|
|
namespace Catch {
|
|
|
void writeToDebugConsole( std::string const& text ) {
|
|
|
// !TBD: Need a version for Mac/ XCode and other IDEs
|
|
|
- std::cout << text;
|
|
|
+ Catch::cout() << text;
|
|
|
}
|
|
|
}
|
|
|
#endif // Platform
|
|
@@ -6834,7 +8029,11 @@ namespace Catch {
|
|
|
|
|
|
namespace Detail {
|
|
|
|
|
|
+ const std::string unprintableString = "{?}";
|
|
|
+
|
|
|
namespace {
|
|
|
+ const int hexThreshold = 255;
|
|
|
+
|
|
|
struct Endianness {
|
|
|
enum Arch { Big, Little };
|
|
|
|
|
@@ -6892,7 +8091,7 @@ std::string toString( std::wstring const& value ) {
|
|
|
s.reserve( value.size() );
|
|
|
for(size_t i = 0; i < value.size(); ++i )
|
|
|
s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
|
|
|
- return toString( s );
|
|
|
+ return Catch::toString( s );
|
|
|
}
|
|
|
|
|
|
std::string toString( const char* const value ) {
|
|
@@ -6916,20 +8115,21 @@ std::string toString( wchar_t* const value )
|
|
|
std::string toString( int value ) {
|
|
|
std::ostringstream oss;
|
|
|
oss << value;
|
|
|
+ if( value > Detail::hexThreshold )
|
|
|
+ oss << " (0x" << std::hex << value << ")";
|
|
|
return oss.str();
|
|
|
}
|
|
|
|
|
|
std::string toString( unsigned long value ) {
|
|
|
std::ostringstream oss;
|
|
|
- if( value > 8192 )
|
|
|
- oss << "0x" << std::hex << value;
|
|
|
- else
|
|
|
- oss << value;
|
|
|
+ oss << value;
|
|
|
+ if( value > Detail::hexThreshold )
|
|
|
+ oss << " (0x" << std::hex << value << ")";
|
|
|
return oss.str();
|
|
|
}
|
|
|
|
|
|
std::string toString( unsigned int value ) {
|
|
|
- return toString( static_cast<unsigned long>( value ) );
|
|
|
+ return Catch::toString( static_cast<unsigned long>( value ) );
|
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
@@ -6973,6 +8173,23 @@ std::string toString( unsigned char value ) {
|
|
|
return toString( static_cast<char>( value ) );
|
|
|
}
|
|
|
|
|
|
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
|
|
|
+std::string toString( long long value ) {
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << value;
|
|
|
+ if( value > Detail::hexThreshold )
|
|
|
+ oss << " (0x" << std::hex << value << ")";
|
|
|
+ return oss.str();
|
|
|
+}
|
|
|
+std::string toString( unsigned long long value ) {
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << value;
|
|
|
+ if( value > Detail::hexThreshold )
|
|
|
+ oss << " (0x" << std::hex << value << ")";
|
|
|
+ return oss.str();
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
|
|
std::string toString( std::nullptr_t ) {
|
|
|
return "nullptr";
|
|
@@ -7002,11 +8219,17 @@ std::string toString( std::nullptr_t ) {
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
+ std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) {
|
|
|
+ return secondArg.empty() || secondArg == "\"\""
|
|
|
+ ? capturedExpression
|
|
|
+ : capturedExpression + ", " + secondArg;
|
|
|
+ }
|
|
|
ResultBuilder::ResultBuilder( char const* macroName,
|
|
|
SourceLineInfo const& lineInfo,
|
|
|
char const* capturedExpression,
|
|
|
- ResultDisposition::Flags resultDisposition )
|
|
|
- : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ),
|
|
|
+ ResultDisposition::Flags resultDisposition,
|
|
|
+ char const* secondArg )
|
|
|
+ : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
|
|
|
m_shouldDebugBreak( false ),
|
|
|
m_shouldThrow( false )
|
|
|
{}
|
|
@@ -7043,19 +8266,45 @@ namespace Catch {
|
|
|
captureResult( ResultWas::ThrewException );
|
|
|
}
|
|
|
|
|
|
- void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
|
|
|
- setResultType( resultType );
|
|
|
- captureExpression();
|
|
|
+ void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
|
|
|
+ setResultType( resultType );
|
|
|
+ captureExpression();
|
|
|
+ }
|
|
|
+ void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
|
|
|
+ if( expectedMessage.empty() )
|
|
|
+ captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
|
|
|
+ else
|
|
|
+ captureExpectedException( Matchers::Equals( expectedMessage ) );
|
|
|
+ }
|
|
|
+
|
|
|
+ void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
|
|
|
+
|
|
|
+ assert( m_exprComponents.testFalse == false );
|
|
|
+ AssertionResultData data = m_data;
|
|
|
+ data.resultType = ResultWas::Ok;
|
|
|
+ data.reconstructedExpression = m_assertionInfo.capturedExpression;
|
|
|
+
|
|
|
+ std::string actualMessage = Catch::translateActiveException();
|
|
|
+ if( !matcher.match( actualMessage ) ) {
|
|
|
+ data.resultType = ResultWas::ExpressionFailed;
|
|
|
+ data.reconstructedExpression = actualMessage;
|
|
|
+ }
|
|
|
+ AssertionResult result( m_assertionInfo, data );
|
|
|
+ handleResult( result );
|
|
|
}
|
|
|
|
|
|
void ResultBuilder::captureExpression() {
|
|
|
AssertionResult result = build();
|
|
|
+ handleResult( result );
|
|
|
+ }
|
|
|
+ void ResultBuilder::handleResult( AssertionResult const& result )
|
|
|
+ {
|
|
|
getResultCapture().assertionEnded( result );
|
|
|
|
|
|
if( !result.isOk() ) {
|
|
|
if( getCurrentContext().getConfig()->shouldDebugBreak() )
|
|
|
m_shouldDebugBreak = true;
|
|
|
- if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal )
|
|
|
+ if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
|
|
|
m_shouldThrow = true;
|
|
|
}
|
|
|
}
|
|
@@ -7195,19 +8444,157 @@ namespace Catch {
|
|
|
}
|
|
|
catch( std::exception& ex ) {
|
|
|
Colour colourGuard( Colour::Red );
|
|
|
- std::cerr << ex.what() << std::endl;
|
|
|
+ Catch::cerr() << ex.what() << std::endl;
|
|
|
exit(1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
} // end namespace Catch
|
|
|
|
|
|
+// #included from: ../reporters/catch_reporter_multi.hpp
|
|
|
+#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
|
|
|
+
|
|
|
+namespace Catch {
|
|
|
+
|
|
|
+class MultipleReporters : public SharedImpl<IStreamingReporter> {
|
|
|
+ typedef std::vector<Ptr<IStreamingReporter> > Reporters;
|
|
|
+ Reporters m_reporters;
|
|
|
+
|
|
|
+public:
|
|
|
+ void add( Ptr<IStreamingReporter> const& reporter ) {
|
|
|
+ m_reporters.push_back( reporter );
|
|
|
+ }
|
|
|
+
|
|
|
+public: // IStreamingReporter
|
|
|
+
|
|
|
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
|
|
|
+ return m_reporters[0]->getPreferences();
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->noMatchingTestCases( spec );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->testRunStarting( testRunInfo );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->testGroupStarting( groupInfo );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->testCaseStarting( testInfo );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->sectionStarting( sectionInfo );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->assertionStarting( assertionInfo );
|
|
|
+ }
|
|
|
+
|
|
|
+ // The return value indicates if the messages buffer should be cleared:
|
|
|
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
|
|
|
+ bool clearBuffer = false;
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ clearBuffer |= (*it)->assertionEnded( assertionStats );
|
|
|
+ return clearBuffer;
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->sectionEnded( sectionStats );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->testCaseEnded( testCaseStats );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->testGroupEnded( testGroupStats );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->testRunEnded( testRunStats );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
|
|
|
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it )
|
|
|
+ (*it)->skipTest( testInfo );
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
|
|
|
+ Ptr<IStreamingReporter> resultingReporter;
|
|
|
+
|
|
|
+ if( existingReporter ) {
|
|
|
+ MultipleReporters* multi = existingReporter->tryAsMulti();
|
|
|
+ if( !multi ) {
|
|
|
+ multi = new MultipleReporters;
|
|
|
+ resultingReporter = Ptr<IStreamingReporter>( multi );
|
|
|
+ if( existingReporter )
|
|
|
+ multi->add( existingReporter );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ resultingReporter = existingReporter;
|
|
|
+ multi->add( additionalReporter );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ resultingReporter = additionalReporter;
|
|
|
+
|
|
|
+ return resultingReporter;
|
|
|
+}
|
|
|
+
|
|
|
+} // end namespace Catch
|
|
|
+
|
|
|
// #included from: ../reporters/catch_reporter_xml.hpp
|
|
|
#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
|
|
|
|
|
|
// #included from: catch_reporter_bases.hpp
|
|
|
#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
|
|
|
|
|
|
+#include <cstring>
|
|
|
+
|
|
|
namespace Catch {
|
|
|
|
|
|
struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
|
|
@@ -7215,43 +8602,53 @@ namespace Catch {
|
|
|
StreamingReporterBase( ReporterConfig const& _config )
|
|
|
: m_config( _config.fullConfig() ),
|
|
|
stream( _config.stream() )
|
|
|
- {}
|
|
|
+ {
|
|
|
+ m_reporterPrefs.shouldRedirectStdOut = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
|
|
|
+ return m_reporterPrefs;
|
|
|
+ }
|
|
|
|
|
|
- virtual ~StreamingReporterBase();
|
|
|
+ virtual ~StreamingReporterBase() CATCH_OVERRIDE;
|
|
|
|
|
|
- virtual void noMatchingTestCases( std::string const& ) {}
|
|
|
+ virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {}
|
|
|
|
|
|
- virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
|
|
|
+ virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE {
|
|
|
currentTestRunInfo = _testRunInfo;
|
|
|
}
|
|
|
- virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
|
|
|
+ virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE {
|
|
|
currentGroupInfo = _groupInfo;
|
|
|
}
|
|
|
|
|
|
- virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
|
|
|
+ virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE {
|
|
|
currentTestCaseInfo = _testInfo;
|
|
|
}
|
|
|
- virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
|
|
|
+ virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
|
|
|
m_sectionStack.push_back( _sectionInfo );
|
|
|
}
|
|
|
|
|
|
- virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
|
|
|
+ virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE {
|
|
|
m_sectionStack.pop_back();
|
|
|
}
|
|
|
- virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
|
|
|
+ virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE {
|
|
|
currentTestCaseInfo.reset();
|
|
|
- assert( m_sectionStack.empty() );
|
|
|
}
|
|
|
- virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
|
|
|
+ virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE {
|
|
|
currentGroupInfo.reset();
|
|
|
}
|
|
|
- virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
|
|
|
+ virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE {
|
|
|
currentTestCaseInfo.reset();
|
|
|
currentGroupInfo.reset();
|
|
|
currentTestRunInfo.reset();
|
|
|
}
|
|
|
|
|
|
- Ptr<IConfig> m_config;
|
|
|
+ virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {
|
|
|
+ // Don't do anything with this by default.
|
|
|
+ // It can optionally be overridden in the derived class.
|
|
|
+ }
|
|
|
+
|
|
|
+ Ptr<IConfig const> m_config;
|
|
|
std::ostream& stream;
|
|
|
|
|
|
LazyStat<TestRunInfo> currentTestRunInfo;
|
|
@@ -7259,6 +8656,7 @@ namespace Catch {
|
|
|
LazyStat<TestCaseInfo> currentTestCaseInfo;
|
|
|
|
|
|
std::vector<SectionInfo> m_sectionStack;
|
|
|
+ ReporterPreferences m_reporterPrefs;
|
|
|
};
|
|
|
|
|
|
struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
|
|
@@ -7309,15 +8707,21 @@ namespace Catch {
|
|
|
CumulativeReporterBase( ReporterConfig const& _config )
|
|
|
: m_config( _config.fullConfig() ),
|
|
|
stream( _config.stream() )
|
|
|
- {}
|
|
|
+ {
|
|
|
+ m_reporterPrefs.shouldRedirectStdOut = false;
|
|
|
+ }
|
|
|
~CumulativeReporterBase();
|
|
|
|
|
|
- virtual void testRunStarting( TestRunInfo const& ) {}
|
|
|
- virtual void testGroupStarting( GroupInfo const& ) {}
|
|
|
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
|
|
|
+ return m_reporterPrefs;
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {}
|
|
|
+ virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {}
|
|
|
|
|
|
- virtual void testCaseStarting( TestCaseInfo const& ) {}
|
|
|
+ virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {}
|
|
|
|
|
|
- virtual void sectionStarting( SectionInfo const& sectionInfo ) {
|
|
|
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
|
|
|
SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
|
|
|
Ptr<SectionNode> node;
|
|
|
if( m_sectionStack.empty() ) {
|
|
@@ -7342,21 +8746,21 @@ namespace Catch {
|
|
|
m_deepestSection = node;
|
|
|
}
|
|
|
|
|
|
- virtual void assertionStarting( AssertionInfo const& ) {}
|
|
|
+ virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
|
|
|
|
|
|
- virtual bool assertionEnded( AssertionStats const& assertionStats ) {
|
|
|
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
|
|
|
assert( !m_sectionStack.empty() );
|
|
|
SectionNode& sectionNode = *m_sectionStack.back();
|
|
|
sectionNode.assertions.push_back( assertionStats );
|
|
|
return true;
|
|
|
}
|
|
|
- virtual void sectionEnded( SectionStats const& sectionStats ) {
|
|
|
+ virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
|
|
|
assert( !m_sectionStack.empty() );
|
|
|
SectionNode& node = *m_sectionStack.back();
|
|
|
node.stats = sectionStats;
|
|
|
m_sectionStack.pop_back();
|
|
|
}
|
|
|
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
|
|
|
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
|
|
|
Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
|
|
|
assert( m_sectionStack.size() == 0 );
|
|
|
node->children.push_back( m_rootSection );
|
|
@@ -7367,12 +8771,12 @@ namespace Catch {
|
|
|
m_deepestSection->stdOut = testCaseStats.stdOut;
|
|
|
m_deepestSection->stdErr = testCaseStats.stdErr;
|
|
|
}
|
|
|
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
|
|
|
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
|
|
|
Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
|
|
|
node->children.swap( m_testCases );
|
|
|
m_testGroups.push_back( node );
|
|
|
}
|
|
|
- virtual void testRunEnded( TestRunStats const& testRunStats ) {
|
|
|
+ virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
|
|
|
Ptr<TestRunNode> node = new TestRunNode( testRunStats );
|
|
|
node->children.swap( m_testGroups );
|
|
|
m_testRuns.push_back( node );
|
|
@@ -7380,7 +8784,9 @@ namespace Catch {
|
|
|
}
|
|
|
virtual void testRunEndedCumulative() = 0;
|
|
|
|
|
|
- Ptr<IConfig> m_config;
|
|
|
+ virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
|
|
|
+
|
|
|
+ Ptr<IConfig const> m_config;
|
|
|
std::ostream& stream;
|
|
|
std::vector<AssertionStats> m_assertions;
|
|
|
std::vector<std::vector<Ptr<SectionNode> > > m_sections;
|
|
@@ -7392,7 +8798,29 @@ namespace Catch {
|
|
|
Ptr<SectionNode> m_rootSection;
|
|
|
Ptr<SectionNode> m_deepestSection;
|
|
|
std::vector<Ptr<SectionNode> > m_sectionStack;
|
|
|
+ ReporterPreferences m_reporterPrefs;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ template<char C>
|
|
|
+ char const* getLineOfChars() {
|
|
|
+ static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
|
|
|
+ if( !*line ) {
|
|
|
+ memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
|
|
|
+ line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
|
|
|
+ }
|
|
|
+ return line;
|
|
|
+ }
|
|
|
+
|
|
|
+ struct TestEventListenerBase : StreamingReporterBase {
|
|
|
+ TestEventListenerBase( ReporterConfig const& _config )
|
|
|
+ : StreamingReporterBase( _config )
|
|
|
+ {}
|
|
|
|
|
|
+ virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
|
|
|
+ virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
} // end namespace Catch
|
|
@@ -7425,7 +8853,7 @@ namespace Catch {
|
|
|
template<typename T>
|
|
|
class ReporterRegistrar {
|
|
|
|
|
|
- class ReporterFactory : public IReporterFactory {
|
|
|
+ class ReporterFactory : public SharedImpl<IReporterFactory> {
|
|
|
|
|
|
// *** Please Note ***:
|
|
|
// - If you end up here looking at a compiler error because it's trying to register
|
|
@@ -7453,23 +8881,103 @@ namespace Catch {
|
|
|
getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+ template<typename T>
|
|
|
+ class ListenerRegistrar {
|
|
|
+
|
|
|
+ class ListenerFactory : public SharedImpl<IReporterFactory> {
|
|
|
+
|
|
|
+ virtual IStreamingReporter* create( ReporterConfig const& config ) const {
|
|
|
+ return new T( config );
|
|
|
+ }
|
|
|
+ virtual std::string getDescription() const {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ public:
|
|
|
+
|
|
|
+ ListenerRegistrar() {
|
|
|
+ getMutableRegistryHub().registerListener( new ListenerFactory() );
|
|
|
+ }
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
|
|
|
namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
|
|
|
+
|
|
|
#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
|
|
|
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
|
|
|
|
|
|
+#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
|
|
|
+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
|
|
|
+
|
|
|
// #included from: ../internal/catch_xmlwriter.hpp
|
|
|
#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
|
|
|
|
|
|
#include <sstream>
|
|
|
-#include <iostream>
|
|
|
#include <string>
|
|
|
#include <vector>
|
|
|
+#include <iomanip>
|
|
|
|
|
|
namespace Catch {
|
|
|
|
|
|
+ class XmlEncode {
|
|
|
+ public:
|
|
|
+ enum ForWhat { ForTextNodes, ForAttributes };
|
|
|
+
|
|
|
+ XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes )
|
|
|
+ : m_str( str ),
|
|
|
+ m_forWhat( forWhat )
|
|
|
+ {}
|
|
|
+
|
|
|
+ void encodeTo( std::ostream& os ) const {
|
|
|
+
|
|
|
+ // Apostrophe escaping not necessary if we always use " to write attributes
|
|
|
+ // (see: http://www.w3.org/TR/xml/#syntax)
|
|
|
+
|
|
|
+ for( std::size_t i = 0; i < m_str.size(); ++ i ) {
|
|
|
+ char c = m_str[i];
|
|
|
+ switch( c ) {
|
|
|
+ case '<': os << "<"; break;
|
|
|
+ case '&': os << "&"; break;
|
|
|
+
|
|
|
+ case '>':
|
|
|
+ // See: http://www.w3.org/TR/xml/#syntax
|
|
|
+ if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
|
|
|
+ os << ">";
|
|
|
+ else
|
|
|
+ os << c;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case '\"':
|
|
|
+ if( m_forWhat == ForAttributes )
|
|
|
+ os << """;
|
|
|
+ else
|
|
|
+ os << c;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ // Escape control chars - based on contribution by @espenalb in PR #465 and
|
|
|
+ // by @mrpi PR #588
|
|
|
+ if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
|
|
|
+ os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
|
|
|
+ else
|
|
|
+ os << c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
|
|
|
+ xmlEncode.encodeTo( os );
|
|
|
+ return os;
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ std::string m_str;
|
|
|
+ ForWhat m_forWhat;
|
|
|
+ };
|
|
|
+
|
|
|
class XmlWriter {
|
|
|
public:
|
|
|
|
|
@@ -7481,7 +8989,7 @@ namespace Catch {
|
|
|
|
|
|
ScopedElement( ScopedElement const& other )
|
|
|
: m_writer( other.m_writer ){
|
|
|
- other.m_writer = NULL;
|
|
|
+ other.m_writer = CATCH_NULL;
|
|
|
}
|
|
|
|
|
|
~ScopedElement() {
|
|
@@ -7507,41 +9015,27 @@ namespace Catch {
|
|
|
XmlWriter()
|
|
|
: m_tagIsOpen( false ),
|
|
|
m_needsNewline( false ),
|
|
|
- m_os( &std::cout )
|
|
|
- {}
|
|
|
+ m_os( &Catch::cout() )
|
|
|
+ {
|
|
|
+ // We encode control characters, which requires
|
|
|
+ // XML 1.1
|
|
|
+ // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
|
|
+ *m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
|
|
|
+ }
|
|
|
|
|
|
XmlWriter( std::ostream& os )
|
|
|
: m_tagIsOpen( false ),
|
|
|
m_needsNewline( false ),
|
|
|
m_os( &os )
|
|
|
- {}
|
|
|
+ {
|
|
|
+ *m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
|
|
|
+ }
|
|
|
|
|
|
~XmlWriter() {
|
|
|
while( !m_tags.empty() )
|
|
|
endElement();
|
|
|
}
|
|
|
|
|
|
-//# ifndef CATCH_CPP11_OR_GREATER
|
|
|
-// XmlWriter& operator = ( XmlWriter const& other ) {
|
|
|
-// XmlWriter temp( other );
|
|
|
-// swap( temp );
|
|
|
-// return *this;
|
|
|
-// }
|
|
|
-//# else
|
|
|
-// XmlWriter( XmlWriter const& ) = default;
|
|
|
-// XmlWriter( XmlWriter && ) = default;
|
|
|
-// XmlWriter& operator = ( XmlWriter const& ) = default;
|
|
|
-// XmlWriter& operator = ( XmlWriter && ) = default;
|
|
|
-//# endif
|
|
|
-//
|
|
|
-// void swap( XmlWriter& other ) {
|
|
|
-// std::swap( m_tagIsOpen, other.m_tagIsOpen );
|
|
|
-// std::swap( m_needsNewline, other.m_needsNewline );
|
|
|
-// std::swap( m_tags, other.m_tags );
|
|
|
-// std::swap( m_indent, other.m_indent );
|
|
|
-// std::swap( m_os, other.m_os );
|
|
|
-// }
|
|
|
-
|
|
|
XmlWriter& startElement( std::string const& name ) {
|
|
|
ensureTagClosed();
|
|
|
newlineIfNecessary();
|
|
@@ -7573,11 +9067,8 @@ namespace Catch {
|
|
|
}
|
|
|
|
|
|
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
|
|
|
- if( !name.empty() && !attribute.empty() ) {
|
|
|
- stream() << " " << name << "=\"";
|
|
|
- writeEncodedText( attribute );
|
|
|
- stream() << "\"";
|
|
|
- }
|
|
|
+ if( !name.empty() && !attribute.empty() )
|
|
|
+ stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\"";
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
@@ -7588,9 +9079,9 @@ namespace Catch {
|
|
|
|
|
|
template<typename T>
|
|
|
XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
|
|
|
- if( !name.empty() )
|
|
|
- stream() << " " << name << "=\"" << attribute << "\"";
|
|
|
- return *this;
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << attribute;
|
|
|
+ return writeAttribute( name, oss.str() );
|
|
|
}
|
|
|
|
|
|
XmlWriter& writeText( std::string const& text, bool indent = true ) {
|
|
@@ -7599,7 +9090,7 @@ namespace Catch {
|
|
|
ensureTagClosed();
|
|
|
if( tagWasOpen && indent )
|
|
|
stream() << m_indent;
|
|
|
- writeEncodedText( text );
|
|
|
+ stream() << XmlEncode( text );
|
|
|
m_needsNewline = true;
|
|
|
}
|
|
|
return *this;
|
|
@@ -7644,30 +9135,6 @@ namespace Catch {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- void writeEncodedText( std::string const& text ) {
|
|
|
- static const char* charsToEncode = "<&\"";
|
|
|
- std::string mtext = text;
|
|
|
- std::string::size_type pos = mtext.find_first_of( charsToEncode );
|
|
|
- while( pos != std::string::npos ) {
|
|
|
- stream() << mtext.substr( 0, pos );
|
|
|
-
|
|
|
- switch( mtext[pos] ) {
|
|
|
- case '<':
|
|
|
- stream() << "<";
|
|
|
- break;
|
|
|
- case '&':
|
|
|
- stream() << "&";
|
|
|
- break;
|
|
|
- case '\"':
|
|
|
- stream() << """;
|
|
|
- break;
|
|
|
- }
|
|
|
- mtext = mtext.substr( pos+1 );
|
|
|
- pos = mtext.find_first_of( charsToEncode );
|
|
|
- }
|
|
|
- stream() << mtext;
|
|
|
- }
|
|
|
-
|
|
|
bool m_tagIsOpen;
|
|
|
bool m_needsNewline;
|
|
|
std::vector<std::string> m_tags;
|
|
@@ -7676,82 +9143,103 @@ namespace Catch {
|
|
|
};
|
|
|
|
|
|
}
|
|
|
+// #included from: catch_reenable_warnings.h
|
|
|
+
|
|
|
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
|
|
|
+
|
|
|
+#ifdef __clang__
|
|
|
+# ifdef __ICC // icpc defines the __clang__ macro
|
|
|
+# pragma warning(pop)
|
|
|
+# else
|
|
|
+# pragma clang diagnostic pop
|
|
|
+# endif
|
|
|
+#elif defined __GNUC__
|
|
|
+# pragma GCC diagnostic pop
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
namespace Catch {
|
|
|
- class XmlReporter : public SharedImpl<IReporter> {
|
|
|
+ class XmlReporter : public StreamingReporterBase {
|
|
|
public:
|
|
|
- XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {}
|
|
|
+ XmlReporter( ReporterConfig const& _config )
|
|
|
+ : StreamingReporterBase( _config ),
|
|
|
+ m_sectionDepth( 0 )
|
|
|
+ {
|
|
|
+ m_reporterPrefs.shouldRedirectStdOut = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual ~XmlReporter() CATCH_OVERRIDE;
|
|
|
|
|
|
static std::string getDescription() {
|
|
|
return "Reports test results as an XML document";
|
|
|
}
|
|
|
- virtual ~XmlReporter();
|
|
|
|
|
|
- private: // IReporter
|
|
|
+ public: // StreamingReporterBase
|
|
|
|
|
|
- virtual bool shouldRedirectStdout() const {
|
|
|
- return true;
|
|
|
+ virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::noMatchingTestCases( s );
|
|
|
}
|
|
|
|
|
|
- virtual void StartTesting() {
|
|
|
- m_xml.setStream( m_config.stream() );
|
|
|
+ virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::testRunStarting( testInfo );
|
|
|
+ m_xml.setStream( stream );
|
|
|
m_xml.startElement( "Catch" );
|
|
|
- if( !m_config.fullConfig()->name().empty() )
|
|
|
- m_xml.writeAttribute( "name", m_config.fullConfig()->name() );
|
|
|
- }
|
|
|
-
|
|
|
- virtual void EndTesting( const Totals& totals ) {
|
|
|
- m_xml.scopedElement( "OverallResults" )
|
|
|
- .writeAttribute( "successes", totals.assertions.passed )
|
|
|
- .writeAttribute( "failures", totals.assertions.failed )
|
|
|
- .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
|
|
|
- m_xml.endElement();
|
|
|
+ if( !m_config->name().empty() )
|
|
|
+ m_xml.writeAttribute( "name", m_config->name() );
|
|
|
}
|
|
|
|
|
|
- virtual void StartGroup( const std::string& groupName ) {
|
|
|
+ virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::testGroupStarting( groupInfo );
|
|
|
m_xml.startElement( "Group" )
|
|
|
- .writeAttribute( "name", groupName );
|
|
|
+ .writeAttribute( "name", groupInfo.name );
|
|
|
}
|
|
|
|
|
|
- virtual void EndGroup( const std::string&, const Totals& totals ) {
|
|
|
- m_xml.scopedElement( "OverallResults" )
|
|
|
- .writeAttribute( "successes", totals.assertions.passed )
|
|
|
- .writeAttribute( "failures", totals.assertions.failed )
|
|
|
- .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
|
|
|
- m_xml.endElement();
|
|
|
+ virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::testCaseStarting(testInfo);
|
|
|
+ m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name );
|
|
|
+
|
|
|
+ if ( m_config->showDurations() == ShowDurations::Always )
|
|
|
+ m_testCaseTimer.start();
|
|
|
}
|
|
|
|
|
|
- virtual void StartSection( const std::string& sectionName, const std::string& description ) {
|
|
|
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::sectionStarting( sectionInfo );
|
|
|
if( m_sectionDepth++ > 0 ) {
|
|
|
m_xml.startElement( "Section" )
|
|
|
- .writeAttribute( "name", trim( sectionName ) )
|
|
|
- .writeAttribute( "description", description );
|
|
|
+ .writeAttribute( "name", trim( sectionInfo.name ) )
|
|
|
+ .writeAttribute( "description", sectionInfo.description );
|
|
|
}
|
|
|
}
|
|
|
- virtual void NoAssertionsInSection( const std::string& ) {}
|
|
|
- virtual void NoAssertionsInTestCase( const std::string& ) {}
|
|
|
|
|
|
- virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
|
|
|
- if( --m_sectionDepth > 0 ) {
|
|
|
- m_xml.scopedElement( "OverallResults" )
|
|
|
- .writeAttribute( "successes", assertions.passed )
|
|
|
- .writeAttribute( "failures", assertions.failed )
|
|
|
- .writeAttribute( "expectedFailures", assertions.failedButOk );
|
|
|
- m_xml.endElement();
|
|
|
- }
|
|
|
- }
|
|
|
+ virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { }
|
|
|
|
|
|
- virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
|
|
|
- m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
|
|
|
- m_currentTestSuccess = true;
|
|
|
- }
|
|
|
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
|
|
|
+ const AssertionResult& assertionResult = assertionStats.assertionResult;
|
|
|
|
|
|
- virtual void Result( const Catch::AssertionResult& assertionResult ) {
|
|
|
- if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok )
|
|
|
- return;
|
|
|
+ // Print any info messages in <Info> tags.
|
|
|
+ if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
|
|
|
+ for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
|
|
|
+ it != itEnd;
|
|
|
+ ++it ) {
|
|
|
+ if( it->type == ResultWas::Info ) {
|
|
|
+ m_xml.scopedElement( "Info" )
|
|
|
+ .writeText( it->message );
|
|
|
+ } else if ( it->type == ResultWas::Warning ) {
|
|
|
+ m_xml.scopedElement( "Warning" )
|
|
|
+ .writeText( it->message );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Drop out if result was successful but we're not printing them.
|
|
|
+ if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) )
|
|
|
+ return true;
|
|
|
|
|
|
+ // Print the expression if there is one.
|
|
|
if( assertionResult.hasExpression() ) {
|
|
|
m_xml.startElement( "Expression" )
|
|
|
.writeAttribute( "success", assertionResult.succeeded() )
|
|
|
+ .writeAttribute( "type", assertionResult.getTestMacroName() )
|
|
|
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
|
|
.writeAttribute( "line", assertionResult.getSourceInfo().line );
|
|
|
|
|
@@ -7759,58 +9247,96 @@ namespace Catch {
|
|
|
.writeText( assertionResult.getExpression() );
|
|
|
m_xml.scopedElement( "Expanded" )
|
|
|
.writeText( assertionResult.getExpandedExpression() );
|
|
|
- m_currentTestSuccess &= assertionResult.succeeded();
|
|
|
}
|
|
|
|
|
|
+ // And... Print a result applicable to each result type.
|
|
|
switch( assertionResult.getResultType() ) {
|
|
|
case ResultWas::ThrewException:
|
|
|
m_xml.scopedElement( "Exception" )
|
|
|
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
|
|
.writeAttribute( "line", assertionResult.getSourceInfo().line )
|
|
|
.writeText( assertionResult.getMessage() );
|
|
|
- m_currentTestSuccess = false;
|
|
|
+ break;
|
|
|
+ case ResultWas::FatalErrorCondition:
|
|
|
+ m_xml.scopedElement( "Fatal Error Condition" )
|
|
|
+ .writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
|
|
+ .writeAttribute( "line", assertionResult.getSourceInfo().line )
|
|
|
+ .writeText( assertionResult.getMessage() );
|
|
|
break;
|
|
|
case ResultWas::Info:
|
|
|
m_xml.scopedElement( "Info" )
|
|
|
.writeText( assertionResult.getMessage() );
|
|
|
break;
|
|
|
case ResultWas::Warning:
|
|
|
- m_xml.scopedElement( "Warning" )
|
|
|
- .writeText( assertionResult.getMessage() );
|
|
|
+ // Warning will already have been written
|
|
|
break;
|
|
|
case ResultWas::ExplicitFailure:
|
|
|
m_xml.scopedElement( "Failure" )
|
|
|
.writeText( assertionResult.getMessage() );
|
|
|
- m_currentTestSuccess = false;
|
|
|
break;
|
|
|
- case ResultWas::Unknown:
|
|
|
- case ResultWas::Ok:
|
|
|
- case ResultWas::FailureBit:
|
|
|
- case ResultWas::ExpressionFailed:
|
|
|
- case ResultWas::Exception:
|
|
|
- case ResultWas::DidntThrowException:
|
|
|
+ default:
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
if( assertionResult.hasExpression() )
|
|
|
m_xml.endElement();
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::sectionEnded( sectionStats );
|
|
|
+ if( --m_sectionDepth > 0 ) {
|
|
|
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
|
|
|
+ e.writeAttribute( "successes", sectionStats.assertions.passed );
|
|
|
+ e.writeAttribute( "failures", sectionStats.assertions.failed );
|
|
|
+ e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
|
|
|
+
|
|
|
+ if ( m_config->showDurations() == ShowDurations::Always )
|
|
|
+ e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
|
|
|
+
|
|
|
+ m_xml.endElement();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::testCaseEnded( testCaseStats );
|
|
|
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
|
|
|
+ e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
|
|
|
+
|
|
|
+ if ( m_config->showDurations() == ShowDurations::Always )
|
|
|
+ e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
|
|
|
+
|
|
|
+ m_xml.endElement();
|
|
|
}
|
|
|
|
|
|
- virtual void Aborted() {
|
|
|
- // !TBD
|
|
|
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::testGroupEnded( testGroupStats );
|
|
|
+ // TODO: Check testGroupStats.aborting and act accordingly.
|
|
|
+ m_xml.scopedElement( "OverallResults" )
|
|
|
+ .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
|
|
|
+ .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
|
|
|
+ .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
|
|
|
+ m_xml.endElement();
|
|
|
}
|
|
|
|
|
|
- virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
|
|
|
- m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
|
|
|
+ virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
|
|
|
+ StreamingReporterBase::testRunEnded( testRunStats );
|
|
|
+ m_xml.scopedElement( "OverallResults" )
|
|
|
+ .writeAttribute( "successes", testRunStats.totals.assertions.passed )
|
|
|
+ .writeAttribute( "failures", testRunStats.totals.assertions.failed )
|
|
|
+ .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
|
|
|
m_xml.endElement();
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
- ReporterConfig m_config;
|
|
|
- bool m_currentTestSuccess;
|
|
|
+ Timer m_testCaseTimer;
|
|
|
XmlWriter m_xml;
|
|
|
int m_sectionDepth;
|
|
|
};
|
|
|
|
|
|
+ INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
|
|
|
+
|
|
|
} // end namespace Catch
|
|
|
|
|
|
// #included from: ../reporters/catch_reporter_junit.hpp
|
|
@@ -7825,28 +9351,24 @@ namespace Catch {
|
|
|
JunitReporter( ReporterConfig const& _config )
|
|
|
: CumulativeReporterBase( _config ),
|
|
|
xml( _config.stream() )
|
|
|
- {}
|
|
|
+ {
|
|
|
+ m_reporterPrefs.shouldRedirectStdOut = true;
|
|
|
+ }
|
|
|
|
|
|
- ~JunitReporter();
|
|
|
+ virtual ~JunitReporter() CATCH_OVERRIDE;
|
|
|
|
|
|
static std::string getDescription() {
|
|
|
return "Reports test results in an XML format that looks like Ant's junitreport target";
|
|
|
}
|
|
|
|
|
|
- virtual void noMatchingTestCases( std::string const& /*spec*/ ) {}
|
|
|
-
|
|
|
- virtual ReporterPreferences getPreferences() const {
|
|
|
- ReporterPreferences prefs;
|
|
|
- prefs.shouldRedirectStdOut = true;
|
|
|
- return prefs;
|
|
|
- }
|
|
|
+ virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {}
|
|
|
|
|
|
- virtual void testRunStarting( TestRunInfo const& runInfo ) {
|
|
|
+ virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE {
|
|
|
CumulativeReporterBase::testRunStarting( runInfo );
|
|
|
xml.startElement( "testsuites" );
|
|
|
}
|
|
|
|
|
|
- virtual void testGroupStarting( GroupInfo const& groupInfo ) {
|
|
|
+ virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
|
|
|
suiteTimer.start();
|
|
|
stdOutForSuite.str("");
|
|
|
stdErrForSuite.str("");
|
|
@@ -7854,25 +9376,25 @@ namespace Catch {
|
|
|
CumulativeReporterBase::testGroupStarting( groupInfo );
|
|
|
}
|
|
|
|
|
|
- virtual bool assertionEnded( AssertionStats const& assertionStats ) {
|
|
|
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
|
|
|
if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
|
|
|
unexpectedExceptions++;
|
|
|
return CumulativeReporterBase::assertionEnded( assertionStats );
|
|
|
}
|
|
|
|
|
|
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
|
|
|
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
|
|
|
stdOutForSuite << testCaseStats.stdOut;
|
|
|
stdErrForSuite << testCaseStats.stdErr;
|
|
|
CumulativeReporterBase::testCaseEnded( testCaseStats );
|
|
|
}
|
|
|
|
|
|
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
|
|
|
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
|
|
|
double suiteTime = suiteTimer.getElapsedSeconds();
|
|
|
CumulativeReporterBase::testGroupEnded( testGroupStats );
|
|
|
writeGroup( *m_testGroups.back(), suiteTime );
|
|
|
}
|
|
|
|
|
|
- virtual void testRunEndedCumulative() {
|
|
|
+ virtual void testRunEndedCumulative() CATCH_OVERRIDE {
|
|
|
xml.endElement();
|
|
|
}
|
|
|
|
|
@@ -7937,7 +9459,7 @@ namespace Catch {
|
|
|
xml.writeAttribute( "classname", className );
|
|
|
xml.writeAttribute( "name", name );
|
|
|
}
|
|
|
- xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) );
|
|
|
+ xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
|
|
|
|
|
|
writeAssertions( sectionNode );
|
|
|
|
|
@@ -7970,6 +9492,7 @@ namespace Catch {
|
|
|
std::string elementName;
|
|
|
switch( result.getResultType() ) {
|
|
|
case ResultWas::ThrewException:
|
|
|
+ case ResultWas::FatalErrorCondition:
|
|
|
elementName = "error";
|
|
|
break;
|
|
|
case ResultWas::ExplicitFailure:
|
|
@@ -8028,8 +9551,6 @@ namespace Catch {
|
|
|
// #included from: ../reporters/catch_reporter_console.hpp
|
|
|
#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
|
|
|
|
|
|
-#include <cstring>
|
|
|
-
|
|
|
namespace Catch {
|
|
|
|
|
|
struct ConsoleReporter : StreamingReporterBase {
|
|
@@ -8038,24 +9559,19 @@ namespace Catch {
|
|
|
m_headerPrinted( false )
|
|
|
{}
|
|
|
|
|
|
- virtual ~ConsoleReporter();
|
|
|
+ virtual ~ConsoleReporter() CATCH_OVERRIDE;
|
|
|
static std::string getDescription() {
|
|
|
return "Reports test results as plain lines of text";
|
|
|
}
|
|
|
- virtual ReporterPreferences getPreferences() const {
|
|
|
- ReporterPreferences prefs;
|
|
|
- prefs.shouldRedirectStdOut = false;
|
|
|
- return prefs;
|
|
|
- }
|
|
|
|
|
|
- virtual void noMatchingTestCases( std::string const& spec ) {
|
|
|
+ virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
|
|
|
stream << "No test cases matched '" << spec << "'" << std::endl;
|
|
|
}
|
|
|
|
|
|
- virtual void assertionStarting( AssertionInfo const& ) {
|
|
|
+ virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
|
|
|
}
|
|
|
|
|
|
- virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
|
|
|
+ virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE {
|
|
|
AssertionResult const& result = _assertionStats.assertionResult;
|
|
|
|
|
|
bool printInfoMessages = true;
|
|
@@ -8075,11 +9591,11 @@ namespace Catch {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
|
|
|
+ virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
|
|
|
m_headerPrinted = false;
|
|
|
StreamingReporterBase::sectionStarting( _sectionInfo );
|
|
|
}
|
|
|
- virtual void sectionEnded( SectionStats const& _sectionStats ) {
|
|
|
+ virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE {
|
|
|
if( _sectionStats.missingAssertions ) {
|
|
|
lazyPrint();
|
|
|
Colour colour( Colour::ResultError );
|
|
@@ -8101,11 +9617,11 @@ namespace Catch {
|
|
|
StreamingReporterBase::sectionEnded( _sectionStats );
|
|
|
}
|
|
|
|
|
|
- virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) {
|
|
|
+ virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE {
|
|
|
StreamingReporterBase::testCaseEnded( _testCaseStats );
|
|
|
m_headerPrinted = false;
|
|
|
}
|
|
|
- virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
|
|
|
+ virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE {
|
|
|
if( currentGroupInfo.used ) {
|
|
|
printSummaryDivider();
|
|
|
stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
|
|
@@ -8114,7 +9630,7 @@ namespace Catch {
|
|
|
}
|
|
|
StreamingReporterBase::testGroupEnded( _testGroupStats );
|
|
|
}
|
|
|
- virtual void testRunEnded( TestRunStats const& _testRunStats ) {
|
|
|
+ virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE {
|
|
|
printTotalsDivider( _testRunStats.totals );
|
|
|
printTotals( _testRunStats.totals );
|
|
|
stream << std::endl;
|
|
@@ -8164,6 +9680,11 @@ namespace Catch {
|
|
|
passOrFail = "FAILED";
|
|
|
messageLabel = "due to unexpected exception with message";
|
|
|
break;
|
|
|
+ case ResultWas::FatalErrorCondition:
|
|
|
+ colour = Colour::Error;
|
|
|
+ passOrFail = "FAILED";
|
|
|
+ messageLabel = "due to a fatal error condition";
|
|
|
+ break;
|
|
|
case ResultWas::DidntThrowException:
|
|
|
colour = Colour::Error;
|
|
|
passOrFail = "FAILED";
|
|
@@ -8273,14 +9794,12 @@ namespace Catch {
|
|
|
stream << "\n" << getLineOfChars<'~'>() << "\n";
|
|
|
Colour colour( Colour::SecondaryText );
|
|
|
stream << currentTestRunInfo->name
|
|
|
- << " is a Catch v" << libraryVersion.majorVersion << "."
|
|
|
- << libraryVersion.minorVersion << " b"
|
|
|
- << libraryVersion.buildNumber;
|
|
|
- if( libraryVersion.branchName != std::string( "master" ) )
|
|
|
- stream << " (" << libraryVersion.branchName << ")";
|
|
|
- stream << " host application.\n"
|
|
|
+ << " is a Catch v" << libraryVersion << " host application.\n"
|
|
|
<< "Run with -? for options\n\n";
|
|
|
|
|
|
+ if( m_config->rngSeed() != 0 )
|
|
|
+ stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
|
|
|
+
|
|
|
currentTestRunInfo.used = true;
|
|
|
}
|
|
|
void lazyPrintGroupInfo() {
|
|
@@ -8368,7 +9887,7 @@ namespace Catch {
|
|
|
if( totals.testCases.total() == 0 ) {
|
|
|
stream << Colour( Colour::Warning ) << "No tests ran\n";
|
|
|
}
|
|
|
- else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) {
|
|
|
+ else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
|
|
|
stream << Colour( Colour::ResultSuccess ) << "All tests passed";
|
|
|
stream << " ("
|
|
|
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
|
|
@@ -8452,15 +9971,6 @@ namespace Catch {
|
|
|
void printSummaryDivider() {
|
|
|
stream << getLineOfChars<'-'>() << "\n";
|
|
|
}
|
|
|
- template<char C>
|
|
|
- static char const* getLineOfChars() {
|
|
|
- static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
|
|
|
- if( !*line ) {
|
|
|
- memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
|
|
|
- line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
|
|
|
- }
|
|
|
- return line;
|
|
|
- }
|
|
|
|
|
|
private:
|
|
|
bool m_headerPrinted;
|
|
@@ -8569,6 +10079,13 @@ namespace Catch {
|
|
|
printExpressionWas();
|
|
|
printRemainingMessages();
|
|
|
break;
|
|
|
+ case ResultWas::FatalErrorCondition:
|
|
|
+ printResultType( Colour::Error, failedString() );
|
|
|
+ printIssue( "fatal error condition with message:" );
|
|
|
+ printMessage();
|
|
|
+ printExpressionWas();
|
|
|
+ printRemainingMessages();
|
|
|
+ break;
|
|
|
case ResultWas::DidntThrowException:
|
|
|
printResultType( Colour::Error, failedString() );
|
|
|
printIssue( "expected exception, got none" );
|
|
@@ -8752,8 +10269,14 @@ namespace Catch {
|
|
|
} // end namespace Catch
|
|
|
|
|
|
namespace Catch {
|
|
|
+ // These are all here to avoid warnings about not having any out of line
|
|
|
+ // virtual methods
|
|
|
NonCopyable::~NonCopyable() {}
|
|
|
IShared::~IShared() {}
|
|
|
+ IStream::~IStream() CATCH_NOEXCEPT {}
|
|
|
+ FileStream::~FileStream() CATCH_NOEXCEPT {}
|
|
|
+ CoutStream::~CoutStream() CATCH_NOEXCEPT {}
|
|
|
+ DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
|
|
|
StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
|
|
|
IContext::~IContext() {}
|
|
|
IResultCapture::~IResultCapture() {}
|
|
@@ -8787,6 +10310,7 @@ namespace Catch {
|
|
|
FreeFunctionTestCase::~FreeFunctionTestCase() {}
|
|
|
IGeneratorInfo::~IGeneratorInfo() {}
|
|
|
IGeneratorsForTest::~IGeneratorsForTest() {}
|
|
|
+ WildcardPattern::~WildcardPattern() {}
|
|
|
TestSpec::Pattern::~Pattern() {}
|
|
|
TestSpec::NamePattern::~NamePattern() {}
|
|
|
TestSpec::TagPattern::~TagPattern() {}
|
|
@@ -8799,7 +10323,12 @@ namespace Catch {
|
|
|
|
|
|
void Config::dummy() {}
|
|
|
|
|
|
- INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
|
|
|
+ namespace TestCaseTracking {
|
|
|
+ ITracker::~ITracker() {}
|
|
|
+ TrackerBase::~TrackerBase() {}
|
|
|
+ SectionTracker::~SectionTracker() {}
|
|
|
+ IndexTracker::~IndexTracker() {}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#ifdef __clang__
|
|
@@ -8815,7 +10344,7 @@ namespace Catch {
|
|
|
#ifndef __OBJC__
|
|
|
|
|
|
// Standard C/C++ main entry point
|
|
|
-int main (int argc, char * const argv[]) {
|
|
|
+int main (int argc, char * argv[]) {
|
|
|
return Catch::Session().run( argc, argv );
|
|
|
}
|
|
|
|
|
@@ -8853,8 +10382,9 @@ int main (int argc, char * const argv[]) {
|
|
|
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
|
|
|
#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
|
|
|
|
|
|
-#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" )
|
|
|
+#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" )
|
|
|
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
|
|
|
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" )
|
|
|
#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
|
|
|
|
|
|
#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
|
|
@@ -8865,6 +10395,7 @@ int main (int argc, char * const argv[]) {
|
|
|
|
|
|
#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
|
|
|
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
|
|
|
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" )
|
|
|
#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
|
|
|
|
|
|
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
|
|
@@ -8880,6 +10411,7 @@ int main (int argc, char * const argv[]) {
|
|
|
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
|
|
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
|
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
|
|
+ #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
|
|
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
|
|
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
|
|
|
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
|
|
@@ -8887,6 +10419,7 @@ int main (int argc, char * const argv[]) {
|
|
|
#define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
|
|
|
#define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
|
|
|
#define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
|
|
|
+ #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
|
|
|
#define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
|
|
|
#define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
|
|
|
#define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
|
|
@@ -8906,11 +10439,11 @@ int main (int argc, char * const argv[]) {
|
|
|
#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
|
|
|
#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
|
|
|
#endif
|
|
|
-#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" )
|
|
|
-#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" )
|
|
|
-#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" )
|
|
|
-#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" )
|
|
|
-#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" )
|
|
|
+#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" )
|
|
|
+#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" )
|
|
|
+#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
|
|
|
+#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" )
|
|
|
+#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
|
|
|
|
|
|
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
|
|
#else
|
|
@@ -8918,8 +10451,9 @@ int main (int argc, char * const argv[]) {
|
|
|
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
|
|
|
#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
|
|
|
|
|
|
-#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" )
|
|
|
+#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" )
|
|
|
#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
|
|
|
+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" )
|
|
|
#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
|
|
|
|
|
|
#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
|
|
@@ -8928,8 +10462,9 @@ int main (int argc, char * const argv[]) {
|
|
|
#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
|
|
|
#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
|
|
|
|
|
|
-#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" )
|
|
|
+#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" )
|
|
|
#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
|
|
|
+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" )
|
|
|
#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
|
|
|
|
|
|
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
|
|
@@ -8945,6 +10480,7 @@ int main (int argc, char * const argv[]) {
|
|
|
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
|
|
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
|
|
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
|
|
+ #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
|
|
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
|
|
#define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
|
|
|
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
|
|
@@ -8952,6 +10488,7 @@ int main (int argc, char * const argv[]) {
|
|
|
#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
|
|
|
#define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
|
|
|
#define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
|
|
|
+ #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
|
|
|
#define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
|
|
|
#define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
|
|
|
#define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
|
|
@@ -8975,23 +10512,13 @@ int main (int argc, char * const argv[]) {
|
|
|
#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
|
|
|
#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
|
|
|
#endif
|
|
|
-#define GIVEN( desc ) SECTION( " Given: " desc, "" )
|
|
|
-#define WHEN( desc ) SECTION( " When: " desc, "" )
|
|
|
-#define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
|
|
|
-#define THEN( desc ) SECTION( " Then: " desc, "" )
|
|
|
-#define AND_THEN( desc ) SECTION( " And: " desc, "" )
|
|
|
+#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" )
|
|
|
+#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" )
|
|
|
+#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" )
|
|
|
+#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" )
|
|
|
+#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" )
|
|
|
|
|
|
using Catch::Detail::Approx;
|
|
|
|
|
|
-// #included from: internal/catch_reenable_warnings.h
|
|
|
-
|
|
|
-#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
|
|
|
-
|
|
|
-#ifdef __clang__
|
|
|
-#pragma clang diagnostic pop
|
|
|
-#elif defined __GNUC__
|
|
|
-#pragma GCC diagnostic pop
|
|
|
-#endif
|
|
|
-
|
|
|
#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
|
|
|
|