From 4012b45d7c3cca5b42507c77e3033322b5dfab3d Mon Sep 17 00:00:00 2001 From: Marco Paland Date: Tue, 26 Mar 2019 08:46:44 +0100 Subject: chore(catch): update to catch2 2.7.0 --- test/catch.hpp | 1803 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 1331 insertions(+), 472 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 //////////////////////////////////////////////////////////////////////////////// @@ -240,6 +248,12 @@ namespace Catch { # define CATCH_INTERNAL_CONFIG_NO_WCHAR #endif // __DJGPP__ +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + //////////////////////////////////////////////////////////////////////////////// // Use of __COUNTER__ is suppressed during code analysis in @@ -260,6 +274,14 @@ namespace Catch { #endif #endif +//////////////////////////////////////////////////////////////////////////////// +// Check if optional is available and usable +#if defined(__has_include) +# if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL +# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // __has_include + //////////////////////////////////////////////////////////////////////////////// // Check if variant is available and usable #if defined(__has_include) @@ -270,9 +292,11 @@ namespace Catch { # include # 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() && 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 -#include namespace Catch { @@ -453,8 +488,6 @@ namespace Catch { virtual ~ITestInvoker(); }; - using ITestCasePtr = std::shared_ptr; - 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 + +namespace Catch{ + +#ifdef CATCH_CPP17_OR_GREATER + template + inline constexpr auto is_unique = std::true_type{}; + + template + inline constexpr auto is_unique = std::bool_constant< + (!std::is_same_v && ...) && is_unique + >{}; +#else + +template +struct is_unique : std::true_type{}; + +template +struct is_unique : std::integral_constant +::value + && is_unique::value + && is_unique::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 + +#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 + +namespace Catch { +template< typename... > +struct TypeList {}; + +template< typename... > +struct append; + +template< template class L1 + , typename...E1 + , template class L2 + , typename...E2 +> +struct append< L1, L2 > { + using type = L1; +}; + +template< template class L1 + , typename...E1 + , template class L2 + , typename...E2 + , typename...Rest +> +struct append< L1, L2, Rest...> { + using type = typename append< L1, Rest... >::type; +}; + +template< template class + , typename... +> +struct rewrap; + +template< template class Container + , template class List + , typename...elems +> +struct rewrap> { + using type = TypeList< Container< elems... > >; +}; + +template< template class Container + , template class List + , class...Elems + , typename...Elements> + struct rewrap, Elements...> { + using type = typename append>, typename rewrap::type>::type; +}; + +template< template class...Containers > +struct combine { + template< typename...Types > + struct with_types { + template< template class Final > + struct into { + using type = typename append, typename rewrap::type...>::type; + }; + }; +}; + +template +struct always_false : std::false_type {}; + +} // namespace Catch + +// end catch_meta.hpp namespace Catch { template @@ -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 \ + static void TestName() + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ + namespace{ \ + template \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName ) { \ + void test(); \ + }; \ + } \ + template \ + 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 \ + static void TestFunc();\ + namespace {\ + template \ + struct TestName{\ + template \ + 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 ), 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 \ + 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_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 static void TestFuncName(); \ + namespace { \ + template \ + 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 ), 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 \ + ::with_types::into::type; \ + TestInit(); \ + return 0; \ + }(); \ + } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + template \ + 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 \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName ) { \ + void test();\ + };\ + template \ + struct TestNameClass{\ + template \ + 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::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 \ + void TestName::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 \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName ) { \ + void test();\ + };\ + namespace {\ + template\ + 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::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\ + ::with_types::into::type;\ + TestInit();\ + return 0;\ + }(); \ + }\ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + template \ + void TestName::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 +namespace Catch { + template + struct StringMaker > { + static std::string convert(const std::optional& 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 @@ -1458,6 +1840,7 @@ struct ratio_string { #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 + auto operator && ( T ) const -> BinaryExpr const { + static_assert(always_false::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template + auto operator || ( T ) const -> BinaryExpr const { + static_assert(always_false::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template + auto operator == ( T ) const -> BinaryExpr const { + static_assert(always_false::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template + auto operator != ( T ) const -> BinaryExpr const { + static_assert(always_false::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template + auto operator > ( T ) const -> BinaryExpr const { + static_assert(always_false::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template + auto operator < ( T ) const -> BinaryExpr const { + static_assert(always_false::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template + auto operator >= ( T ) const -> BinaryExpr const { + static_assert(always_false::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template + auto operator <= ( T ) const -> BinaryExpr const { + static_assert(always_false::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } }; template @@ -1513,7 +1952,7 @@ namespace Catch { public: explicit UnaryExpr( LhsT lhs ) - : ITransientExpression{ false, lhs ? true : false }, + : ITransientExpression{ false, static_cast(lhs) }, m_lhs( lhs ) {} }; @@ -1580,6 +2019,20 @@ namespace Catch { return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; } + template + auto operator && ( RhsT const& ) -> BinaryExpr const { + static_assert(always_false::value, + "operator&& is not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template + auto operator || ( RhsT const& ) -> BinaryExpr const { + static_assert(always_false::value, + "operator|| is not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + auto makeUnaryExpr() const -> UnaryExpr { return UnaryExpr{ 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 - void captureValues( size_t index, T&& value ) { + void captureValues( size_t index, T const& value ) { captureValue( index, Catch::Detail::stringify( value ) ); } template - 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( !!(__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( !!(__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 &&. /////////////////////////////////////////////////////////////////////////////// @@ -1956,6 +2415,10 @@ namespace Catch { #define INTERNAL_CATCH_INFO( macroName, log ) \ 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, ... ) \ @@ -2453,10 +2916,6 @@ namespace Matchers { struct MatcherMethod { virtual bool match( ObjectT const& arg ) const = 0; }; - template - struct MatcherMethod { - 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; + using GeneratorBasePtr = std::unique_ptr; } // 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 #include +#include 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 - 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 - class SingleValueGenerator : public IGenerator { + class SingleValueGenerator final : public IGenerator { 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 - class FixedValuesGenerator : public IGenerator { + class FixedValuesGenerator final : public IGenerator { std::vector m_values; - + size_t m_idx = 0; public: FixedValuesGenerator( std::initializer_list 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 + class GeneratorWrapper final { + std::unique_ptr> m_generator; + public: + GeneratorWrapper(std::unique_ptr> generator): + m_generator(std::move(generator)) + {} + T const& get() const { + return m_generator->get(); + } + bool next() { + return m_generator->next(); + } + }; + + template + GeneratorWrapper value(T&& value) { + return GeneratorWrapper(pf::make_unique>(std::forward(value))); + } + template + GeneratorWrapper values(std::initializer_list values) { + return GeneratorWrapper(pf::make_unique>(values)); + } + template - class RangeGenerator : public IGenerator { - T const m_first; - T const m_last; + class Generators : public IGenerator { + std::vector> m_generators; + size_t m_current = 0; + + void populate(GeneratorWrapper&& generator) { + m_generators.emplace_back(std::move(generator)); + } + void populate(T&& val) { + m_generators.emplace_back(value(std::move(val))); + } + template + void populate(U&& val) { + populate(T(std::move(val))); + } + template + void populate(U&& valueOrGenerator, Gs... moreGenerators) { + populate(std::forward(valueOrGenerator)); + populate(std::forward(moreGenerators)...); + } public: - RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) { - assert( m_last > m_first ); + template + Generators(Gs... moreGenerators) { + m_generators.reserve(sizeof...(Gs)); + populate(std::forward(moreGenerators)...); } - auto get( size_t index ) const -> T override { - // ToDo:: introduce a safe cast to catch potential overflows - return static_cast(m_first+index); + T const& get() const override { + return m_generators[m_current].get(); } - }; - template - struct NullGenerator : IGenerator { - 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 + GeneratorWrapper> table( std::initializer_list::type...>> tuples ) { + return values>( tuples ); + } + + // Tag type to signal that a generator sequence should convert arguments to a specific type + template + struct as {}; + + template + auto makeGenerators( GeneratorWrapper&& generator, Gs... moreGenerators ) -> Generators { + return Generators(std::move(generator), std::forward(moreGenerators)...); + } template - class Generator { - std::unique_ptr> m_generator; - size_t m_size; + auto makeGenerators( GeneratorWrapper&& generator ) -> Generators { + return Generators(std::move(generator)); + } + template + auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators { + return makeGenerators( value( std::forward( val ) ), std::forward( moreGenerators )... ); + } + template + auto makeGenerators( as, U&& val, Gs... moreGenerators ) -> Generators { + return makeGenerators( value( T( std::forward( val ) ) ), std::forward( moreGenerators )... ); + } + + auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + + template + // 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().get()) { + using UnderlyingType = typename decltype(generatorExpression())::type; + + IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); + if (!tracker.hasGenerator()) { + tracker.setGenerator(pf::make_unique>(generatorExpression())); + } + + auto const& generator = static_cast 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 + class TakeGenerator : public IGenerator { + GeneratorWrapper m_generator; + size_t m_returned = 0; + size_t m_target; public: - Generator( size_t size, std::unique_ptr> generator ) - : m_generator( std::move( generator ) ), - m_size( size ) - {} + TakeGenerator(size_t target, GeneratorWrapper&& 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 randomiseIndices( size_t selectionSize, size_t sourceSize ); - - template - class GeneratorRandomiser : public IGenerator { - Generator m_baseGenerator; + template + GeneratorWrapper take(size_t target, GeneratorWrapper&& generator) { + return GeneratorWrapper(pf::make_unique>(target, std::move(generator))); + } - std::vector m_indices; + template + class FilterGenerator : public IGenerator { + GeneratorWrapper m_generator; + Predicate m_predicate; public: - GeneratorRandomiser( Generator&& baseGenerator, size_t numberOfItems ) - : m_baseGenerator( std::move( baseGenerator ) ), - m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) ) - {} + template + FilterGenerator(P&& pred, GeneratorWrapper&& generator): + m_generator(std::move(generator)), + m_predicate(std::forward

(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 - struct RequiresASpecialisationFor; + template + GeneratorWrapper filter(Predicate&& pred, GeneratorWrapper&& generator) { + return GeneratorWrapper(std::unique_ptr>(pf::make_unique>(std::forward(pred), std::move(generator)))); + } - template - auto all() -> Generator { return RequiresASpecialisationFor(); } + template + class RepeatGenerator : public IGenerator { + GeneratorWrapper m_generator; + mutable std::vector 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&& 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() -> Generator; + 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 - auto range( T const& first, T const& last ) -> Generator { - return Generator( (last-first), pf::make_unique>( 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 + GeneratorWrapper repeat(size_t repeats, GeneratorWrapper&& generator) { + return GeneratorWrapper(pf::make_unique>(repeats, std::move(generator))); } - template - auto random( T const& first, T const& last ) -> Generator { - auto gen = range( first, last ); - auto size = gen.size(); + template + class MapGenerator : public IGenerator { + // TBD: provide static assert for mapping function, for friendly error message + GeneratorWrapper m_generator; + Func m_function; + // To avoid returning dangling reference, we have to save the values + T m_cache; + public: + template + MapGenerator(F2&& function, GeneratorWrapper&& generator) : + m_generator(std::move(generator)), + m_function(std::forward(function)), + m_cache(m_function(m_generator.get())) + {} - return Generator( size, pf::make_unique>( std::move( gen ), size ) ); + 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; + } + }; + + template + GeneratorWrapper map(Func&& function, GeneratorWrapper&& generator) { + return GeneratorWrapper( + pf::make_unique>(std::forward(function), std::move(generator)) + ); } - template - auto random( size_t size ) -> Generator { - return Generator( size, pf::make_unique>( all(), size ) ); + template + GeneratorWrapper map(Func&& function, GeneratorWrapper&& generator) { + return GeneratorWrapper( + pf::make_unique>(std::forward(function), std::move(generator)) + ); } - template - auto values( std::initializer_list values ) -> Generator { - return Generator( values.size(), pf::make_unique>( values ) ); - } - template - auto value( T const& val ) -> Generator { - return Generator( 1, pf::make_unique>( val ) ); + template + class ChunkGenerator final : public IGenerator> { + std::vector m_chunk; + size_t m_chunk_size; + GeneratorWrapper m_generator; + bool m_used_up = false; + public: + ChunkGenerator(size_t size, GeneratorWrapper 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 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 + GeneratorWrapper> chunk(size_t size, GeneratorWrapper&& generator) { + return GeneratorWrapper>( + pf::make_unique>(size, std::move(generator)) + ); } - template - auto as() -> Generator { - return Generator( 0, pf::make_unique>() ); +} // namespace Generators +} // namespace Catch + +// end catch_generators_generic.hpp +// start catch_generators_specific.hpp + +// start catch_context.h + +#include + +namespace Catch { + + struct IResultCapture; + struct IRunner; + struct IConfig; + struct IMutableContext; + + using IConfigPtr = std::shared_ptr; + + 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 - auto table( std::initializer_list>&& tuples ) -> Generator> { - return values>( std::forward>>( tuples ) ); + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); } - template - struct Generators : GeneratorBase { - std::vector> m_generators; + void cleanUpContext(); +} - using type = T; +// end catch_context.h +// start catch_interfaces_config.h + +#include +#include +#include +#include - Generators() : GeneratorBase( 0 ) {} +namespace Catch { - void populate( T&& val ) { - m_size += 1; - m_generators.emplace_back( value( std::move( val ) ) ); - } - template - void populate( U&& val ) { - populate( T( std::move( val ) ) ); - } - void populate( Generator&& generator ) { - m_size += generator.size(); - m_generators.emplace_back( std::move( generator ) ); - } + enum class Verbosity { + Quiet = 0, + Normal, + High + }; - template - void populate( U&& valueOrGenerator, Gs... moreGenerators ) { - populate( std::forward( valueOrGenerator ) ); - populate( std::forward( moreGenerators )... ); - } + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01, + NoTests = 0x02 + }; }; - 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 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 const& getSectionsToRun() const = 0; + virtual Verbosity verbosity() const = 0; }; - template - auto makeGenerators( Generator&& generator, Gs... moreGenerators ) -> Generators { - Generators generators; - generators.m_generators.reserve( 1+sizeof...(Gs) ); - generators.populate( std::move( generator ), std::forward( moreGenerators )... ); - return generators; + using IConfigPtr = std::shared_ptr; +} + +// end catch_interfaces_config.h +#include + +namespace Catch { +namespace Generators { + +template +class RandomFloatingGenerator final : public IGenerator { + // FIXME: What is the right seed? + std::minstd_rand m_rand; + std::uniform_real_distribution m_dist; + Float m_current_number; +public: + + RandomFloatingGenerator(Float a, Float b): + m_rand(getCurrentContext().getConfig()->rngSeed()), + m_dist(a, b) { + static_cast(next()); } - template - auto makeGenerators( Generator&& generator ) -> Generators { - Generators generators; - generators.populate( std::move( generator ) ); - return generators; + + Float const& get() const override { + return m_current_number; } - template - auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators { - return makeGenerators( value( std::forward( val ) ), std::forward( moreGenerators )... ); + bool next() override { + m_current_number = m_dist(m_rand); + return true; } - template - auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators { - return makeGenerators( value( T( std::forward( val ) ) ), std::forward( moreGenerators )... ); +}; + +template +class RandomIntegerGenerator final : public IGenerator { + std::minstd_rand m_rand; + std::uniform_int_distribution m_dist; + Integer m_current_number; +public: + + RandomIntegerGenerator(Integer a, Integer b): + m_rand(getCurrentContext().getConfig()->rngSeed()), + m_dist(a, b) { + static_cast(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 - // 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()[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 std::enable_if::value && !std::is_same::value, +GeneratorWrapper>::type +random(T a, T b) { + return GeneratorWrapper( + pf::make_unique>(a, b) + ); +} - IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); - if( !tracker.hasGenerator() ) - tracker.setGenerator( pf::make_unique>( generatorExpression() ) ); +template +typename std::enable_if::value, +GeneratorWrapper>::type +random(T a, T b) { + return GeneratorWrapper( + pf::make_unique>(a, b) + ); +} + +template +class RangeGenerator final : public IGenerator { + T m_current; + T m_end; + T m_step; + bool m_positive; + +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 +GeneratorWrapper range(T const& start, T const& end, T const& step) { + static_assert(std::is_integral::value && !std::is_same::value, "Type must be an integer"); + return GeneratorWrapper(pf::make_unique>(start, end, step)); +} - auto const& generator = static_cast const&>( *tracker.getGenerator() ); - return generator[tracker.getIndex()]; - } +template +GeneratorWrapper range(T const& start, T const& end) { + static_assert(std::is_integral::value && !std::is_same::value, "Type must be an integer"); + return GeneratorWrapper(pf::make_unique>(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 -#include -#include -#include - -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 const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - }; - - using IConfigPtr = std::shared_ptr; -} - -// end catch_interfaces_config.h // Libstdc++ doesn't like incomplete classes for unique_ptr #include @@ -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( ReporterConfig const& _config ); + static std::set 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 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::convert(Catch::Detail::Approx co // end catch_approx.cpp // start catch_assertionhandler.cpp -// start catch_context.h - -#include - -namespace Catch { - - struct IResultCapture; - struct IRunner; - struct IConfig; - struct IMutableContext; - - using IConfigPtr = std::shared_ptr; - - 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 m_lastResult; IConfigPtr m_config; Totals m_totals; IStreamingReporterPtr m_reporter; std::vector m_messages; + std::vector m_messageScopes; /* Keeps owners of so-called unscoped messages. */ AssertionInfo m_lastAssertionInfo; std::vector m_unfinishedSections; std::vector 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 #include #include #include @@ -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( ::tolower(c) ); } ); + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( 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 randomiseIndices( size_t selectionSize, size_t sourceSize ) { +const char* GeneratorException::what() const noexcept { + return m_msg; +} - assert( selectionSize <= sourceSize ); - std::vector indices; - indices.reserve( selectionSize ); - std::uniform_int_distribution uid( 0, sourceSize-1 ); +namespace Generators { - std::set 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() -> Generator { - return range( std::numeric_limits::min(), std::numeric_limits::max() ); - } - } // namespace Generators } // namespace Catch // end catch_generators.cpp @@ -8346,7 +9078,7 @@ namespace Catch { std::size_t listReporters(); - Option list( Config const& config ); + Option list( std::shared_ptr const& config ); } // end namespace Catch @@ -8484,15 +9216,16 @@ namespace Catch { return factories.size(); } - Option list( Config const& config ) { + Option list( std::shared_ptr const& config ) { Option 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 @@ -8588,7 +9329,7 @@ template 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 +#include 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 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 + +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( -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( 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(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(new ListeningReporter); - + // On older platforms, returning std::unique_ptr + // when the return type is std::unique_ptr + // 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(new ListeningReporter); + auto& multi = static_cast(*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 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 listed = list( config() ) ) + if( Option listed = list( m_config ) ) return static_cast( *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 tracker; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = std::static_pointer_cast( childTracker ); - } - else { - tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); - currentTracker.addChild( tracker ); - } - - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); - } - - return *tracker; - } - - 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 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(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 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) -- cgit v1.2.3