aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Paland <marco@paland.com>2019-03-26 08:46:44 +0100
committerMarco Paland <marco@paland.com>2019-03-26 08:46:44 +0100
commit4012b45d7c3cca5b42507c77e3033322b5dfab3d (patch)
treeb4ef1a75a1c02328e33630812cc61f9308c0ecb6
parentb20ddfb40f7a2f8ab312078698211186d80d6e1a (diff)
downloadprintf-4012b45d7c3cca5b42507c77e3033322b5dfab3d.tar.gz
printf-4012b45d7c3cca5b42507c77e3033322b5dfab3d.tar.bz2
printf-4012b45d7c3cca5b42507c77e3033322b5dfab3d.zip
chore(catch): update to catch2 2.7.0
-rw-r--r--test/catch.hpp1801
1 files changed, 1330 insertions, 471 deletions
diff --git a/test/catch.hpp b/test/catch.hpp
index b324e56..1850fff 100644
--- a/test/catch.hpp
+++ b/test/catch.hpp
@@ -1,9 +1,9 @@
/*
- * Catch v2.4.2
- * Generated: 2018-10-26 21:12:29.223927
+ * Catch v2.7.0
+ * Generated: 2019-03-07 21:34:30.252164
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
- * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
+ * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -14,8 +14,8 @@
#define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 4
-#define CATCH_VERSION_PATCH 2
+#define CATCH_VERSION_MINOR 7
+#define CATCH_VERSION_PATCH 0
#ifdef __clang__
# pragma clang system_header
@@ -36,10 +36,11 @@
# pragma clang diagnostic ignored "-Wcovered-switch-default"
# endif
#elif defined __GNUC__
- // GCC likes to warn on REQUIREs, and we cannot suppress them
- // locally because g++'s support for _Pragma is lacking in older,
- // still supported, versions
-# pragma GCC diagnostic ignored "-Wparentheses"
+ // Because REQUIREs trigger GCC's -Wparentheses, and because still
+ // supported version of g++ have only buggy support for _Pragmas,
+ // Wparentheses have to be suppressed globally.
+# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details
+
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-variable"
# pragma GCC diagnostic ignored "-Wpadded"
@@ -226,6 +227,13 @@ namespace Catch {
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
# endif
+// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
+// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
+// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
+# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
+# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+# endif
+
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
@@ -241,6 +249,12 @@ namespace Catch {
#endif // __DJGPP__
////////////////////////////////////////////////////////////////////////////////
+// Embarcadero C++Build
+#if defined(__BORLANDC__)
+ #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
// Use of __COUNTER__ is suppressed during code analysis in
// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
@@ -261,6 +275,14 @@ namespace Catch {
#endif
////////////////////////////////////////////////////////////////////////////////
+// Check if optional is available and usable
+#if defined(__has_include)
+# if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // __has_include
+
+////////////////////////////////////////////////////////////////////////////////
// Check if variant is available and usable
#if defined(__has_include)
# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
@@ -270,9 +292,11 @@ namespace Catch {
# include <ciso646>
# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
# define CATCH_CONFIG_NO_CPP17_VARIANT
-# else
+# else
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+# else
+# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
# endif // defined(__clang__) && (__clang_major__ < 8)
# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
@@ -296,6 +320,10 @@ namespace Catch {
# define CATCH_CONFIG_CPP11_TO_STRING
#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
+# define CATCH_CONFIG_CPP17_OPTIONAL
+#endif
+
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
@@ -320,6 +348,10 @@ namespace Catch {
# define CATCH_CONFIG_DISABLE_EXCEPTIONS
#endif
+#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)
+# define CATCH_CONFIG_POLYFILL_ISNAN
+#endif
+
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
@@ -343,6 +375,10 @@ namespace Catch {
#define CATCH_CATCH_ANON(type) catch (type)
#endif
+#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)
+#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#endif
+
// end catch_compiler_capabilities.h
#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 )
@@ -386,10 +422,10 @@ namespace Catch {
line( _line )
{}
- SourceLineInfo( SourceLineInfo const& other ) = default;
- SourceLineInfo( SourceLineInfo && ) = default;
- SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
- SourceLineInfo& operator = ( SourceLineInfo && ) = default;
+ SourceLineInfo( SourceLineInfo const& other ) = default;
+ SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+ SourceLineInfo( SourceLineInfo&& ) noexcept = default;
+ SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
bool empty() const noexcept;
bool operator == ( SourceLineInfo const& other ) const noexcept;
@@ -442,7 +478,6 @@ namespace Catch {
// start catch_interfaces_testcase.h
#include <vector>
-#include <memory>
namespace Catch {
@@ -453,8 +488,6 @@ namespace Catch {
virtual ~ITestInvoker();
};
- using ITestCasePtr = std::shared_ptr<ITestInvoker>;
-
class TestCase;
struct IConfig;
@@ -479,8 +512,6 @@ namespace Catch {
namespace Catch {
- class StringData;
-
/// A non-owning string class (similar to the forthcoming std::string_view)
/// Note that, because a StringRef may be a substring of another string,
/// it may not be null terminated. c_str() must return a null terminated
@@ -597,6 +628,188 @@ inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noex
}
// end catch_stringref.h
+// start catch_type_traits.hpp
+
+
+#include <type_traits>
+
+namespace Catch{
+
+#ifdef CATCH_CPP17_OR_GREATER
+ template <typename...>
+ inline constexpr auto is_unique = std::true_type{};
+
+ template <typename T, typename... Rest>
+ inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
+ (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
+ >{};
+#else
+
+template <typename...>
+struct is_unique : std::true_type{};
+
+template <typename T0, typename T1, typename... Rest>
+struct is_unique<T0, T1, Rest...> : std::integral_constant
+<bool,
+ !std::is_same<T0, T1>::value
+ && is_unique<T0, Rest...>::value
+ && is_unique<T1, Rest...>::value
+>{};
+
+#endif
+}
+
+// end catch_type_traits.hpp
+// start catch_preprocessor.hpp
+
+
+#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
+#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))
+
+#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__
+// MSVC needs more evaluations
+#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))
+#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))
+#else
+#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__)
+#endif
+
+#define CATCH_REC_END(...)
+#define CATCH_REC_OUT
+
+#define CATCH_EMPTY()
+#define CATCH_DEFER(id) id CATCH_EMPTY()
+
+#define CATCH_REC_GET_END2() 0, CATCH_REC_END
+#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2
+#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1
+#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT
+#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)
+#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)
+
+#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
+
+#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+
+// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,
+// and passes userdata as the first parameter to each invocation,
+// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)
+#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)
+#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
+#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
+#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
+#else
+// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
+#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
+#endif
+
+#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
+
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__)
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
+#else
+// MSVC is adding extra space and needs more calls to properly remove ()
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__)
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
+#endif
+
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
+
+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\
+ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types))
+
+// end catch_preprocessor.hpp
+// start catch_meta.hpp
+
+
+#include <type_traits>
+
+namespace Catch {
+template< typename... >
+struct TypeList {};
+
+template< typename... >
+struct append;
+
+template< template<typename...> class L1
+ , typename...E1
+ , template<typename...> class L2
+ , typename...E2
+>
+struct append< L1<E1...>, L2<E2...> > {
+ using type = L1<E1..., E2...>;
+};
+
+template< template<typename...> class L1
+ , typename...E1
+ , template<typename...> class L2
+ , typename...E2
+ , typename...Rest
+>
+struct append< L1<E1...>, L2<E2...>, Rest...> {
+ using type = typename append< L1<E1..., E2...>, Rest... >::type;
+};
+
+template< template<typename...> class
+ , typename...
+>
+struct rewrap;
+
+template< template<typename...> class Container
+ , template<typename...> class List
+ , typename...elems
+>
+struct rewrap<Container, List<elems...>> {
+ using type = TypeList< Container< elems... > >;
+};
+
+template< template<typename...> class Container
+ , template<typename...> class List
+ , class...Elems
+ , typename...Elements>
+ struct rewrap<Container, List<Elems...>, Elements...> {
+ using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
+};
+
+template< template<typename...> class...Containers >
+struct combine {
+ template< typename...Types >
+ struct with_types {
+ template< template <typename...> class Final >
+ struct into {
+ using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
+ };
+ };
+};
+
+template<typename T>
+struct always_false : std::false_type {};
+
+} // namespace Catch
+
+// end catch_meta.hpp
namespace Catch {
template<typename C>
@@ -631,22 +844,28 @@ struct AutoReg : NonCopyable {
} // end namespace Catch
-#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)
-#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
-#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
-#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
-
#if defined(CATCH_CONFIG_DISABLE)
#define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
static void TestName()
#define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
namespace{ \
- struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
void test(); \
}; \
} \
void TestName::test()
-
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... ) \
+ template<typename TestType> \
+ static void TestName()
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
+ namespace{ \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test(); \
+ }; \
+ } \
+ template<typename TestType> \
+ void TestName::test()
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -669,7 +888,7 @@ struct AutoReg : NonCopyable {
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ \
- struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
void test(); \
}; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
@@ -685,6 +904,150 @@ struct AutoReg : NonCopyable {
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> \
+ static void TestFunc();\
+ namespace {\
+ template<typename...Types> \
+ struct TestName{\
+ template<typename...Ts> \
+ TestName(Ts...names){\
+ CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+ using expander = int[];\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+ }\
+ };\
+ INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \
+ }\
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> \
+ static void TestFunc()
+
+#if defined(CATCH_CPP17_OR_GREATER)
+#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case");
+#else
+#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case");
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\
+ return 0;\
+ }();
+
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> static void TestFuncName(); \
+ namespace { \
+ template<typename... Types> \
+ struct TestName { \
+ TestName() { \
+ CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \
+ int index = 0; \
+ using expander = int[]; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\
+ } \
+ }; \
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
+ ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
+ TestInit(); \
+ return 0; \
+ }(); \
+ } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> \
+ static void TestFuncName()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__)
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test();\
+ };\
+ template<typename...Types> \
+ struct TestNameClass{\
+ template<typename...Ts> \
+ TestNameClass(Ts...names){\
+ CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+ using expander = int[];\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+ }\
+ };\
+ INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\
+ }\
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
+ template<typename TestType> \
+ void TestName<TestType>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test();\
+ };\
+ namespace {\
+ template<typename...Types>\
+ struct TestNameClass{\
+ TestNameClass(){\
+ CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
+ int index = 0;\
+ using expander = int[];\
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
+ ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
+ TestInit();\
+ return 0;\
+ }(); \
+ }\
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> \
+ void TestName<TestType>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) )
+#endif
+
// end catch_test_registry.h
// start catch_capture.hpp
@@ -1176,6 +1539,7 @@ namespace Catch {
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
#endif
// Separate std::pair specialization
@@ -1197,6 +1561,24 @@ namespace Catch {
}
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
+#include <optional>
+namespace Catch {
+ template<typename T>
+ struct StringMaker<std::optional<T> > {
+ static std::string convert(const std::optional<T>& optional) {
+ ReusableStringStream rss;
+ if (optional.has_value()) {
+ rss << ::Catch::Detail::stringify(*optional);
+ } else {
+ rss << "{ }";
+ }
+ return rss.str();
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
+
// Separate std::tuple specialization
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
#include <tuple>
@@ -1458,6 +1840,7 @@ struct ratio_string<std::milli> {
#pragma warning(disable:4018) // more "signed/unsigned mismatch"
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
#pragma warning(disable:4180) // qualifier applied to function type has no meaning
+#pragma warning(disable:4800) // Forcing result to true or false
#endif
namespace Catch {
@@ -1501,6 +1884,62 @@ namespace Catch {
m_op( op ),
m_rhs( rhs )
{}
+
+ template<typename T>
+ auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
};
template<typename LhsT>
@@ -1513,7 +1952,7 @@ namespace Catch {
public:
explicit UnaryExpr( LhsT lhs )
- : ITransientExpression{ false, lhs ? true : false },
+ : ITransientExpression{ false, static_cast<bool>(lhs) },
m_lhs( lhs )
{}
};
@@ -1580,6 +2019,20 @@ namespace Catch {
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
}
+ template<typename RhsT>
+ auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<RhsT>::value,
+ "operator&& is not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename RhsT>
+ auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<RhsT>::value,
+ "operator|| is not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
return UnaryExpr<LhsT>{ m_lhs };
}
@@ -1621,6 +2074,7 @@ namespace Catch {
struct SectionInfo;
struct SectionEndInfo;
struct MessageInfo;
+ struct MessageBuilder;
struct Counts;
struct BenchmarkInfo;
struct BenchmarkStats;
@@ -1647,6 +2101,8 @@ namespace Catch {
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
virtual void popScopedMessage( MessageInfo const& message ) = 0;
+ virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
+
virtual void handleFatalErrorCondition( StringRef message ) = 0;
virtual void handleExpr
@@ -1810,9 +2266,12 @@ namespace Catch {
class ScopedMessage {
public:
explicit ScopedMessage( MessageBuilder const& builder );
+ ScopedMessage( ScopedMessage& duplicate ) = delete;
+ ScopedMessage( ScopedMessage&& old );
~ScopedMessage();
MessageInfo m_info;
+ bool m_moved;
};
class Capturer {
@@ -1823,16 +2282,16 @@ namespace Catch {
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
~Capturer();
- void captureValue( size_t index, StringRef value );
+ void captureValue( size_t index, std::string const& value );
template<typename T>
- void captureValues( size_t index, T&& value ) {
+ void captureValues( size_t index, T const& value ) {
captureValue( index, Catch::Detail::stringify( value ) );
}
template<typename T, typename... Ts>
- void captureValues( size_t index, T&& value, Ts&&... values ) {
- captureValues( index, value );
+ void captureValues( size_t index, T const& value, Ts const&... values ) {
+ captureValue( index, Catch::Detail::stringify(value) );
captureValues( index+1, values... );
}
};
@@ -1875,7 +2334,7 @@ namespace Catch {
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
+ } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
///////////////////////////////////////////////////////////////////////////////
@@ -1957,6 +2416,10 @@ namespace Catch {
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
+ Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
+
+///////////////////////////////////////////////////////////////////////////////
// Although this is matcher-based, it can be used with just a string
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
do { \
@@ -2453,10 +2916,6 @@ namespace Matchers {
struct MatcherMethod {
virtual bool match( ObjectT const& arg ) const = 0;
};
- template<typename PtrT>
- struct MatcherMethod<PtrT*> {
- virtual bool match( PtrT* arg ) const = 0;
- };
#ifdef __clang__
# pragma clang diagnostic pop
@@ -2985,16 +3444,17 @@ namespace Catch {
namespace Catch {
namespace Generators {
- class GeneratorBase {
- protected:
- size_t m_size = 0;
-
+ class GeneratorUntypedBase {
public:
- GeneratorBase( size_t size ) : m_size( size ) {}
- virtual ~GeneratorBase();
- auto size() const -> size_t { return m_size; }
+ GeneratorUntypedBase() = default;
+ virtual ~GeneratorUntypedBase();
+ // Attempts to move the generator to the next element
+ //
+ // Returns true iff the move succeeded (and a valid element
+ // can be retrieved).
+ virtual bool next() = 0;
};
- using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
+ using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;
} // namespace Generators
@@ -3003,7 +3463,6 @@ namespace Catch {
virtual auto hasGenerator() const -> bool = 0;
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
- virtual auto getIndex() const -> std::size_t = 0;
};
} // namespace Catch
@@ -3043,8 +3502,21 @@ namespace Catch {
#include <cassert>
#include <utility>
+#include <exception>
namespace Catch {
+
+class GeneratorException : public std::exception {
+ const char* const m_msg = "";
+
+public:
+ GeneratorException(const char* msg):
+ m_msg(msg)
+ {}
+
+ const char* what() const noexcept override final;
+};
+
namespace Generators {
// !TBD move this into its own location?
@@ -3056,223 +3528,631 @@ namespace Generators {
}
template<typename T>
- struct IGenerator {
- virtual ~IGenerator() {}
- virtual auto get( size_t index ) const -> T = 0;
+ struct IGenerator : GeneratorUntypedBase {
+ virtual ~IGenerator() = default;
+
+ // Returns the current element of the generator
+ //
+ // \Precondition The generator is either freshly constructed,
+ // or the last call to `next()` returned true
+ virtual T const& get() const = 0;
+ using type = T;
};
template<typename T>
- class SingleValueGenerator : public IGenerator<T> {
+ class SingleValueGenerator final : public IGenerator<T> {
T m_value;
public:
- SingleValueGenerator( T const& value ) : m_value( value ) {}
+ SingleValueGenerator(T const& value) : m_value( value ) {}
+ SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
- auto get( size_t ) const -> T override {
+ T const& get() const override {
return m_value;
}
+ bool next() override {
+ return false;
+ }
};
template<typename T>
- class FixedValuesGenerator : public IGenerator<T> {
+ class FixedValuesGenerator final : public IGenerator<T> {
std::vector<T> m_values;
-
+ size_t m_idx = 0;
public:
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
- auto get( size_t index ) const -> T override {
- return m_values[index];
+ T const& get() const override {
+ return m_values[m_idx];
+ }
+ bool next() override {
+ ++m_idx;
+ return m_idx < m_values.size();
}
};
+ template <typename T>
+ class GeneratorWrapper final {
+ std::unique_ptr<IGenerator<T>> m_generator;
+ public:
+ GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
+ m_generator(std::move(generator))
+ {}
+ T const& get() const {
+ return m_generator->get();
+ }
+ bool next() {
+ return m_generator->next();
+ }
+ };
+
+ template <typename T>
+ GeneratorWrapper<T> value(T&& value) {
+ return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
+ }
+ template <typename T>
+ GeneratorWrapper<T> values(std::initializer_list<T> values) {
+ return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
+ }
+
template<typename T>
- class RangeGenerator : public IGenerator<T> {
- T const m_first;
- T const m_last;
+ class Generators : public IGenerator<T> {
+ std::vector<GeneratorWrapper<T>> m_generators;
+ size_t m_current = 0;
+
+ void populate(GeneratorWrapper<T>&& generator) {
+ m_generators.emplace_back(std::move(generator));
+ }
+ void populate(T&& val) {
+ m_generators.emplace_back(value(std::move(val)));
+ }
+ template<typename U>
+ void populate(U&& val) {
+ populate(T(std::move(val)));
+ }
+ template<typename U, typename... Gs>
+ void populate(U&& valueOrGenerator, Gs... moreGenerators) {
+ populate(std::forward<U>(valueOrGenerator));
+ populate(std::forward<Gs>(moreGenerators)...);
+ }
public:
- RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) {
- assert( m_last > m_first );
+ template <typename... Gs>
+ Generators(Gs... moreGenerators) {
+ m_generators.reserve(sizeof...(Gs));
+ populate(std::forward<Gs>(moreGenerators)...);
}
- auto get( size_t index ) const -> T override {
- // ToDo:: introduce a safe cast to catch potential overflows
- return static_cast<T>(m_first+index);
+ T const& get() const override {
+ return m_generators[m_current].get();
}
- };
- template<typename T>
- struct NullGenerator : IGenerator<T> {
- auto get( size_t ) const -> T override {
- CATCH_INTERNAL_ERROR("A Null Generator is always empty");
+ bool next() override {
+ if (m_current >= m_generators.size()) {
+ return false;
+ }
+ const bool current_status = m_generators[m_current].next();
+ if (!current_status) {
+ ++m_current;
+ }
+ return m_current < m_generators.size();
}
};
+ template<typename... Ts>
+ GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
+ return values<std::tuple<Ts...>>( tuples );
+ }
+
+ // Tag type to signal that a generator sequence should convert arguments to a specific type
+ template <typename T>
+ struct as {};
+
+ template<typename T, typename... Gs>
+ auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
+ return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
+ }
template<typename T>
- class Generator {
- std::unique_ptr<IGenerator<T>> m_generator;
- size_t m_size;
+ auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
+ return Generators<T>(std::move(generator));
+ }
+ template<typename T, typename... Gs>
+ auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+ }
+ template<typename T, typename U, typename... Gs>
+ auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+ }
+
+ auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+
+ template<typename L>
+ // Note: The type after -> is weird, because VS2015 cannot parse
+ // the expression used in the typedef inside, when it is in
+ // return type. Yeah.
+ auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
+ using UnderlyingType = typename decltype(generatorExpression())::type;
+
+ IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
+ if (!tracker.hasGenerator()) {
+ tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
+ }
+
+ auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
+ return generator.get();
+ }
+
+} // namespace Generators
+} // namespace Catch
+
+#define GENERATE( ... ) \
+ Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+// end catch_generators.hpp
+// start catch_generators_generic.hpp
+
+namespace Catch {
+namespace Generators {
+
+ template <typename T>
+ class TakeGenerator : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ size_t m_returned = 0;
+ size_t m_target;
public:
- Generator( size_t size, std::unique_ptr<IGenerator<T>> generator )
- : m_generator( std::move( generator ) ),
- m_size( size )
- {}
+ TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_target(target)
+ {
+ assert(target != 0 && "Empty generators are not allowed");
+ }
+ T const& get() const override {
+ return m_generator.get();
+ }
+ bool next() override {
+ ++m_returned;
+ if (m_returned >= m_target) {
+ return false;
+ }
- auto size() const -> size_t { return m_size; }
- auto operator[]( size_t index ) const -> T {
- assert( index < m_size );
- return m_generator->get( index );
+ const auto success = m_generator.next();
+ // If the underlying generator does not contain enough values
+ // then we cut short as well
+ if (!success) {
+ m_returned = m_target;
+ }
+ return success;
}
};
- std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
-
- template<typename T>
- class GeneratorRandomiser : public IGenerator<T> {
- Generator<T> m_baseGenerator;
+ template <typename T>
+ GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
+ }
- std::vector<size_t> m_indices;
+ template <typename T, typename Predicate>
+ class FilterGenerator : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ Predicate m_predicate;
public:
- GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems )
- : m_baseGenerator( std::move( baseGenerator ) ),
- m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) )
- {}
+ template <typename P = Predicate>
+ FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_predicate(std::forward<P>(pred))
+ {
+ if (!m_predicate(m_generator.get())) {
+ // It might happen that there are no values that pass the
+ // filter. In that case we throw an exception.
+ auto has_initial_value = next();
+ if (!has_initial_value) {
+ Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
+ }
+ }
+ }
- auto get( size_t index ) const -> T override {
- return m_baseGenerator[m_indices[index]];
+ T const& get() const override {
+ return m_generator.get();
+ }
+
+ bool next() override {
+ bool success = m_generator.next();
+ if (!success) {
+ return false;
+ }
+ while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
+ return success;
}
};
- template<typename T>
- struct RequiresASpecialisationFor;
+ template <typename T, typename Predicate>
+ GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
+ }
- template<typename T>
- auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
+ template <typename T>
+ class RepeatGenerator : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ mutable std::vector<T> m_returned;
+ size_t m_target_repeats;
+ size_t m_current_repeat = 0;
+ size_t m_repeat_index = 0;
+ public:
+ RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_target_repeats(repeats)
+ {
+ assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
+ }
- template<>
- auto all<int>() -> Generator<int>;
+ T const& get() const override {
+ if (m_current_repeat == 0) {
+ m_returned.push_back(m_generator.get());
+ return m_returned.back();
+ }
+ return m_returned[m_repeat_index];
+ }
- template<typename T>
- auto range( T const& first, T const& last ) -> Generator<T> {
- return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) );
+ bool next() override {
+ // There are 2 basic cases:
+ // 1) We are still reading the generator
+ // 2) We are reading our own cache
+
+ // In the first case, we need to poke the underlying generator.
+ // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
+ if (m_current_repeat == 0) {
+ const auto success = m_generator.next();
+ if (!success) {
+ ++m_current_repeat;
+ }
+ return m_current_repeat < m_target_repeats;
+ }
+
+ // In the second case, we need to move indices forward and check that we haven't run up against the end
+ ++m_repeat_index;
+ if (m_repeat_index == m_returned.size()) {
+ m_repeat_index = 0;
+ ++m_current_repeat;
+ }
+ return m_current_repeat < m_target_repeats;
+ }
+ };
+
+ template <typename T>
+ GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
}
- template<typename T>
- auto random( T const& first, T const& last ) -> Generator<T> {
- auto gen = range( first, last );
- auto size = gen.size();
+ template <typename T, typename U, typename Func>
+ class MapGenerator : public IGenerator<T> {
+ // TBD: provide static assert for mapping function, for friendly error message
+ GeneratorWrapper<U> m_generator;
+ Func m_function;
+ // To avoid returning dangling reference, we have to save the values
+ T m_cache;
+ public:
+ template <typename F2 = Func>
+ MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
+ m_generator(std::move(generator)),
+ m_function(std::forward<F2>(function)),
+ m_cache(m_function(m_generator.get()))
+ {}
+
+ T const& get() const override {
+ return m_cache;
+ }
+ bool next() override {
+ const auto success = m_generator.next();
+ if (success) {
+ m_cache = m_function(m_generator.get());
+ }
+ return success;
+ }
+ };
- return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
+ template <typename T, typename U, typename Func>
+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+ return GeneratorWrapper<T>(
+ pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
+ );
}
- template<typename T>
- auto random( size_t size ) -> Generator<T> {
- return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
+ template <typename T, typename Func>
+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(
+ pf::make_unique<MapGenerator<T, T, Func>>(std::forward<Func>(function), std::move(generator))
+ );
}
- template<typename T>
- auto values( std::initializer_list<T> values ) -> Generator<T> {
- return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) );
- }
- template<typename T>
- auto value( T const& val ) -> Generator<T> {
- return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) );
+ template <typename T>
+ class ChunkGenerator final : public IGenerator<std::vector<T>> {
+ std::vector<T> m_chunk;
+ size_t m_chunk_size;
+ GeneratorWrapper<T> m_generator;
+ bool m_used_up = false;
+ public:
+ ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
+ m_chunk_size(size), m_generator(std::move(generator))
+ {
+ m_chunk.reserve(m_chunk_size);
+ m_chunk.push_back(m_generator.get());
+ for (size_t i = 1; i < m_chunk_size; ++i) {
+ if (!m_generator.next()) {
+ Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
+ }
+ m_chunk.push_back(m_generator.get());
+ }
+ }
+ std::vector<T> const& get() const override {
+ return m_chunk;
+ }
+ bool next() override {
+ m_chunk.clear();
+ for (size_t idx = 0; idx < m_chunk_size; ++idx) {
+ if (!m_generator.next()) {
+ return false;
+ }
+ m_chunk.push_back(m_generator.get());
+ }
+ return true;
+ }
+ };
+
+ template <typename T>
+ GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<std::vector<T>>(
+ pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
+ );
}
- template<typename T>
- auto as() -> Generator<T> {
- return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
+} // namespace Generators
+} // namespace Catch
+
+// end catch_generators_generic.hpp
+// start catch_generators_specific.hpp
+
+// start catch_context.h
+
+#include <memory>
+
+namespace Catch {
+
+ struct IResultCapture;
+ struct IRunner;
+ struct IConfig;
+ struct IMutableContext;
+
+ using IConfigPtr = std::shared_ptr<IConfig const>;
+
+ struct IContext
+ {
+ virtual ~IContext();
+
+ virtual IResultCapture* getResultCapture() = 0;
+ virtual IRunner* getRunner() = 0;
+ virtual IConfigPtr const& getConfig() const = 0;
+ };
+
+ struct IMutableContext : IContext
+ {
+ virtual ~IMutableContext();
+ virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+ virtual void setRunner( IRunner* runner ) = 0;
+ virtual void setConfig( IConfigPtr const& config ) = 0;
+
+ private:
+ static IMutableContext *currentContext;
+ friend IMutableContext& getCurrentMutableContext();
+ friend void cleanUpContext();
+ static void createContext();
+ };
+
+ inline IMutableContext& getCurrentMutableContext()
+ {
+ if( !IMutableContext::currentContext )
+ IMutableContext::createContext();
+ return *IMutableContext::currentContext;
}
- template<typename... Ts>
- auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> {
- return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) );
+ inline IContext& getCurrentContext()
+ {
+ return getCurrentMutableContext();
}
- template<typename T>
- struct Generators : GeneratorBase {
- std::vector<Generator<T>> m_generators;
+ void cleanUpContext();
+}
- using type = T;
+// end catch_context.h
+// start catch_interfaces_config.h
- Generators() : GeneratorBase( 0 ) {}
+#include <iosfwd>
+#include <string>
+#include <vector>
+#include <memory>
- void populate( T&& val ) {
- m_size += 1;
- m_generators.emplace_back( value( std::move( val ) ) );
- }
- template<typename U>
- void populate( U&& val ) {
- populate( T( std::move( val ) ) );
- }
- void populate( Generator<T>&& generator ) {
- m_size += generator.size();
- m_generators.emplace_back( std::move( generator ) );
- }
+namespace Catch {
- template<typename U, typename... Gs>
- void populate( U&& valueOrGenerator, Gs... moreGenerators ) {
- populate( std::forward<U>( valueOrGenerator ) );
- populate( std::forward<Gs>( moreGenerators )... );
- }
+ enum class Verbosity {
+ Quiet = 0,
+ Normal,
+ High
+ };
- auto operator[]( size_t index ) const -> T {
- size_t sizes = 0;
- for( auto const& gen : m_generators ) {
- auto localIndex = index-sizes;
- sizes += gen.size();
- if( index < sizes )
- return gen[localIndex];
- }
- CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
- }
+ struct WarnAbout { enum What {
+ Nothing = 0x00,
+ NoAssertions = 0x01,
+ NoTests = 0x02
+ }; };
+
+ struct ShowDurations { enum OrNot {
+ DefaultForReporter,
+ Always,
+ Never
+ }; };
+ struct RunTests { enum InWhatOrder {
+ InDeclarationOrder,
+ InLexicographicalOrder,
+ InRandomOrder
+ }; };
+ struct UseColour { enum YesOrNo {
+ Auto,
+ Yes,
+ No
+ }; };
+ struct WaitForKeypress { enum When {
+ Never,
+ BeforeStart = 1,
+ BeforeExit = 2,
+ BeforeStartAndExit = BeforeStart | BeforeExit
+ }; };
+
+ class TestSpec;
+
+ struct IConfig : NonCopyable {
+
+ virtual ~IConfig();
+
+ virtual bool allowThrows() const = 0;
+ virtual std::ostream& stream() const = 0;
+ virtual std::string name() const = 0;
+ virtual bool includeSuccessfulResults() const = 0;
+ virtual bool shouldDebugBreak() const = 0;
+ virtual bool warnAboutMissingAssertions() const = 0;
+ virtual bool warnAboutNoTests() const = 0;
+ virtual int abortAfter() const = 0;
+ virtual bool showInvisibles() const = 0;
+ virtual ShowDurations::OrNot showDurations() const = 0;
+ virtual TestSpec const& testSpec() const = 0;
+ virtual bool hasTestFilters() const = 0;
+ virtual RunTests::InWhatOrder runOrder() const = 0;
+ virtual unsigned int rngSeed() const = 0;
+ virtual int benchmarkResolutionMultiple() const = 0;
+ virtual UseColour::YesOrNo useColour() const = 0;
+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+ virtual Verbosity verbosity() const = 0;
};
- template<typename T, typename... Gs>
- auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
- Generators<T> generators;
- generators.m_generators.reserve( 1+sizeof...(Gs) );
- generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... );
- return generators;
+ using IConfigPtr = std::shared_ptr<IConfig const>;
+}
+
+// end catch_interfaces_config.h
+#include <random>
+
+namespace Catch {
+namespace Generators {
+
+template <typename Float>
+class RandomFloatingGenerator final : public IGenerator<Float> {
+ // FIXME: What is the right seed?
+ std::minstd_rand m_rand;
+ std::uniform_real_distribution<Float> m_dist;
+ Float m_current_number;
+public:
+
+ RandomFloatingGenerator(Float a, Float b):
+ m_rand(getCurrentContext().getConfig()->rngSeed()),
+ m_dist(a, b) {
+ static_cast<void>(next());
}
- template<typename T>
- auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
- Generators<T> generators;
- generators.populate( std::move( generator ) );
- return generators;
+
+ Float const& get() const override {
+ return m_current_number;
}
- template<typename T, typename... Gs>
- auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
- return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+ bool next() override {
+ m_current_number = m_dist(m_rand);
+ return true;
}
- template<typename T, typename U, typename... Gs>
- auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> {
- return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+};
+
+template <typename Integer>
+class RandomIntegerGenerator final : public IGenerator<Integer> {
+ std::minstd_rand m_rand;
+ std::uniform_int_distribution<Integer> m_dist;
+ Integer m_current_number;
+public:
+
+ RandomIntegerGenerator(Integer a, Integer b):
+ m_rand(getCurrentContext().getConfig()->rngSeed()),
+ m_dist(a, b) {
+ static_cast<void>(next());
}
- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+ Integer const& get() const override {
+ return m_current_number;
+ }
+ bool next() override {
+ m_current_number = m_dist(m_rand);
+ return true;
+ }
+};
- template<typename L>
- // Note: The type after -> is weird, because VS2015 cannot parse
- // the expression used in the typedef inside, when it is in
- // return type. Yeah, ¯\_(ツ)_/¯
- auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) {
- using UnderlyingType = typename decltype(generatorExpression())::type;
+// TODO: Ideally this would be also constrained against the various char types,
+// but I don't expect users to run into that in practice.
+template <typename T>
+typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
+GeneratorWrapper<T>>::type
+random(T a, T b) {
+ return GeneratorWrapper<T>(
+ pf::make_unique<RandomIntegerGenerator<T>>(a, b)
+ );
+}
- IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
- if( !tracker.hasGenerator() )
- tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) );
+template <typename T>
+typename std::enable_if<std::is_floating_point<T>::value,
+GeneratorWrapper<T>>::type
+random(T a, T b) {
+ return GeneratorWrapper<T>(
+ pf::make_unique<RandomFloatingGenerator<T>>(a, b)
+ );
+}
+
+template <typename T>
+class RangeGenerator final : public IGenerator<T> {
+ T m_current;
+ T m_end;
+ T m_step;
+ bool m_positive;
- auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() );
- return generator[tracker.getIndex()];
+public:
+ RangeGenerator(T const& start, T const& end, T const& step):
+ m_current(start),
+ m_end(end),
+ m_step(step),
+ m_positive(m_step > T(0))
+ {
+ assert(m_current != m_end && "Range start and end cannot be equal");
+ assert(m_step != T(0) && "Step size cannot be zero");
+ assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
}
+ RangeGenerator(T const& start, T const& end):
+ RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
+ {}
+
+ T const& get() const override {
+ return m_current;
+ }
+
+ bool next() override {
+ m_current += m_step;
+ return (m_positive) ? (m_current < m_end) : (m_current > m_end);
+ }
+};
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
+ static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+ return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
+}
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end) {
+ static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+ return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
+}
+
} // namespace Generators
} // namespace Catch
-#define GENERATE( ... ) \
- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
-
-// end catch_generators.hpp
+// end catch_generators_specific.hpp
// These files are included here so the single_include script doesn't put them
// in the conditionally compiled sections
@@ -3759,79 +4639,6 @@ namespace Catch {
#endif
// end catch_test_spec_parser.h
-// start catch_interfaces_config.h
-
-#include <iosfwd>
-#include <string>
-#include <vector>
-#include <memory>
-
-namespace Catch {
-
- enum class Verbosity {
- Quiet = 0,
- Normal,
- High
- };
-
- struct WarnAbout { enum What {
- Nothing = 0x00,
- NoAssertions = 0x01,
- NoTests = 0x02
- }; };
-
- struct ShowDurations { enum OrNot {
- DefaultForReporter,
- Always,
- Never
- }; };
- struct RunTests { enum InWhatOrder {
- InDeclarationOrder,
- InLexicographicalOrder,
- InRandomOrder
- }; };
- struct UseColour { enum YesOrNo {
- Auto,
- Yes,
- No
- }; };
- struct WaitForKeypress { enum When {
- Never,
- BeforeStart = 1,
- BeforeExit = 2,
- BeforeStartAndExit = BeforeStart | BeforeExit
- }; };
-
- class TestSpec;
-
- struct IConfig : NonCopyable {
-
- virtual ~IConfig();
-
- virtual bool allowThrows() const = 0;
- virtual std::ostream& stream() const = 0;
- virtual std::string name() const = 0;
- virtual bool includeSuccessfulResults() const = 0;
- virtual bool shouldDebugBreak() const = 0;
- virtual bool warnAboutMissingAssertions() const = 0;
- virtual bool warnAboutNoTests() const = 0;
- virtual int abortAfter() const = 0;
- virtual bool showInvisibles() const = 0;
- virtual ShowDurations::OrNot showDurations() const = 0;
- virtual TestSpec const& testSpec() const = 0;
- virtual bool hasTestFilters() const = 0;
- virtual RunTests::InWhatOrder runOrder() const = 0;
- virtual unsigned int rngSeed() const = 0;
- virtual int benchmarkResolutionMultiple() const = 0;
- virtual UseColour::YesOrNo useColour() const = 0;
- virtual std::vector<std::string> const& getSectionsToRun() const = 0;
- virtual Verbosity verbosity() const = 0;
- };
-
- using IConfigPtr = std::shared_ptr<IConfig const>;
-}
-
-// end catch_interfaces_config.h
// Libstdc++ doesn't like incomplete classes for unique_ptr
#include <memory>
@@ -4111,8 +4918,8 @@ namespace Catch {
AssertionStats( AssertionStats const& ) = default;
AssertionStats( AssertionStats && ) = default;
- AssertionStats& operator = ( AssertionStats const& ) = default;
- AssertionStats& operator = ( AssertionStats && ) = default;
+ AssertionStats& operator = ( AssertionStats const& ) = delete;
+ AssertionStats& operator = ( AssertionStats && ) = delete;
virtual ~AssertionStats();
AssertionResult assertionResult;
@@ -4514,6 +5321,8 @@ namespace Catch {
struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {
TestEventListenerBase( ReporterConfig const& _config );
+ static std::set<Verbosity> getSupportedVerbosities();
+
void assertionStarting(AssertionInfo const&) override;
bool assertionEnded(AssertionStats const&) override;
};
@@ -4997,7 +5806,7 @@ namespace TestCaseTracking {
// Debug/ checking
virtual bool isSectionTracker() const = 0;
- virtual bool isIndexTracker() const = 0;
+ virtual bool isGeneratorTracker() const = 0;
};
class TrackerContext {
@@ -5062,7 +5871,7 @@ namespace TestCaseTracking {
void openChild() override;
bool isSectionTracker() const override;
- bool isIndexTracker() const override;
+ bool isGeneratorTracker() const override;
void open();
@@ -5082,6 +5891,8 @@ namespace TestCaseTracking {
bool isSectionTracker() const override;
+ bool isComplete() const override;
+
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
void tryOpen();
@@ -5090,28 +5901,11 @@ namespace TestCaseTracking {
void addNextFilters( std::vector<std::string> const& filters );
};
- class IndexTracker : public TrackerBase {
- int m_size;
- int m_index = -1;
- public:
- IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size );
-
- bool isIndexTracker() const override;
- void close() override;
-
- static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size );
-
- int index() const;
-
- void moveNext();
- };
-
} // namespace TestCaseTracking
using TestCaseTracking::ITracker;
using TestCaseTracking::TrackerContext;
using TestCaseTracking::SectionTracker;
-using TestCaseTracking::IndexTracker;
} // namespace Catch
@@ -5209,58 +6003,6 @@ std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx co
// end catch_approx.cpp
// start catch_assertionhandler.cpp
-// start catch_context.h
-
-#include <memory>
-
-namespace Catch {
-
- struct IResultCapture;
- struct IRunner;
- struct IConfig;
- struct IMutableContext;
-
- using IConfigPtr = std::shared_ptr<IConfig const>;
-
- struct IContext
- {
- virtual ~IContext();
-
- virtual IResultCapture* getResultCapture() = 0;
- virtual IRunner* getRunner() = 0;
- virtual IConfigPtr const& getConfig() const = 0;
- };
-
- struct IMutableContext : IContext
- {
- virtual ~IMutableContext();
- virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
- virtual void setRunner( IRunner* runner ) = 0;
- virtual void setConfig( IConfigPtr const& config ) = 0;
-
- private:
- static IMutableContext *currentContext;
- friend IMutableContext& getCurrentMutableContext();
- friend void cleanUpContext();
- static void createContext();
- };
-
- inline IMutableContext& getCurrentMutableContext()
- {
- if( !IMutableContext::currentContext )
- IMutableContext::createContext();
- return *IMutableContext::currentContext;
- }
-
- inline IContext& getCurrentContext()
- {
- return getCurrentMutableContext();
- }
-
- void cleanUpContext();
-}
-
-// end catch_context.h
// start catch_debugger.h
namespace Catch {
@@ -5290,12 +6032,9 @@ namespace Catch {
#endif
#ifdef CATCH_TRAP
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+ #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
#else
- namespace Catch {
- inline void doNothing() {}
- }
- #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
+ #define CATCH_BREAK_INTO_DEBUGGER() []{}()
#endif
// end catch_debugger.h
@@ -5450,6 +6189,8 @@ namespace Catch {
void pushScopedMessage( MessageInfo const& message ) override;
void popScopedMessage( MessageInfo const& message ) override;
+ void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
+
std::string getCurrentTestName() const override;
const AssertionResult* getLastResult() const override;
@@ -5490,13 +6231,14 @@ namespace Catch {
TestRunInfo m_runInfo;
IMutableContext& m_context;
TestCase const* m_activeTestCase = nullptr;
- ITracker* m_testCaseTracker;
+ ITracker* m_testCaseTracker = nullptr;
Option<AssertionResult> m_lastResult;
IConfigPtr m_config;
Totals m_totals;
IStreamingReporterPtr m_reporter;
std::vector<MessageInfo> m_messages;
+ std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
AssertionInfo m_lastAssertionInfo;
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
@@ -6133,6 +6875,7 @@ inline auto Column::operator + (Column const& other) -> Columns {
// ----------- end of #include from clara_textflow.hpp -----------
// ........... back in clara.hpp
+#include <cctype>
#include <string>
#include <memory>
#include <set>
@@ -6425,7 +7168,7 @@ namespace detail {
}
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
std::string srcLC = source;
- std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
+ std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
target = true;
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
@@ -7490,7 +8233,8 @@ namespace {
private:
void setColour( const char* _escapeCode ) {
- Catch::cout() << '\033' << _escapeCode;
+ getCurrentContext().getConfig()->stream()
+ << '\033' << _escapeCode;
}
};
@@ -7869,18 +8613,24 @@ namespace Catch {
}
}
+ std::string ExceptionTranslatorRegistry::tryTranslators() const {
+ if (m_translators.empty()) {
+ std::rethrow_exception(std::current_exception());
+ } else {
+ return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
+ }
+ }
+
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
std::string ExceptionTranslatorRegistry::translateActiveException() const {
CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
}
-#endif
std::string ExceptionTranslatorRegistry::tryTranslators() const {
- if( m_translators.empty() )
- std::rethrow_exception(std::current_exception());
- else
- return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
+ CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
}
+#endif
+
}
// end catch_exception_translator_registry.cpp
// start catch_fatal_condition.cpp
@@ -8069,36 +8819,18 @@ namespace Catch {
IGeneratorTracker::~IGeneratorTracker() {}
-namespace Generators {
-
- GeneratorBase::~GeneratorBase() {}
-
- std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) {
+const char* GeneratorException::what() const noexcept {
+ return m_msg;
+}
- assert( selectionSize <= sourceSize );
- std::vector<size_t> indices;
- indices.reserve( selectionSize );
- std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 );
+namespace Generators {
- std::set<size_t> seen;
- // !TBD: improve this algorithm
- while( indices.size() < selectionSize ) {
- auto index = uid( rng() );
- if( seen.insert( index ).second )
- indices.push_back( index );
- }
- return indices;
- }
+ GeneratorUntypedBase::~GeneratorUntypedBase() {}
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
return getResultCapture().acquireGeneratorTracker( lineInfo );
}
- template<>
- auto all<int>() -> Generator<int> {
- return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() );
- }
-
} // namespace Generators
} // namespace Catch
// end catch_generators.cpp
@@ -8346,7 +9078,7 @@ namespace Catch {
std::size_t listReporters();
- Option<std::size_t> list( Config const& config );
+ Option<std::size_t> list( std::shared_ptr<Config> const& config );
} // end namespace Catch
@@ -8484,15 +9216,16 @@ namespace Catch {
return factories.size();
}
- Option<std::size_t> list( Config const& config ) {
+ Option<std::size_t> list( std::shared_ptr<Config> const& config ) {
Option<std::size_t> listedCount;
- if( config.listTests() )
- listedCount = listedCount.valueOr(0) + listTests( config );
- if( config.listTestNamesOnly() )
- listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
- if( config.listTags() )
- listedCount = listedCount.valueOr(0) + listTags( config );
- if( config.listReporters() )
+ getCurrentMutableContext().setConfig( config );
+ if( config->listTests() )
+ listedCount = listedCount.valueOr(0) + listTests( *config );
+ if( config->listTestNamesOnly() )
+ listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );
+ if( config->listTags() )
+ listedCount = listedCount.valueOr(0) + listTags( *config );
+ if( config->listReporters() )
listedCount = listedCount.valueOr(0) + listReporters();
return listedCount;
}
@@ -8523,6 +9256,14 @@ using Matchers::Impl::MatcherBase;
// end catch_matchers.cpp
// start catch_matchers_floating.cpp
+// start catch_polyfills.hpp
+
+namespace Catch {
+ bool isnan(float f);
+ bool isnan(double d);
+}
+
+// end catch_polyfills.hpp
// start catch_to_string.hpp
#include <string>
@@ -8588,7 +9329,7 @@ template <typename FP>
bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
// Comparison with NaN should always be false.
// This way we can rule it out before getting into the ugly details
- if (std::isnan(lhs) || std::isnan(rhs)) {
+ if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
return false;
}
@@ -8796,6 +9537,7 @@ namespace Catch {
// end catch_uncaught_exceptions.h
#include <cassert>
+#include <stack>
namespace Catch {
@@ -8829,32 +9571,67 @@ namespace Catch {
////////////////////////////////////////////////////////////////////////////
ScopedMessage::ScopedMessage( MessageBuilder const& builder )
- : m_info( builder.m_info )
+ : m_info( builder.m_info ), m_moved()
{
m_info.message = builder.m_stream.str();
getResultCapture().pushScopedMessage( m_info );
}
+ ScopedMessage::ScopedMessage( ScopedMessage&& old )
+ : m_info( old.m_info ), m_moved()
+ {
+ old.m_moved = true;
+ }
+
ScopedMessage::~ScopedMessage() {
- if ( !uncaught_exceptions() ){
+ if ( !uncaught_exceptions() && !m_moved ){
getResultCapture().popScopedMessage(m_info);
}
}
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
- auto start = std::string::npos;
- for( size_t pos = 0; pos <= names.size(); ++pos ) {
+ auto trimmed = [&] (size_t start, size_t end) {
+ while (names[start] == ',' || isspace(names[start])) {
+ ++start;
+ }
+ while (names[end] == ',' || isspace(names[end])) {
+ --end;
+ }
+ return names.substr(start, end - start + 1);
+ };
+
+ size_t start = 0;
+ std::stack<char> openings;
+ for (size_t pos = 0; pos < names.size(); ++pos) {
char c = names[pos];
- if( pos == names.size() || c == ' ' || c == '\t' || c == ',' || c == ']' ) {
- if( start != std::string::npos ) {
- m_messages.push_back( MessageInfo( macroName, lineInfo, resultType ) );
- m_messages.back().message = names.substr( start, pos-start) + " := ";
- start = std::string::npos;
+ switch (c) {
+ case '[':
+ case '{':
+ case '(':
+ // It is basically impossible to disambiguate between
+ // comparison and start of template args in this context
+// case '<':
+ openings.push(c);
+ break;
+ case ']':
+ case '}':
+ case ')':
+// case '>':
+ openings.pop();
+ break;
+ case ',':
+ if (start != pos && openings.size() == 0) {
+ m_messages.emplace_back(macroName, lineInfo, resultType);
+ m_messages.back().message = trimmed(start, pos);
+ m_messages.back().message += " := ";
+ start = pos;
}
}
- else if( c != '[' && c != ']' && start == std::string::npos )
- start = pos;
}
+ assert(openings.size() == 0 && "Mismatched openings");
+ m_messages.emplace_back(macroName, lineInfo, resultType);
+ m_messages.back().message = trimmed(start, names.size() - 1);
+ m_messages.back().message += " := ";
}
Capturer::~Capturer() {
if ( !uncaught_exceptions() ){
@@ -8864,7 +9641,7 @@ namespace Catch {
}
}
- void Capturer::captureValue( size_t index, StringRef value ) {
+ void Capturer::captureValue( size_t index, std::string const& value ) {
assert( index < m_messages.size() );
m_messages[index].message += value;
m_resultCapture.pushScopedMessage( m_messages[index] );
@@ -8915,6 +9692,22 @@ namespace Catch {
auto str() const -> std::string;
};
+ class RedirectedStreams {
+ public:
+ RedirectedStreams(RedirectedStreams const&) = delete;
+ RedirectedStreams& operator=(RedirectedStreams const&) = delete;
+ RedirectedStreams(RedirectedStreams&&) = delete;
+ RedirectedStreams& operator=(RedirectedStreams&&) = delete;
+
+ RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
+ ~RedirectedStreams();
+ private:
+ std::string& m_redirectedCout;
+ std::string& m_redirectedCerr;
+ RedirectedStdOut m_redirectedStdOut;
+ RedirectedStdErr m_redirectedStdErr;
+ };
+
#if defined(CATCH_CONFIG_NEW_CAPTURE)
// Windows's implementation of std::tmpfile is terrible (it tries
@@ -9006,6 +9799,16 @@ namespace Catch {
{}
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
+ RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
+ : m_redirectedCout(redirectedCout),
+ m_redirectedCerr(redirectedCerr)
+ {}
+
+ RedirectedStreams::~RedirectedStreams() {
+ m_redirectedCout += m_redirectedStdOut.str();
+ m_redirectedCerr += m_redirectedStdErr.str();
+ }
+
#if defined(CATCH_CONFIG_NEW_CAPTURE)
#if defined(_MSC_VER)
@@ -9092,6 +9895,31 @@ namespace Catch {
#endif
#endif
// end catch_output_redirect.cpp
+// start catch_polyfills.cpp
+
+#include <cmath>
+
+namespace Catch {
+
+#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)
+ bool isnan(float f) {
+ return std::isnan(f);
+ }
+ bool isnan(double d) {
+ return std::isnan(d);
+ }
+#else
+ // For now we only use this for embarcadero
+ bool isnan(float f) {
+ return std::_isnan(f);
+ }
+ bool isnan(double d) {
+ return std::_isnan(d);
+ }
+#endif
+
+} // end namespace Catch
+// end catch_polyfills.cpp
// start catch_random_number_generator.cpp
namespace Catch {
@@ -9416,7 +10244,6 @@ namespace Catch {
namespace Generators {
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
- size_t m_index = static_cast<size_t>( -1 );
GeneratorBasePtr m_generator;
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
@@ -9430,7 +10257,7 @@ namespace Catch {
ITracker& currentTracker = ctx.currentTracker();
if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
- assert( childTracker->isIndexTracker() );
+ assert( childTracker->isGeneratorTracker() );
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
}
else {
@@ -9439,28 +10266,24 @@ namespace Catch {
}
if( !ctx.completedCycle() && !tracker->isComplete() ) {
- if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
- tracker->moveNext();
tracker->open();
}
return *tracker;
}
- void moveNext() {
- m_index++;
- m_children.clear();
- }
-
// TrackerBase interface
- bool isIndexTracker() const override { return true; }
+ bool isGeneratorTracker() const override { return true; }
auto hasGenerator() const -> bool override {
return !!m_generator;
}
void close() override {
TrackerBase::close();
- if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 )
+ // Generator interface only finds out if it has another item on atual move
+ if (m_runState == CompletedSuccessfully && m_generator->next()) {
+ m_children.clear();
m_runState = Executing;
+ }
}
// IGeneratorTracker interface
@@ -9470,9 +10293,6 @@ namespace Catch {
void setGenerator( GeneratorBasePtr&& generator ) override {
m_generator = std::move( generator );
}
- auto getIndex() const -> size_t override {
- return m_index;
- }
};
GeneratorTracker::~GeneratorTracker() {}
}
@@ -9570,6 +10390,9 @@ namespace Catch {
// and should be let to clear themselves out.
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
+ if (result.getResultType() != ResultWas::Warning)
+ m_messageScopes.clear();
+
// Reset working state
resetAssertionInfo();
m_lastResult = result;
@@ -9624,6 +10447,7 @@ namespace Catch {
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
m_messages.clear();
+ m_messageScopes.clear();
}
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
@@ -9650,6 +10474,10 @@ namespace Catch {
m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
}
+ void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
+ m_messageScopes.emplace_back( builder );
+ }
+
std::string RunContext::getCurrentTestName() const {
return m_activeTestCase
? m_activeTestCase->getTestCaseInfo().name
@@ -9710,6 +10538,7 @@ namespace Catch {
m_lastAssertionPassed = true;
++m_totals.assertions.passed;
resetAssertionInfo();
+ m_messageScopes.clear();
}
bool RunContext::aborting() const {
@@ -9731,13 +10560,10 @@ namespace Catch {
CATCH_TRY {
if (m_reporter->getPreferences().shouldRedirectStdOut) {
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
- RedirectedStdOut redirectedStdOut;
- RedirectedStdErr redirectedStdErr;
+ RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
timer.start();
invokeActiveTestCase();
- redirectedCout += redirectedStdOut.str();
- redirectedCerr += redirectedStdErr.str();
#else
OutputRedirect r(redirectedCout, redirectedCerr);
timer.start();
@@ -9764,6 +10590,7 @@ namespace Catch {
m_testCaseTracker->close();
handleUnfinishedSections();
m_messages.clear();
+ m_messageScopes.clear();
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
m_reporter->sectionEnded(testCaseSectionStats);
@@ -10044,19 +10871,22 @@ namespace Catch {
return createReporter(config->getReporterName(), config);
}
- auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
-
+ // On older platforms, returning std::unique_ptr<ListeningReporter>
+ // when the return type is std::unique_ptr<IStreamingReporter>
+ // doesn't compile without a std::move call. However, this causes
+ // a warning on newer platforms. Thus, we have to work around
+ // it a bit and downcast the pointer manually.
+ auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
+ auto& multi = static_cast<ListeningReporter&>(*ret);
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
for (auto const& listener : listeners) {
- multi->addListener(listener->create(Catch::ReporterConfig(config)));
+ multi.addListener(listener->create(Catch::ReporterConfig(config)));
}
- multi->addReporter(createReporter(config->getReporterName(), config));
- return std::move(multi);
+ multi.addReporter(createReporter(config->getReporterName(), config));
+ return ret;
}
Catch::Totals runTests(std::shared_ptr<Config> const& config) {
- // FixMe: Add listeners in order first, then add reporters.
-
auto reporter = makeReporter(config);
RunContext context(config, std::move(reporter));
@@ -10169,6 +10999,8 @@ namespace Catch {
auto result = m_cli.parse( clara::Args( argc, argv ) );
if( !result ) {
+ config();
+ getCurrentMutableContext().setConfig(m_config);
Catch::cerr()
<< Colour( Colour::Red )
<< "\nError(s) in input:\n"
@@ -10260,7 +11092,7 @@ namespace Catch {
applyFilenamesAsTags( *m_config );
// Handle list request
- if( Option<std::size_t> listed = list( config() ) )
+ if( Option<std::size_t> listed = list( m_config ) )
return static_cast<int>( *listed );
auto totals = runTests( m_config );
@@ -11134,7 +11966,7 @@ namespace TestCaseTracking {
}
bool TrackerBase::isSectionTracker() const { return false; }
- bool TrackerBase::isIndexTracker() const { return false; }
+ bool TrackerBase::isGeneratorTracker() const { return false; }
void TrackerBase::open() {
m_runState = Executing;
@@ -11203,6 +12035,17 @@ namespace TestCaseTracking {
}
}
+ bool SectionTracker::isComplete() const {
+ bool complete = true;
+
+ if ((m_filters.empty() || m_filters[0] == "") ||
+ std::find(m_filters.begin(), m_filters.end(),
+ m_nameAndLocation.name) != m_filters.end())
+ complete = TrackerBase::isComplete();
+ return complete;
+
+ }
+
bool SectionTracker::isSectionTracker() const { return true; }
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
@@ -11240,55 +12083,11 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
}
- IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
- : TrackerBase( nameAndLocation, ctx, parent ),
- m_size( size )
- {}
-
- bool IndexTracker::isIndexTracker() const { return true; }
-
- IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
- std::shared_ptr<IndexTracker> tracker;
-
- ITracker& currentTracker = ctx.currentTracker();
- if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
- assert( childTracker );
- assert( childTracker->isIndexTracker() );
- tracker = std::static_pointer_cast<IndexTracker>( childTracker );
- }
- else {
- tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, &currentTracker, size );
- currentTracker.addChild( tracker );
- }
-
- if( !ctx.completedCycle() && !tracker->isComplete() ) {
- if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
- tracker->moveNext();
- tracker->open();
- }
-
- return *tracker;
- }
-
- int IndexTracker::index() const { return m_index; }
-
- void IndexTracker::moveNext() {
- m_index++;
- m_children.clear();
- }
-
- void IndexTracker::close() {
- TrackerBase::close();
- if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
- m_runState = Executing;
- }
-
} // namespace TestCaseTracking
using TestCaseTracking::ITracker;
using TestCaseTracking::TrackerContext;
using TestCaseTracking::SectionTracker;
-using TestCaseTracking::IndexTracker;
} // namespace Catch
@@ -11491,7 +12290,7 @@ namespace Catch {
// is terrible and we should move on.
// TBD: How to signal that the measured resolution is probably wrong?
if (ticks > startTime + 3 * nanosecondsInSecond) {
- return sum / i;
+ return sum / ( i + 1u );
}
}
@@ -11582,7 +12381,7 @@ namespace Detail {
template<typename T>
std::string fpToString( T value, int precision ) {
- if (std::isnan(value)) {
+ if (Catch::isnan(value)) {
return "nan";
}
@@ -11866,7 +12665,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 2, 4, 2, "", 0 );
+ static Version version( 2, 7, 0, "", 0 );
return version;
}
@@ -11950,9 +12749,11 @@ namespace {
}
void hexEscapeChar(std::ostream& os, unsigned char c) {
+ std::ios_base::fmtflags f(os.flags());
os << "\\x"
<< std::uppercase << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<int>(c);
+ os.flags(f);
}
} // anonymous namespace
@@ -12216,7 +13017,7 @@ namespace Catch {
#ifdef _MSC_VER
sprintf_s(buffer, "%.3f", duration);
#else
- sprintf(buffer, "%.3f", duration);
+ std::sprintf(buffer, "%.3f", duration);
#endif
return std::string(buffer);
}
@@ -12224,6 +13025,10 @@ namespace Catch {
TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
:StreamingReporterBase(_config) {}
+ std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() {
+ return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High };
+ }
+
void TestEventListenerBase::assertionStarting(AssertionInfo const &) {}
bool TestEventListenerBase::assertionEnded(AssertionStats const &) {
@@ -12612,8 +13417,6 @@ public:
void print() const {
printSourceInfo();
if (stats.totals.assertions.total() > 0) {
- if (result.isOk())
- stream << '\n';
printResultType();
printOriginalExpression();
printReconstructedExpression();
@@ -12748,7 +13551,7 @@ public:
case Unit::Nanoseconds:
return "ns";
case Unit::Microseconds:
- return "µs";
+ return "us";
case Unit::Milliseconds:
return "ms";
case Unit::Seconds:
@@ -13197,6 +14000,13 @@ namespace Catch {
void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
CumulativeReporterBase::testRunStarting( runInfo );
xml.startElement( "testsuites" );
+ if( m_config->rngSeed() != 0 ) {
+ xml.startElement( "properties" );
+ xml.scopedElement( "property" )
+ .writeAttribute( "name", "random-seed" )
+ .writeAttribute( "value", m_config->rngSeed() );
+ xml.endElement();
+ }
}
void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
@@ -13781,7 +14591,7 @@ int main (int argc, char * const argv[]) {
#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
-#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ )
+#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
@@ -13795,7 +14605,7 @@ int main (int argc, char * const argv[]) {
#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
-#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ )
+#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
@@ -13825,6 +14635,18 @@ int main (int argc, char * const argv[]) {
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#endif
+
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
@@ -13878,6 +14700,7 @@ int main (int argc, char * const argv[]) {
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
@@ -13892,6 +14715,18 @@ int main (int argc, char * const argv[]) {
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#endif
+
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
@@ -13970,6 +14805,18 @@ using Catch::Detail::Approx;
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#endif
+
// "BDD-style" convenience wrappers
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
@@ -14032,6 +14879,18 @@ using Catch::Detail::Approx;
#define SUCCEED( ... ) (void)(0)
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#endif
+
#define STATIC_REQUIRE( ... ) (void)(0)
#define STATIC_REQUIRE_FALSE( ... ) (void)(0)