Package: dd-opentracing-cpp Version: 1.3.1-1 Severity: serious Tags: patch experimental Justification: FTBFS User: ubuntu-de...@lists.ubuntu.com Usertags: origin-ubuntu jammy ubuntu-patch
Hi Stephen, dd-opentracing-cpp fails to build from source against glibc 2.34 or later because MINSIGSTKSZ is no longer a compile-time constant: [...] In file included from /usr/include/signal.h:328, from /<<PKGBUILDDIR>>/3rd_party/include/catch2/catch.hpp:7955, from /<<PKGBUILDDIR>>/test/test_main.cpp:2: /<<PKGBUILDDIR>>/3rd_party/include/catch2/catch.hpp:10735:58: error: call to non -‘constexpr’ function ‘long int sysconf(int)’ 10735 | static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; | ^~~~~~~~~~~ In file included from /usr/include/x86_64-linux-gnu/bits/sigstksz.h:24, from /usr/include/signal.h:328, from /<<PKGBUILDDIR>>/3rd_party/include/catch2/catch.hpp:7955, from /<<PKGBUILDDIR>>/test/test_main.cpp:2: /usr/include/unistd.h:640:17: note: ‘long int sysconf(int)’ declared here 640 | extern long int sysconf (int __name) __THROW; | ^~~~~~~ In file included from /<<PKGBUILDDIR>>/test/test_main.cpp:2: /<<PKGBUILDDIR>>/3rd_party/include/catch2/catch.hpp:10794:45: error: size of array ‘altStackMem’ is not an integral constant-expression 10794 | char FatalConditionHandler::altStackMem[sigStackSize] = {}; | ^~~~~~~~~~~~ make[3]: *** [test/CMakeFiles/catch.dir/build.make:79: test/CMakeFiles/catch.dir/test_main.cpp.o] Error 1 [...] (https://launchpad.net/ubuntu/+source/dd-opentracing-cpp/1.3.1-1/+build/22380587) glibc 2.34 is currently only in experimental in Debian, but this package will need fixed to be buildable once it reaches unstable. I've applied the attached patch in Ubuntu to fix this build failure, which simply consists of vendorizing a new version of the Catch2 header that includes the upstream fix for this problem. Thanks for considering, -- Steve Langasek Give me a lever long enough and a Free OS Debian Developer to set it on, and I can move the world. Ubuntu Developer https://www.debian.org/ slanga...@ubuntu.com vor...@debian.org
diff -Nru dd-opentracing-cpp-1.3.1/debian/patches/series dd-opentracing-cpp-1.3.1/debian/patches/series --- dd-opentracing-cpp-1.3.1/debian/patches/series 1969-12-31 16:00:00.000000000 -0800 +++ dd-opentracing-cpp-1.3.1/debian/patches/series 2022-04-13 13:47:02.000000000 -0700 @@ -0,0 +1 @@ +update-catch2.patch diff -Nru dd-opentracing-cpp-1.3.1/debian/patches/update-catch2.patch dd-opentracing-cpp-1.3.1/debian/patches/update-catch2.patch --- dd-opentracing-cpp-1.3.1/debian/patches/update-catch2.patch 1969-12-31 16:00:00.000000000 -0800 +++ dd-opentracing-cpp-1.3.1/debian/patches/update-catch2.patch 2022-04-13 13:48:11.000000000 -0700 @@ -0,0 +1,2725 @@ +Description: import catch2 version 2.13.8 to fix build failure with glibc 2.34 +Author: Steve Langasek <steve.langa...@ubuntu.com> +Last-Update: 2022-04-13 +Forwarded: no + +Index: dd-opentracing-cpp-1.3.1/3rd_party/include/catch2/catch.hpp +=================================================================== +--- dd-opentracing-cpp-1.3.1.orig/3rd_party/include/catch2/catch.hpp ++++ dd-opentracing-cpp-1.3.1/3rd_party/include/catch2/catch.hpp +@@ -1,9 +1,9 @@ + /* +- * Catch v2.11.1 +- * Generated: 2019-12-28 21:22:11.930976 ++ * Catch v2.13.8 ++ * Generated: 2022-01-03 21:20:09.589503 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly +- * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. ++ * Copyright (c) 2022 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 11 +-#define CATCH_VERSION_PATCH 1 ++#define CATCH_VERSION_MINOR 13 ++#define CATCH_VERSION_PATCH 8 + + #ifdef __clang__ + # pragma clang system_header +@@ -66,13 +66,16 @@ + #if !defined(CATCH_CONFIG_IMPL_ONLY) + // start catch_platform.h + ++// See e.g.: ++// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html + #ifdef __APPLE__ +-# include <TargetConditionals.h> +-# if TARGET_OS_OSX == 1 +-# define CATCH_PLATFORM_MAC +-# elif TARGET_OS_IPHONE == 1 +-# define CATCH_PLATFORM_IPHONE +-# endif ++# include <TargetConditionals.h> ++# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ ++ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) ++# define CATCH_PLATFORM_MAC ++# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) ++# define CATCH_PLATFORM_IPHONE ++# endif + + #elif defined(linux) || defined(__linux) || defined(__linux__) + # define CATCH_PLATFORM_LINUX +@@ -132,15 +135,14 @@ + + #endif + +-#if defined(CATCH_CPP17_OR_GREATER) +-# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +-#endif +- +-// We have to avoid both ICC and Clang, because they try to mask themselves +-// as gcc, and we want only GCC in this block +-#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) ++// Only GCC compiler should be used in this block, so other compilers trying to ++// mask themselves as GCC should be ignored. ++#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) + # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) + # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) ++ ++# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) ++ + #endif + + #if defined(__clang__) +@@ -148,6 +150,21 @@ + # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) + # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + ++// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug ++// which results in calls to destructors being emitted for each temporary, ++// without a matching initialization. In practice, this can result in something ++// like `std::string::~string` being called on an uninitialized value. ++// ++// For example, this code will likely segfault under IBM XL: ++// ``` ++// REQUIRE(std::string("12") + "34" == "1234") ++// ``` ++// ++// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. ++# if !defined(__ibmxl__) && !defined(__CUDACC__) ++# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ ++# endif ++ + # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") +@@ -223,13 +240,6 @@ + // Visual C++ + #if defined(_MSC_VER) + +-# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +-# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) +- +-# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +-# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +-# endif +- + // Universal Windows platform does not support SEH + // Or console colours (or console at all...) + # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +@@ -238,13 +248,18 @@ + # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH + # endif + ++# if !defined(__clang__) // Handle Clang masquerading for msvc ++ + // 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(__clang__) // Handle Clang masquerading for msvc + # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) + # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + # endif // MSVC_TRADITIONAL ++ ++// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` ++# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) ++# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + # endif // __clang__ + + #endif // _MSC_VER +@@ -294,7 +309,7 @@ + #define CATCH_CONFIG_COLOUR_NONE + #endif + +-#if defined(__UCLIBC__) ++#if !defined(_GLIBCXX_USE_C99_MATH_TR1) + #define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER + #endif + +@@ -312,7 +327,10 @@ + + // Check if byte is available and usable + # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) +- # define CATCH_INTERNAL_CONFIG_CPP17_BYTE ++ # include <cstddef> ++ # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) ++ # define CATCH_INTERNAL_CONFIG_CPP17_BYTE ++ # endif + # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable +@@ -355,10 +373,6 @@ + # 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 +- + #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) + # define CATCH_CONFIG_CPP17_STRING_VIEW + #endif +@@ -420,6 +434,12 @@ + # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS + #endif + ++// The goal of this macro is to avoid evaluation of the arguments, but ++// still have the compiler warn on problems inside... ++#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) ++# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) ++#endif ++ + #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) + # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS + #elif defined(__clang__) && (__clang_major__ < 5) +@@ -751,7 +771,7 @@ + #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) + #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) + #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +-#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) ++#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) + #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) + #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) + #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +@@ -920,13 +940,13 @@ + + #if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 + // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is +- // replaced with std::invoke_result here. Also *_t format is preferred over +- // typename *::type format. +- template <typename Func, typename U> +- using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>; ++ // replaced with std::invoke_result here. ++ template <typename Func, typename... U> ++ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>; + #else +- template <typename Func, typename U> +- using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type; ++ // Keep ::type here because we still support C++11 ++ template <typename Func, typename... U> ++ using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type; + #endif + + } // namespace Catch +@@ -992,34 +1012,34 @@ + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ +- INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_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, typename TestType, __VA_ARGS__ ) ++ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_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, typename TestType, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ +- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_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, typename TestType, __VA_ARGS__ ) ) ++ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_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, typename TestType, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ +- INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_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, Signature, __VA_ARGS__ ) ++ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_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, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ +- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_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, Signature, __VA_ARGS__ ) ) ++ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_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, Signature, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ +- INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_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, typename T, __VA_ARGS__ ) ++ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_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, typename T, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ +- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_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, typename T, __VA_ARGS__ ) ) ++ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_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, typename T, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ +- INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_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, Signature, __VA_ARGS__ ) ++ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_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, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ +- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_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, Signature, __VA_ARGS__ ) ) ++ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_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, Signature, __VA_ARGS__ ) ) + #endif + #endif + +@@ -1032,7 +1052,7 @@ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE( ... ) \ +- INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) ++ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ +@@ -1054,7 +1074,7 @@ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + void TestName::test() + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ +- INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) ++ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ +@@ -1081,7 +1101,7 @@ + int index = 0; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ + using expander = int[];\ +- (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \ ++ (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ +@@ -1095,18 +1115,18 @@ + + #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, typename TestType, __VA_ARGS__ ) ++ 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, typename TestType, __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, typename TestType, __VA_ARGS__ ) ) ++ 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, typename TestType, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ +- 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, Signature, __VA_ARGS__ ) ++ 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, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ +- 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, Signature, __VA_ARGS__ ) ) ++ 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, Signature, __VA_ARGS__ ) ) + #endif + + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \ +@@ -1127,7 +1147,7 @@ + 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 */\ ++ (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++)... };/* NOLINT */\ + } \ + }; \ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ +@@ -1144,18 +1164,18 @@ + + #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, typename T,__VA_ARGS__) ++ 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, typename T,__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, typename T, __VA_ARGS__ ) ) ++ 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, typename T, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ +- 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, Signature, __VA_ARGS__) ++ 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, Signature, __VA_ARGS__) + #else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ +- 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, Signature, __VA_ARGS__ ) ) ++ 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, Signature, __VA_ARGS__ ) ) + #endif + + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\ +@@ -1171,7 +1191,7 @@ + void reg_tests() { \ + int index = 0; \ + using expander = int[]; \ +- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */\ ++ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ + } \ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ +@@ -1186,7 +1206,7 @@ + static void TestFunc() + + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \ +- INTERNAL_CATCH_TEMPLATE_LIST_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, TmplList ) ++ INTERNAL_CATCH_TEMPLATE_LIST_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, TmplList ) + + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ +@@ -1205,7 +1225,7 @@ + int index = 0; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ + using expander = int[];\ +- (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \ ++ (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ +@@ -1219,18 +1239,18 @@ + + #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, typename T, __VA_ARGS__ ) ++ 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, typename T, __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, typename T, __VA_ARGS__ ) ) ++ 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, typename T, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ +- 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, Signature, __VA_ARGS__ ) ++ 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, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ +- 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, Signature, __VA_ARGS__ ) ) ++ 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, Signature, __VA_ARGS__ ) ) + #endif + + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\ +@@ -1254,7 +1274,7 @@ + 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 */ \ ++ (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++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ +@@ -1271,18 +1291,18 @@ + + #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, typename T, __VA_ARGS__ ) ++ 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, typename T, __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, typename T,__VA_ARGS__ ) ) ++ 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, typename T,__VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ +- 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, Signature, __VA_ARGS__ ) ++ 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, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ +- 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, Signature,__VA_ARGS__ ) ) ++ 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, Signature,__VA_ARGS__ ) ) + #endif + + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \ +@@ -1301,7 +1321,7 @@ + void reg_tests(){\ + int index = 0;\ + using expander = int[];\ +- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */ \ ++ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ +@@ -1316,7 +1336,7 @@ + void TestName<TestType>::test() + + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \ +- INTERNAL_CATCH_TEMPLATE_LIST_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, TmplList ) ++ INTERNAL_CATCH_TEMPLATE_LIST_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, TmplList ) + + // end catch_test_registry.h + // start catch_capture.hpp +@@ -1805,8 +1825,8 @@ + #endif + + namespace Detail { +- template<typename InputIterator> +- std::string rangeToString(InputIterator first, InputIterator last) { ++ template<typename InputIterator, typename Sentinel = InputIterator> ++ std::string rangeToString(InputIterator first, Sentinel last) { + ReusableStringStream rss; + rss << "{ "; + if (first != last) { +@@ -1964,20 +1984,27 @@ + #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER + + namespace Catch { +- struct not_this_one {}; // Tag type for detecting which begin/ end are being selected +- +- // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace ++ // Import begin/ end from std here + using std::begin; + using std::end; + +- not_this_one begin( ... ); +- not_this_one end( ... ); ++ namespace detail { ++ template <typename...> ++ struct void_type { ++ using type = void; ++ }; ++ ++ template <typename T, typename = void> ++ struct is_range_impl : std::false_type { ++ }; ++ ++ template <typename T> ++ struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type { ++ }; ++ } // namespace detail + + template <typename T> +- struct is_range { +- static const bool value = +- !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value && +- !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value; ++ struct is_range : detail::is_range_impl<T> { + }; + + #if defined(_MANAGED) // Managed types are never ranges +@@ -2345,6 +2372,18 @@ + auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs }; + } ++ template <typename RhsT> ++ auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { ++ return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs }; ++ } ++ template <typename RhsT> ++ auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { ++ return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs }; ++ } ++ template <typename RhsT> ++ auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { ++ return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs }; ++ } + + template<typename RhsT> + auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { +@@ -2425,7 +2464,7 @@ + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + +- virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; ++ virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; + + #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + virtual void benchmarkPreparing( std::string const& name ) = 0; +@@ -2663,6 +2702,7 @@ + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ + do { \ ++ CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ +@@ -2671,8 +2711,7 @@ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + } 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 +- // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. ++ } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ +@@ -2989,6 +3028,9 @@ + {} + + std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { ++#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) ++ return ""; ++#else + try { + if( it == itEnd ) + std::rethrow_exception(std::current_exception()); +@@ -2998,6 +3040,7 @@ + catch( T& ex ) { + return m_translateFunction( ex ); + } ++#endif + } + + protected: +@@ -3050,7 +3093,7 @@ + Approx operator-() const; + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> +- Approx operator()( T const& value ) { ++ Approx operator()( T const& value ) const { + Approx approx( static_cast<double>(value) ); + approx.m_epsilon = m_epsilon; + approx.m_margin = m_margin; +@@ -3266,9 +3309,10 @@ + return description; + } + +- MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { +- m_matchers.push_back( &other ); +- return *this; ++ MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) { ++ auto copy(*this); ++ copy.m_matchers.push_back( &other ); ++ return copy; + } + + std::vector<MatcherBase<ArgT> const*> m_matchers; +@@ -3299,9 +3343,10 @@ + return description; + } + +- MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { +- m_matchers.push_back( &other ); +- return *this; ++ MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) { ++ auto copy(*this); ++ copy.m_matchers.push_back( &other ); ++ return copy; + } + + std::vector<MatcherBase<ArgT> const*> m_matchers; +@@ -3558,12 +3603,12 @@ + namespace Matchers { + + namespace Vector { +- template<typename T> +- struct ContainsElementMatcher : MatcherBase<std::vector<T>> { ++ template<typename T, typename Alloc> ++ struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> { + + ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} + +- bool match(std::vector<T> const &v) const override { ++ bool match(std::vector<T, Alloc> const &v) const override { + for (auto const& el : v) { + if (el == m_comparator) { + return true; +@@ -3579,12 +3624,12 @@ + T const& m_comparator; + }; + +- template<typename T> +- struct ContainsMatcher : MatcherBase<std::vector<T>> { ++ template<typename T, typename AllocComp, typename AllocMatch> ++ struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> { + +- ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} ++ ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} + +- bool match(std::vector<T> const &v) const override { ++ bool match(std::vector<T, AllocMatch> const &v) const override { + // !TBD: see note in EqualsMatcher + if (m_comparator.size() > v.size()) + return false; +@@ -3606,18 +3651,18 @@ + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + +- std::vector<T> const& m_comparator; ++ std::vector<T, AllocComp> const& m_comparator; + }; + +- template<typename T> +- struct EqualsMatcher : MatcherBase<std::vector<T>> { ++ template<typename T, typename AllocComp, typename AllocMatch> ++ struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { + +- EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} ++ EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} + +- bool match(std::vector<T> const &v) const override { ++ bool match(std::vector<T, AllocMatch> const &v) const override { + // !TBD: This currently works if all elements can be compared using != + // - a more general approach would be via a compare template that defaults +- // to using !=. but could be specialised for, e.g. std::vector<T> etc ++ // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc + // - then just call that directly + if (m_comparator.size() != v.size()) + return false; +@@ -3629,15 +3674,15 @@ + std::string describe() const override { + return "Equals: " + ::Catch::Detail::stringify( m_comparator ); + } +- std::vector<T> const& m_comparator; ++ std::vector<T, AllocComp> const& m_comparator; + }; + +- template<typename T> +- struct ApproxMatcher : MatcherBase<std::vector<T>> { ++ template<typename T, typename AllocComp, typename AllocMatch> ++ struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> { + +- ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {} ++ ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {} + +- bool match(std::vector<T> const &v) const override { ++ bool match(std::vector<T, AllocMatch> const &v) const override { + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) +@@ -3664,16 +3709,14 @@ + return *this; + } + +- std::vector<T> const& m_comparator; ++ std::vector<T, AllocComp> const& m_comparator; + mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); + }; + +- template<typename T> +- struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> { +- UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {} +- bool match(std::vector<T> const& vec) const override { +- // Note: This is a reimplementation of std::is_permutation, +- // because I don't want to include <algorithm> inside the common path ++ template<typename T, typename AllocComp, typename AllocMatch> ++ struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { ++ UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {} ++ bool match(std::vector<T, AllocMatch> const& vec) const override { + if (m_target.size() != vec.size()) { + return false; + } +@@ -3684,7 +3727,7 @@ + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: +- std::vector<T> const& m_target; ++ std::vector<T, AllocComp> const& m_target; + }; + + } // namespace Vector +@@ -3692,29 +3735,29 @@ + // The following functions create the actual matcher objects. + // This allows the types to be inferred + +- template<typename T> +- Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { +- return Vector::ContainsMatcher<T>( comparator ); ++ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> ++ Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) { ++ return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator ); + } + +- template<typename T> +- Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { +- return Vector::ContainsElementMatcher<T>( comparator ); ++ template<typename T, typename Alloc = std::allocator<T>> ++ Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) { ++ return Vector::ContainsElementMatcher<T, Alloc>( comparator ); + } + +- template<typename T> +- Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { +- return Vector::EqualsMatcher<T>( comparator ); ++ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> ++ Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) { ++ return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator ); + } + +- template<typename T> +- Vector::ApproxMatcher<T> Approx( std::vector<T> const& comparator ) { +- return Vector::ApproxMatcher<T>( comparator ); ++ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> ++ Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) { ++ return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator ); + } + +- template<typename T> +- Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) { +- return Vector::UnorderedEqualsMatcher<T>(target); ++ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> ++ Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) { ++ return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target ); + } + + } // namespace Matchers +@@ -4033,16 +4076,16 @@ + return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); + } + +- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; ++ auto acquireGeneratorTracker( StringRef generatorName, 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()) { ++ auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { + using UnderlyingType = typename decltype(generatorExpression())::type; + +- IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); ++ IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); + if (!tracker.hasGenerator()) { + tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); + } +@@ -4055,11 +4098,17 @@ + } // namespace Catch + + #define GENERATE( ... ) \ +- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) ++ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ ++ CATCH_INTERNAL_LINEINFO, \ ++ [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + #define GENERATE_COPY( ... ) \ +- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) ++ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ ++ CATCH_INTERNAL_LINEINFO, \ ++ [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + #define GENERATE_REF( ... ) \ +- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) ++ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ ++ CATCH_INTERNAL_LINEINFO, \ ++ [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + + // end catch_generators.hpp + // start catch_generators_generic.hpp +@@ -4116,7 +4165,7 @@ + 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(); ++ auto has_initial_value = nextImpl(); + if (!has_initial_value) { + Catch::throw_exception(GeneratorException("No valid value found in filtered generator")); + } +@@ -4128,6 +4177,11 @@ + } + + bool next() override { ++ return nextImpl(); ++ } ++ ++ private: ++ bool nextImpl() { + bool success = m_generator.next(); + if (!success) { + return false; +@@ -4411,6 +4465,7 @@ + } // end namespace Catch + + // end catch_option.hpp ++#include <chrono> + #include <iosfwd> + #include <string> + #include <vector> +@@ -4468,6 +4523,7 @@ + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; ++ virtual double minDuration() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; + virtual std::vector<std::string> const& getTestsOrTags() const = 0; +@@ -4481,6 +4537,7 @@ + virtual int benchmarkSamples() const = 0; + virtual double benchmarkConfidenceInterval() const = 0; + virtual unsigned int benchmarkResamples() const = 0; ++ virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; + }; + + using IConfigPtr = std::shared_ptr<IConfig const>; +@@ -5234,10 +5291,12 @@ + unsigned int benchmarkSamples = 100; + double benchmarkConfidenceInterval = 0.95; + unsigned int benchmarkResamples = 100000; ++ std::chrono::milliseconds::rep benchmarkWarmupTime = 100; + + Verbosity verbosity = Verbosity::Normal; + WarnAbout::What warnings = WarnAbout::Nothing; + ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; ++ double minDuration = -1; + RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; + UseColour::YesOrNo useColour = UseColour::Auto; + WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; +@@ -5288,6 +5347,7 @@ + bool warnAboutMissingAssertions() const override; + bool warnAboutNoTests() const override; + ShowDurations::OrNot showDurations() const override; ++ double minDuration() const override; + RunTests::InWhatOrder runOrder() const override; + unsigned int rngSeed() const override; + UseColour::YesOrNo useColour() const override; +@@ -5299,6 +5359,7 @@ + int benchmarkSamples() const override; + double benchmarkConfidenceInterval() const override; + unsigned int benchmarkResamples() const override; ++ std::chrono::milliseconds benchmarkWarmupTime() const override; + + private: + +@@ -5404,6 +5465,8 @@ + } // namespace Catch + + // end catch_outlier_classification.hpp ++ ++#include <iterator> + #endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + #include <string> +@@ -5664,6 +5727,9 @@ + // Returns double formatted as %.3f (format expected on output) + std::string getFormattedDuration( double duration ); + ++ //! Should the reporter show ++ bool shouldShowDuration( IConfig const& config, double duration ); ++ + std::string serializeFilters( std::vector<std::string> const& container ); + + template<typename DerivedT> +@@ -6057,8 +6123,6 @@ + + static std::string getDescription(); + +- ReporterPreferences getPreferences() const override; +- + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; +@@ -6287,9 +6351,10 @@ + + void writeTestCase(TestCaseNode const& testCaseNode); + +- void writeSection(std::string const& className, +- std::string const& rootName, +- SectionNode const& sectionNode); ++ void writeSection( std::string const& className, ++ std::string const& rootName, ++ SectionNode const& sectionNode, ++ bool testOkToFail ); + + void writeAssertions(SectionNode const& sectionNode); + void writeAssertion(AssertionStats const& stats); +@@ -6506,20 +6571,18 @@ + return {}; + } + }; +- template <typename Sig> +- using ResultOf_t = typename std::result_of<Sig>::type; + + // invoke and not return void :( + template <typename Fun, typename... Args> +- CompleteType_t<ResultOf_t<Fun(Args...)>> complete_invoke(Fun&& fun, Args&&... args) { +- return CompleteInvoker<ResultOf_t<Fun(Args...)>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...); ++ CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) { ++ return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...); + } + + const std::string benchmarkErrorMsg = "a benchmark failed to run successfully"; + } // namespace Detail + + template <typename Fun> +- Detail::CompleteType_t<Detail::ResultOf_t<Fun()>> user_code(Fun&& fun) { ++ Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) { + CATCH_TRY{ + return Detail::complete_invoke(std::forward<Fun>(fun)); + } CATCH_CATCH_ALL{ +@@ -6764,8 +6827,8 @@ + Result result; + int iterations; + }; +- template <typename Clock, typename Sig> +- using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<Detail::ResultOf_t<Sig>>>; ++ template <typename Clock, typename Func, typename... Args> ++ using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>; + } // namespace Benchmark + } // namespace Catch + +@@ -6776,7 +6839,7 @@ + namespace Benchmark { + namespace Detail { + template <typename Clock, typename Fun, typename... Args> +- TimingOf<Clock, Fun(Args...)> measure(Fun&& fun, Args&&... args) { ++ TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) { + auto start = Clock::now(); + auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...); + auto end = Clock::now(); +@@ -6795,11 +6858,11 @@ + namespace Benchmark { + namespace Detail { + template <typename Clock, typename Fun> +- TimingOf<Clock, Fun(int)> measure_one(Fun&& fun, int iters, std::false_type) { ++ TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) { + return Detail::measure<Clock>(fun, iters); + } + template <typename Clock, typename Fun> +- TimingOf<Clock, Fun(Chronometer)> measure_one(Fun&& fun, int iters, std::true_type) { ++ TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) { + Detail::ChronometerModel<Clock> meter; + auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); + +@@ -6816,7 +6879,7 @@ + }; + + template <typename Clock, typename Fun> +- TimingOf<Clock, Fun(run_for_at_least_argument_t<Clock, Fun>)> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) { ++ TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) { + auto iters = seed; + while (iters < (1 << 30)) { + auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>()); +@@ -6826,7 +6889,7 @@ + } + iters *= 2; + } +- throw optimized_away_error{}; ++ Catch::throw_exception(optimized_away_error{}); + } + } // namespace Detail + } // namespace Benchmark +@@ -6834,6 +6897,7 @@ + + // end catch_run_for_at_least.hpp + #include <algorithm> ++#include <iterator> + + namespace Catch { + namespace Benchmark { +@@ -6884,11 +6948,13 @@ + #include <algorithm> + #include <functional> + #include <vector> ++#include <iterator> + #include <numeric> + #include <tuple> + #include <cmath> + #include <utility> + #include <cstddef> ++#include <random> + + namespace Catch { + namespace Benchmark { +@@ -7002,8 +7068,8 @@ + double b2 = bias - z1; + double a1 = a(b1); + double a2 = a(b2); +- auto lo = std::max(cumn(a1), 0); +- auto hi = std::min(cumn(a2), n - 1); ++ auto lo = (std::max)(cumn(a1), 0); ++ auto hi = (std::min)(cumn(a2), n - 1); + + return { point, resample[lo], resample[hi], confidence_level }; + } +@@ -7072,7 +7138,9 @@ + } + template <typename Clock> + EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) { +- auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit)); ++ auto time_limit = (std::min)( ++ resolution * clock_cost_estimation_tick_limit, ++ FloatDuration<Clock>(clock_cost_estimation_time_limit)); + auto time_clock = [](int k) { + return Detail::measure<Clock>([k] { + for (int i = 0; i < k; ++i) { +@@ -7238,10 +7306,10 @@ + template <typename Clock> + ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { + auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; +- auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(Detail::warmup_time)); ++ auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime())); + auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun); + int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed)); +- return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(Detail::warmup_time), Detail::warmup_iterations }; ++ return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; + } + + template <typename Clock = default_clock> +@@ -7412,23 +7480,37 @@ + SourceLineInfo location; + + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); ++ friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { ++ return lhs.name == rhs.name ++ && lhs.location == rhs.location; ++ } + }; + +- struct ITracker; ++ class ITracker; + + using ITrackerPtr = std::shared_ptr<ITracker>; + +- struct ITracker { +- virtual ~ITracker(); ++ class ITracker { ++ NameAndLocation m_nameAndLocation; ++ ++ public: ++ ITracker(NameAndLocation const& nameAndLoc) : ++ m_nameAndLocation(nameAndLoc) ++ {} + + // static queries +- virtual NameAndLocation const& nameAndLocation() const = 0; ++ NameAndLocation const& nameAndLocation() const { ++ return m_nameAndLocation; ++ } ++ ++ virtual ~ITracker(); + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; ++ virtual bool hasStarted() const = 0; + + virtual ITracker& parent() = 0; + +@@ -7483,7 +7565,6 @@ + }; + + using Children = std::vector<ITrackerPtr>; +- NameAndLocation m_nameAndLocation; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; +@@ -7492,11 +7573,13 @@ + public: + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + +- NameAndLocation const& nameAndLocation() const override; + bool isComplete() const override; + bool isSuccessfullyCompleted() const override; + bool isOpen() const override; + bool hasChildren() const override; ++ bool hasStarted() const override { ++ return m_runState != NotStarted; ++ } + + void addChild( ITrackerPtr const& child ) override; + +@@ -7535,6 +7618,10 @@ + + void addInitialFilters( std::vector<std::string> const& filters ); + void addNextFilters( std::vector<std::string> const& filters ); ++ //! Returns filters active in this tracker ++ std::vector<std::string> const& getFilters() const; ++ //! Returns whitespace-trimmed name of the tracked section ++ std::string const& trimmedName() const; + }; + + } // namespace TestCaseTracking +@@ -7700,7 +7787,7 @@ + double sb = stddev.point; + double mn = mean.point / n; + double mg_min = mn / 2.; +- double sg = std::min(mg_min / 4., sb / std::sqrt(n)); ++ double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); + double sg2 = sg * sg; + double sb2 = sb * sb; + +@@ -7719,7 +7806,7 @@ + return (nc / n) * (sb2 - nc * sg2); + }; + +- return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2; ++ return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; + } + + bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) { +@@ -7859,7 +7946,11 @@ + + #ifdef CATCH_PLATFORM_MAC + +- #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ ++ #if defined(__i386__) || defined(__x86_64__) ++ #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ ++ #elif defined(__aarch64__) ++ #define CATCH_TRAP() __asm__(".inst 0xd4200000") ++ #endif + + #elif defined(CATCH_PLATFORM_IPHONE) + +@@ -7868,8 +7959,10 @@ + #define CATCH_TRAP() __asm__("int $3") + #elif defined(__aarch64__) + #define CATCH_TRAP() __asm__(".inst 0xd4200000") +- #elif defined(__arm__) ++ #elif defined(__arm__) && !defined(__thumb__) + #define CATCH_TRAP() __asm__(".inst 0xe7f001f0") ++ #elif defined(__arm__) && defined(__thumb__) ++ #define CATCH_TRAP() __asm__(".inst 0xde01") + #endif + + #elif defined(CATCH_PLATFORM_LINUX) +@@ -7890,10 +7983,12 @@ + #define CATCH_TRAP() DebugBreak() + #endif + +-#ifdef CATCH_TRAP +- #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() +-#else +- #define CATCH_BREAK_INTO_DEBUGGER() []{}() ++#ifndef CATCH_BREAK_INTO_DEBUGGER ++ #ifdef CATCH_TRAP ++ #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() ++ #else ++ #define CATCH_BREAK_INTO_DEBUGGER() []{}() ++ #endif + #endif + + // end catch_debugger.h +@@ -7901,86 +7996,58 @@ + + // start catch_fatal_condition.h + +-// start catch_windows_h_proxy.h +- +- +-#if defined(CATCH_PLATFORM_WINDOWS) +- +-#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +-# define CATCH_DEFINED_NOMINMAX +-# define NOMINMAX +-#endif +-#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +-# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +-# define WIN32_LEAN_AND_MEAN +-#endif +- +-#ifdef __AFXDLL +-#include <AfxWin.h> +-#else +-#include <windows.h> +-#endif +- +-#ifdef CATCH_DEFINED_NOMINMAX +-# undef NOMINMAX +-#endif +-#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +-# undef WIN32_LEAN_AND_MEAN +-#endif +- +-#endif // defined(CATCH_PLATFORM_WINDOWS) +- +-// end catch_windows_h_proxy.h +-#if defined( CATCH_CONFIG_WINDOWS_SEH ) ++#include <cassert> + + namespace Catch { + +- struct FatalConditionHandler { +- +- static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); ++ // Wrapper for platform-specific fatal error (signals/SEH) handlers ++ // ++ // Tries to be cooperative with other handlers, and not step over ++ // other handlers. This means that unknown structured exceptions ++ // are passed on, previous signal handlers are called, and so on. ++ // ++ // Can only be instantiated once, and assumes that once a signal ++ // is caught, the binary will end up terminating. Thus, there ++ class FatalConditionHandler { ++ bool m_started = false; ++ ++ // Install/disengage implementation for specific platform. ++ // Should be if-defed to work on current platform, can assume ++ // engage-disengage 1:1 pairing. ++ void engage_platform(); ++ void disengage_platform(); ++ public: ++ // Should also have platform-specific implementations as needed + FatalConditionHandler(); +- static void reset(); + ~FatalConditionHandler(); + +- private: +- static bool isSet; +- static ULONG guaranteeSize; +- static PVOID exceptionHandlerHandle; +- }; +- +-} // namespace Catch +- +-#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) +- +-#include <signal.h> +- +-namespace Catch { +- +- struct FatalConditionHandler { +- +- static bool isSet; +- static struct sigaction oldSigActions[]; +- static stack_t oldSigStack; +- static char altStackMem[]; +- +- static void handleSignal( int sig ); ++ void engage() { ++ assert(!m_started && "Handler cannot be installed twice."); ++ m_started = true; ++ engage_platform(); ++ } + +- FatalConditionHandler(); +- ~FatalConditionHandler(); +- static void reset(); ++ void disengage() { ++ assert(m_started && "Handler cannot be uninstalled without being installed first"); ++ m_started = false; ++ disengage_platform(); ++ } + }; + +-} // namespace Catch +- +-#else +- +-namespace Catch { +- struct FatalConditionHandler { +- void reset(); ++ //! Simple RAII guard for (dis)engaging the FatalConditionHandler ++ class FatalConditionHandlerGuard { ++ FatalConditionHandler* m_handler; ++ public: ++ FatalConditionHandlerGuard(FatalConditionHandler* handler): ++ m_handler(handler) { ++ m_handler->engage(); ++ } ++ ~FatalConditionHandlerGuard() { ++ m_handler->disengage(); ++ } + }; +-} + +-#endif ++} // end namespace Catch + + // end catch_fatal_condition.h + #include <string> +@@ -8040,7 +8107,7 @@ + void sectionEnded( SectionEndInfo const& endInfo ) override; + void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + +- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; ++ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + + #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing( std::string const& name ) override; +@@ -8106,6 +8173,7 @@ + std::vector<SectionEndInfo> m_unfinishedSections; + std::vector<ITracker*> m_activeSections; + TrackerContext m_trackerContext; ++ FatalConditionHandler m_fatalConditionhandler; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; +@@ -9016,7 +9084,7 @@ + } + 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>( std::tolower(c) ); } ); ++ std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned 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") +@@ -9665,8 +9733,7 @@ + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + config.testsOrTags.push_back( line ); +- config.testsOrTags.push_back( "," ); +- ++ config.testsOrTags.emplace_back( "," ); + } + } + //Remove comma in the end +@@ -9707,14 +9774,16 @@ + }; + auto const setWaitForKeypress = [&]( std::string const& keypress ) { + auto keypressLc = toLower( keypress ); +- if( keypressLc == "start" ) ++ if (keypressLc == "never") ++ config.waitForKeypress = WaitForKeypress::Never; ++ else if( keypressLc == "start" ) + config.waitForKeypress = WaitForKeypress::BeforeStart; + else if( keypressLc == "exit" ) + config.waitForKeypress = WaitForKeypress::BeforeExit; + else if( keypressLc == "both" ) + config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; + else +- return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); ++ return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setVerbosity = [&]( std::string const& verbosity ) { +@@ -9784,6 +9853,9 @@ + | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) + ["-d"]["--durations"] + ( "show test durations" ) ++ | Opt( config.minDuration, "seconds" ) ++ ["-D"]["--min-duration"] ++ ( "show test durations for tests taking at least the given number of seconds" ) + | Opt( loadTestNamesFromFile, "filename" ) + ["-f"]["--input-file"] + ( "load test names to run from a file" ) +@@ -9814,7 +9886,7 @@ + | Opt( config.libIdentify ) + ["--libidentify"] + ( "report name and version according to libidentify standard" ) +- | Opt( setWaitForKeypress, "start|exit|both" ) ++ | Opt( setWaitForKeypress, "never|start|exit|both" ) + ["--wait-for-keypress"] + ( "waits for a keypress before exiting" ) + | Opt( config.benchmarkSamples, "samples" ) +@@ -9829,7 +9901,10 @@ + | Opt( config.benchmarkNoAnalysis ) + ["--benchmark-no-analysis"] + ( "perform only measurements; do not perform any analysis" ) +- | Arg( config.testsOrTags, "test name|pattern|tags" ) ++ | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" ) ++ ["--benchmark-warmup-time"] ++ ( "amount of time in milliseconds spent on warming up each test (default: 100)" ) ++ | Arg( config.testsOrTags, "test name|pattern|tags" ) + ( "which test or tests to use" ); + + return cli; +@@ -9928,6 +10003,7 @@ + bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } + bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } + ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } ++ double Config::minDuration() const { return m_data.minDuration; } + RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } + unsigned int Config::rngSeed() const { return m_data.rngSeed; } + UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } +@@ -9936,10 +10012,11 @@ + bool Config::showInvisibles() const { return m_data.showInvisibles; } + Verbosity Config::verbosity() const { return m_data.verbosity; } + +- bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } +- int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } +- double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } +- unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } ++ bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } ++ int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } ++ double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } ++ unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } ++ std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); } + + IStream const* Config::openStream() { + return Catch::makeStream(m_data.outputFilename); +@@ -9969,6 +10046,36 @@ + } + + // end catch_errno_guard.h ++// start catch_windows_h_proxy.h ++ ++ ++#if defined(CATCH_PLATFORM_WINDOWS) ++ ++#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) ++# define CATCH_DEFINED_NOMINMAX ++# define NOMINMAX ++#endif ++#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) ++# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN ++# define WIN32_LEAN_AND_MEAN ++#endif ++ ++#ifdef __AFXDLL ++#include <AfxWin.h> ++#else ++#include <windows.h> ++#endif ++ ++#ifdef CATCH_DEFINED_NOMINMAX ++# undef NOMINMAX ++#endif ++#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN ++# undef WIN32_LEAN_AND_MEAN ++#endif ++ ++#endif // defined(CATCH_PLATFORM_WINDOWS) ++ ++// end catch_windows_h_proxy.h + #include <sstream> + + namespace Catch { +@@ -9980,7 +10087,7 @@ + }; + + struct NoColourImpl : IColourImpl { +- void use( Colour::Code ) {} ++ void use( Colour::Code ) override {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; +@@ -10153,13 +10260,13 @@ + namespace Catch { + + Colour::Colour( Code _colourCode ) { use( _colourCode ); } +- Colour::Colour( Colour&& rhs ) noexcept { +- m_moved = rhs.m_moved; +- rhs.m_moved = true; +- } +- Colour& Colour::operator=( Colour&& rhs ) noexcept { +- m_moved = rhs.m_moved; +- rhs.m_moved = true; ++ Colour::Colour( Colour&& other ) noexcept { ++ m_moved = other.m_moved; ++ other.m_moved = true; ++ } ++ Colour& Colour::operator=( Colour&& other ) noexcept { ++ m_moved = other.m_moved; ++ other.m_moved = true; + return *this; + } + +@@ -10171,7 +10278,7 @@ + // However, under some conditions it does happen (see #1626), + // and this change is small enough that we can let practicality + // triumph over purity in this case. +- if (impl != NULL) { ++ if (impl != nullptr) { + impl->use( _colourCode ); + } + } +@@ -10291,8 +10398,7 @@ + + #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) + +-# include <assert.h> +-# include <stdbool.h> ++# include <cassert> + # include <sys/types.h> + # include <unistd.h> + # include <cstddef> +@@ -10486,7 +10592,7 @@ + // Extracts the actual name part of an enum instance + // In other words, it returns the Blue part of Bikeshed::Colour::Blue + StringRef extractInstanceName(StringRef enumInstance) { +- // Find last occurence of ":" ++ // Find last occurrence of ":" + size_t name_start = enumInstance.size(); + while (name_start > 0 && enumInstance[name_start - 1] != ':') { + --name_start; +@@ -10524,7 +10630,7 @@ + assert( valueNames.size() == values.size() ); + std::size_t i = 0; + for( auto value : values ) +- enumInfo->m_values.push_back({ value, valueNames[i++] }); ++ enumInfo->m_values.emplace_back(value, valueNames[i++]); + + return enumInfo; + } +@@ -10648,25 +10754,47 @@ + // end catch_exception_translator_registry.cpp + // start catch_fatal_condition.cpp + +-#if defined(__GNUC__) +-# pragma GCC diagnostic push +-# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +-#endif ++#include <algorithm> ++ ++#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) ++ ++namespace Catch { ++ ++ // If neither SEH nor signal handling is required, the handler impls ++ // do not have to do anything, and can be empty. ++ void FatalConditionHandler::engage_platform() {} ++ void FatalConditionHandler::disengage_platform() {} ++ FatalConditionHandler::FatalConditionHandler() = default; ++ FatalConditionHandler::~FatalConditionHandler() = default; ++ ++} // end namespace Catch ++ ++#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS ++ ++#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) ++#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" ++#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS + + #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) + + namespace { +- // Report the error condition ++ //! Signals fatal error message to the run context + void reportFatal( char const * const message ) { + Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); + } +-} + +-#endif // signals/SEH handling ++ //! Minimal size Catch2 needs for its own fatal error handling. ++ //! Picked anecdotally, so it might not be sufficient on all ++ //! platforms, and for all configurations. ++ constexpr std::size_t minStackSizeForErrors = 32 * 1024; ++} // end unnamed namespace ++ ++#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS + + #if defined( CATCH_CONFIG_WINDOWS_SEH ) + + namespace Catch { ++ + struct SignalDefs { DWORD id; const char* name; }; + + // There is no 1-1 mapping between signals and windows exceptions. +@@ -10679,7 +10807,7 @@ + { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, + }; + +- LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { ++ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (auto const& def : signalDefs) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { + reportFatal(def.name); +@@ -10690,38 +10818,50 @@ + return EXCEPTION_CONTINUE_SEARCH; + } + ++ // Since we do not support multiple instantiations, we put these ++ // into global variables and rely on cleaning them up in outlined ++ // constructors/destructors ++ static PVOID exceptionHandlerHandle = nullptr; ++ ++ // For MSVC, we reserve part of the stack memory for handling ++ // memory overflow structured exception. + FatalConditionHandler::FatalConditionHandler() { +- isSet = true; +- // 32k seems enough for Catch to handle stack overflow, +- // but the value was found experimentally, so there is no strong guarantee +- guaranteeSize = 32 * 1024; +- exceptionHandlerHandle = nullptr; ++ ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors); ++ if (!SetThreadStackGuarantee(&guaranteeSize)) { ++ // We do not want to fully error out, because needing ++ // the stack reserve should be rare enough anyway. ++ Catch::cerr() ++ << "Failed to reserve piece of stack." ++ << " Stack overflows will not be reported successfully."; ++ } ++ } ++ ++ // We do not attempt to unset the stack guarantee, because ++ // Windows does not support lowering the stack size guarantee. ++ FatalConditionHandler::~FatalConditionHandler() = default; ++ ++ void FatalConditionHandler::engage_platform() { + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); +- // Pass in guarantee size to be filled +- SetThreadStackGuarantee(&guaranteeSize); ++ if (!exceptionHandlerHandle) { ++ CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); ++ } + } + +- void FatalConditionHandler::reset() { +- if (isSet) { +- RemoveVectoredExceptionHandler(exceptionHandlerHandle); +- SetThreadStackGuarantee(&guaranteeSize); +- exceptionHandlerHandle = nullptr; +- isSet = false; ++ void FatalConditionHandler::disengage_platform() { ++ if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { ++ CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); + } ++ exceptionHandlerHandle = nullptr; + } + +- FatalConditionHandler::~FatalConditionHandler() { +- reset(); +- } ++} // end namespace Catch + +-bool FatalConditionHandler::isSet = false; +-ULONG FatalConditionHandler::guaranteeSize = 0; +-PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; ++#endif // CATCH_CONFIG_WINDOWS_SEH + +-} // namespace Catch ++#if defined( CATCH_CONFIG_POSIX_SIGNALS ) + +-#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) ++#include <signal.h> + + namespace Catch { + +@@ -10730,10 +10870,6 @@ + const char* name; + }; + +- // 32kb for the alternate stack seems to be sufficient. However, this value +- // is experimentally determined, so that's not guaranteed. +- static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; +- + static SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, +@@ -10743,7 +10879,32 @@ + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + +- void FatalConditionHandler::handleSignal( int sig ) { ++// Older GCCs trigger -Wmissing-field-initializers for T foo = {} ++// which is zero initialization, but not explicit. We want to avoid ++// that. ++#if defined(__GNUC__) ++# pragma GCC diagnostic push ++# pragma GCC diagnostic ignored "-Wmissing-field-initializers" ++#endif ++ ++ static char* altStackMem = nullptr; ++ static std::size_t altStackSize = 0; ++ static stack_t oldSigStack{}; ++ static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; ++ ++ static void restorePreviousSignalHandlers() { ++ // We set signal handlers back to the previous ones. Hopefully ++ // nobody overwrote them in the meantime, and doesn't expect ++ // their signal handlers to live past ours given that they ++ // installed them after ours.. ++ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { ++ sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); ++ } ++ // Return the old stack ++ sigaltstack(&oldSigStack, nullptr); ++ } ++ ++ static void handleSignal( int sig ) { + char const * name = "<unknown signal>"; + for (auto const& def : signalDefs) { + if (sig == def.id) { +@@ -10751,16 +10912,33 @@ + break; + } + } +- reset(); +- reportFatal(name); ++ // We need to restore previous signal handlers and let them do ++ // their thing, so that the users can have the debugger break ++ // when a signal is raised, and so on. ++ restorePreviousSignalHandlers(); ++ reportFatal( name ); + raise( sig ); + } + + FatalConditionHandler::FatalConditionHandler() { +- isSet = true; ++ assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists"); ++ if (altStackSize == 0) { ++ altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors); ++ } ++ altStackMem = new char[altStackSize](); ++ } ++ ++ FatalConditionHandler::~FatalConditionHandler() { ++ delete[] altStackMem; ++ // We signal that another instance can be constructed by zeroing ++ // out the pointer. ++ altStackMem = nullptr; ++ } ++ ++ void FatalConditionHandler::engage_platform() { + stack_t sigStack; + sigStack.ss_sp = altStackMem; +- sigStack.ss_size = sigStackSize; ++ sigStack.ss_size = altStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { }; +@@ -10772,40 +10950,17 @@ + } + } + +- FatalConditionHandler::~FatalConditionHandler() { +- reset(); +- } ++#if defined(__GNUC__) ++# pragma GCC diagnostic pop ++#endif + +- void FatalConditionHandler::reset() { +- if( isSet ) { +- // Set signals back to previous values -- hopefully nobody overwrote them in the meantime +- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { +- sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); +- } +- // Return the old stack +- sigaltstack(&oldSigStack, nullptr); +- isSet = false; +- } ++ void FatalConditionHandler::disengage_platform() { ++ restorePreviousSignalHandlers(); + } + +- bool FatalConditionHandler::isSet = false; +- struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; +- stack_t FatalConditionHandler::oldSigStack = {}; +- char FatalConditionHandler::altStackMem[sigStackSize] = {}; +- +-} // namespace Catch +- +-#else +- +-namespace Catch { +- void FatalConditionHandler::reset() {} +-} +- +-#endif // signals/SEH handling ++} // end namespace Catch + +-#if defined(__GNUC__) +-# pragma GCC diagnostic pop +-#endif ++#endif // CATCH_CONFIG_POSIX_SIGNALS + // end catch_fatal_condition.cpp + // start catch_generators.cpp + +@@ -10824,8 +10979,8 @@ + + GeneratorUntypedBase::~GeneratorUntypedBase() {} + +- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { +- return getResultCapture().acquireGeneratorTracker( lineInfo ); ++ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { ++ return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); + } + + } // namespace Generators +@@ -11100,7 +11255,7 @@ + namespace Catch { + + std::size_t listTests( Config const& config ) { +- TestSpec testSpec = config.testSpec(); ++ TestSpec const& testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { +@@ -11134,7 +11289,7 @@ + } + + std::size_t listTestsNamesOnly( Config const& config ) { +- TestSpec testSpec = config.testSpec(); ++ TestSpec const& testSpec = config.testSpec(); + std::size_t matchedTests = 0; + std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { +@@ -11172,7 +11327,7 @@ + } + + std::size_t listTags( Config const& config ) { +- TestSpec testSpec = config.testSpec(); ++ TestSpec const& testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { +@@ -11360,20 +11515,13 @@ + return lhs == rhs; + } + +- auto ulpDiff = std::abs(lc - rc); ++ // static cast as a workaround for IBM XLC ++ auto ulpDiff = std::abs(static_cast<FP>(lc - rc)); + return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff; + } + +-} //end anonymous namespace +- + #if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) + +-#if defined(__clang__) +-#pragma clang diagnostic push +-// The long double overload is currently unused +-#pragma clang diagnostic ignored "-Wunused-function" +-#endif +- + float nextafter(float x, float y) { + return ::nextafterf(x, y); + } +@@ -11382,18 +11530,8 @@ + return ::nextafter(x, y); + } + +- long double nextafter(long double x, long double y) { +- return ::nextafterl(x, y); +- } +- +-#if defined(__clang__) +-#pragma clang diagnostic pop +-#endif +- + #endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ + +-namespace { +- + template <typename FP> + FP step(FP start, FP direction, uint64_t steps) { + for (uint64_t i = 0; i < steps; ++i) { +@@ -11552,7 +11690,6 @@ + + } // namespace Matchers + } // namespace Catch +- + // end catch_matchers_floating.cpp + // start catch_matchers_generic.cpp + +@@ -11730,10 +11867,10 @@ + + Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { + auto trimmed = [&] (size_t start, size_t end) { +- while (names[start] == ',' || isspace(names[start])) { ++ while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) { + ++start; + } +- while (names[end] == ',' || isspace(names[end])) { ++ while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) { + --end; + } + return names.substr(start, end - start + 1); +@@ -11772,7 +11909,7 @@ + pos = skipq(pos, c); + break; + case ',': +- if (start != pos && openings.size() == 0) { ++ if (start != pos && openings.empty()) { + m_messages.emplace_back(macroName, lineInfo, resultType); + m_messages.back().message = static_cast<std::string>(trimmed(start, pos)); + m_messages.back().message += " := "; +@@ -11780,7 +11917,7 @@ + } + } + } +- assert(openings.size() == 0 && "Mismatched openings"); ++ assert(openings.empty() && "Mismatched openings"); + m_messages.emplace_back(macroName, lineInfo, resultType); + m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1)); + m_messages.back().message += " := "; +@@ -11968,7 +12105,7 @@ + if (tmpnam_s(m_buffer)) { + CATCH_RUNTIME_ERROR("Could not get a temp filename"); + } +- if (fopen_s(&m_file, m_buffer, "w")) { ++ if (fopen_s(&m_file, m_buffer, "w+")) { + char buffer[100]; + if (strerror_s(buffer, errno)) { + CATCH_RUNTIME_ERROR("Could not translate errno to a string"); +@@ -12263,11 +12400,13 @@ + namespace Catch { + + class StartupExceptionRegistry { ++#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + public: + void add(std::exception_ptr const& exception) noexcept; + std::vector<std::exception_ptr> const& getExceptions() const noexcept; + private: + std::vector<std::exception_ptr> m_exceptions; ++#endif + }; + + } // end namespace Catch +@@ -12350,7 +12489,11 @@ + m_tagAliasRegistry.add( alias, tag, lineInfo ); + } + void registerStartupException() noexcept override { ++#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + m_exceptionRegistry.add(std::current_exception()); ++#else ++ CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); ++#endif + } + IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { + return m_enumValuesRegistry; +@@ -12454,17 +12597,32 @@ + std::shared_ptr<GeneratorTracker> tracker; + + ITracker& currentTracker = ctx.currentTracker(); +- if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { ++ // Under specific circumstances, the generator we want ++ // to acquire is also the current tracker. If this is ++ // the case, we have to avoid looking through current ++ // tracker's children, and instead return the current ++ // tracker. ++ // A case where this check is important is e.g. ++ // for (int i = 0; i < 5; ++i) { ++ // int n = GENERATE(1, 2); ++ // } ++ // ++ // without it, the code above creates 5 nested generators. ++ if (currentTracker.nameAndLocation() == nameAndLocation) { ++ auto thisTracker = currentTracker.parent().findChild(nameAndLocation); ++ assert(thisTracker); ++ assert(thisTracker->isGeneratorTracker()); ++ tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker); ++ } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isGeneratorTracker() ); + tracker = std::static_pointer_cast<GeneratorTracker>( childTracker ); +- } +- else { ++ } else { + tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( tracker ); + } + +- if( !ctx.completedCycle() && !tracker->isComplete() ) { ++ if( !tracker->isComplete() ) { + tracker->open(); + } + +@@ -12478,8 +12636,68 @@ + } + void close() override { + TrackerBase::close(); +- // Generator interface only finds out if it has another item on atual move +- if (m_runState == CompletedSuccessfully && m_generator->next()) { ++ // If a generator has a child (it is followed by a section) ++ // and none of its children have started, then we must wait ++ // until later to start consuming its values. ++ // This catches cases where `GENERATE` is placed between two ++ // `SECTION`s. ++ // **The check for m_children.empty cannot be removed**. ++ // doing so would break `GENERATE` _not_ followed by `SECTION`s. ++ const bool should_wait_for_child = [&]() { ++ // No children -> nobody to wait for ++ if ( m_children.empty() ) { ++ return false; ++ } ++ // If at least one child started executing, don't wait ++ if ( std::find_if( ++ m_children.begin(), ++ m_children.end(), ++ []( TestCaseTracking::ITrackerPtr tracker ) { ++ return tracker->hasStarted(); ++ } ) != m_children.end() ) { ++ return false; ++ } ++ ++ // No children have started. We need to check if they _can_ ++ // start, and thus we should wait for them, or they cannot ++ // start (due to filters), and we shouldn't wait for them ++ auto* parent = m_parent; ++ // This is safe: there is always at least one section ++ // tracker in a test case tracking tree ++ while ( !parent->isSectionTracker() ) { ++ parent = &( parent->parent() ); ++ } ++ assert( parent && ++ "Missing root (test case) level section" ); ++ ++ auto const& parentSection = ++ static_cast<SectionTracker&>( *parent ); ++ auto const& filters = parentSection.getFilters(); ++ // No filters -> no restrictions on running sections ++ if ( filters.empty() ) { ++ return true; ++ } ++ ++ for ( auto const& child : m_children ) { ++ if ( child->isSectionTracker() && ++ std::find( filters.begin(), ++ filters.end(), ++ static_cast<SectionTracker&>( *child ) ++ .trimmedName() ) != ++ filters.end() ) { ++ return true; ++ } ++ } ++ return false; ++ }(); ++ ++ // This check is a bit tricky, because m_generator->next() ++ // has a side-effect, where it consumes generator's current ++ // value, but we do not want to invoke the side-effect if ++ // this generator is still waiting for any child to start. ++ if ( should_wait_for_child || ++ ( m_runState == CompletedSuccessfully && ++ m_generator->next() ) ) { + m_children.clear(); + m_runState = Executing; + } +@@ -12615,10 +12833,10 @@ + + return true; + } +- auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { ++ auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + using namespace Generators; +- GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); +- assert( tracker.isOpen() ); ++ GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, ++ TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) ); + m_lastAssertionInfo.lineInfo = lineInfo; + return tracker; + } +@@ -12661,17 +12879,17 @@ + + #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void RunContext::benchmarkPreparing(std::string const& name) { +- m_reporter->benchmarkPreparing(name); +- } ++ m_reporter->benchmarkPreparing(name); ++ } + void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { + m_reporter->benchmarkStarting( info ); + } + void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { + m_reporter->benchmarkEnded( stats ); + } +- void RunContext::benchmarkFailed(std::string const & error) { +- m_reporter->benchmarkFailed(error); +- } ++ void RunContext::benchmarkFailed(std::string const & error) { ++ m_reporter->benchmarkFailed(error); ++ } + #endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + void RunContext::pushScopedMessage(MessageInfo const & message) { +@@ -12805,9 +13023,8 @@ + } + + void RunContext::invokeActiveTestCase() { +- FatalConditionHandler fatalConditionHandler; // Handle signals ++ FatalConditionHandlerGuard _(&m_fatalConditionhandler); + m_activeTestCase->invoke(); +- fatalConditionHandler.reset(); + } + + void RunContext::handleUnfinishedSections() { +@@ -13268,11 +13485,11 @@ + char **utf8Argv = new char *[ argc ]; + + for ( int i = 0; i < argc; ++i ) { +- int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); ++ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr ); + + utf8Argv[ i ] = new char[ bufSize ]; + +- WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); ++ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr ); + } + + int returnCode = applyCommandLine( argc, utf8Argv ); +@@ -13392,6 +13609,7 @@ + // end catch_singletons.cpp + // start catch_startup_exception_registry.cpp + ++#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + namespace Catch { + void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { + CATCH_TRY { +@@ -13407,6 +13625,7 @@ + } + + } // end namespace Catch ++#endif + // end catch_startup_exception_registry.cpp + // start catch_stream.cpp + +@@ -13591,7 +13810,7 @@ + + namespace { + char toLowerCh(char c) { +- return static_cast<char>( std::tolower( c ) ); ++ return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) ); + } + } + +@@ -13871,7 +14090,8 @@ + } + } + if( isHidden ) { +- tags.push_back( "." ); ++ // Add all "hidden" tags to make them behave identically ++ tags.insert( tags.end(), { ".", "!hide" } ); + } + + TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo ); +@@ -13966,27 +14186,81 @@ + // end catch_test_case_info.cpp + // start catch_test_case_registry_impl.cpp + ++#include <algorithm> + #include <sstream> + + namespace Catch { + +- std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { ++ namespace { ++ struct TestHasher { ++ using hash_t = uint64_t; + +- std::vector<TestCase> sorted = unsortedTestCases; ++ explicit TestHasher( hash_t hashSuffix ): ++ m_hashSuffix{ hashSuffix } {} + ++ uint32_t operator()( TestCase const& t ) const { ++ // FNV-1a hash with multiplication fold. ++ const hash_t prime = 1099511628211u; ++ hash_t hash = 14695981039346656037u; ++ for ( const char c : t.name ) { ++ hash ^= c; ++ hash *= prime; ++ } ++ hash ^= m_hashSuffix; ++ hash *= prime; ++ const uint32_t low{ static_cast<uint32_t>( hash ) }; ++ const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) }; ++ return low * high; ++ } ++ ++ private: ++ hash_t m_hashSuffix; ++ }; ++ } // end unnamed namespace ++ ++ std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { + switch( config.runOrder() ) { +- case RunTests::InLexicographicalOrder: +- std::sort( sorted.begin(), sorted.end() ); +- break; +- case RunTests::InRandomOrder: +- seedRng( config ); +- std::shuffle( sorted.begin(), sorted.end(), rng() ); +- break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; ++ ++ case RunTests::InLexicographicalOrder: { ++ std::vector<TestCase> sorted = unsortedTestCases; ++ std::sort( sorted.begin(), sorted.end() ); ++ return sorted; ++ } ++ ++ case RunTests::InRandomOrder: { ++ seedRng( config ); ++ TestHasher h{ config.rngSeed() }; ++ ++ using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>; ++ std::vector<hashedTest> indexed_tests; ++ indexed_tests.reserve( unsortedTestCases.size() ); ++ ++ for (auto const& testCase : unsortedTestCases) { ++ indexed_tests.emplace_back(h(testCase), &testCase); ++ } ++ ++ std::sort(indexed_tests.begin(), indexed_tests.end(), ++ [](hashedTest const& lhs, hashedTest const& rhs) { ++ if (lhs.first == rhs.first) { ++ return lhs.second->name < rhs.second->name; ++ } ++ return lhs.first < rhs.first; ++ }); ++ ++ std::vector<TestCase> sorted; ++ sorted.reserve( indexed_tests.size() ); ++ ++ for (auto const& hashed : indexed_tests) { ++ sorted.emplace_back(*hashed.second); ++ } ++ ++ return sorted; ++ } + } +- return sorted; ++ return unsortedTestCases; + } + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { +@@ -14123,15 +14397,12 @@ + m_currentTracker = tracker; + } + +- TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) +- : m_nameAndLocation( nameAndLocation ), ++ TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): ++ ITracker(nameAndLocation), + m_ctx( ctx ), + m_parent( parent ) + {} + +- NameAndLocation const& TrackerBase::nameAndLocation() const { +- return m_nameAndLocation; +- } + bool TrackerBase::isComplete() const { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } +@@ -14247,7 +14518,8 @@ + bool SectionTracker::isComplete() const { + bool complete = true; + +- if ((m_filters.empty() || m_filters[0] == "") ++ if (m_filters.empty() ++ || m_filters[0] == "" + || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { + complete = TrackerBase::isComplete(); + } +@@ -14282,8 +14554,8 @@ + void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) { + if( !filters.empty() ) { + m_filters.reserve( m_filters.size() + filters.size() + 2 ); +- m_filters.push_back(""); // Root - should never be consulted +- m_filters.push_back(""); // Test Case - not a section filter ++ m_filters.emplace_back(""); // Root - should never be consulted ++ m_filters.emplace_back(""); // Test Case - not a section filter + m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); + } + } +@@ -14292,6 +14564,14 @@ + m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); + } + ++ std::vector<std::string> const& SectionTracker::getFilters() const { ++ return m_filters; ++ } ++ ++ std::string const& SectionTracker::trimmedName() const { ++ return m_trimmed_name; ++ } ++ + } // namespace TestCaseTracking + + using TestCaseTracking::ITracker; +@@ -14580,6 +14860,7 @@ + m_pos = m_arg.size(); + m_substring.clear(); + m_patternName.clear(); ++ m_realPatternPos = 0; + return false; + } + endMode(); +@@ -14598,6 +14879,7 @@ + } + + m_patternName.clear(); ++ m_realPatternPos = 0; + + return token; + } +@@ -15024,11 +15306,48 @@ + // end catch_totals.cpp + // start catch_uncaught_exceptions.cpp + ++// start catch_config_uncaught_exceptions.hpp ++ ++// Copyright Catch2 Authors ++// Distributed under the Boost Software License, Version 1.0. ++// (See accompanying file LICENSE_1_0.txt or copy at ++// https://www.boost.org/LICENSE_1_0.txt) ++ ++// SPDX-License-Identifier: BSL-1.0 ++ ++#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP ++#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP ++ ++#if defined(_MSC_VER) ++# if _MSC_VER >= 1900 // Visual Studio 2015 or newer ++# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS ++# endif ++#endif ++ ++#include <exception> ++ ++#if defined(__cpp_lib_uncaught_exceptions) \ ++ && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) ++ ++# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS ++#endif // __cpp_lib_uncaught_exceptions ++ ++#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 ++ ++#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP ++// end catch_config_uncaught_exceptions.hpp + #include <exception> + + namespace Catch { + bool uncaught_exceptions() { +-#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) ++#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) ++ return false; ++#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + return std::uncaught_exceptions() > 0; + #else + return std::uncaught_exception(); +@@ -15068,7 +15387,7 @@ + } + + Version const& libraryVersion() { +- static Version version( 2, 11, 1, "", 0 ); ++ static Version version( 2, 13, 8, "", 0 ); + return version; + } + +@@ -15118,8 +15437,6 @@ + #include <iomanip> + #include <type_traits> + +-using uchar = unsigned char; +- + namespace Catch { + + namespace { +@@ -15192,7 +15509,7 @@ + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { +- uchar c = m_str[idx]; ++ unsigned char c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; +@@ -15252,7 +15569,7 @@ + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { +- uchar nc = m_str[idx + n]; ++ unsigned char nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } +@@ -15472,6 +15789,17 @@ + return std::string(buffer); + } + ++ bool shouldShowDuration( IConfig const& config, double duration ) { ++ if ( config.showDurations() == ShowDurations::Always ) { ++ return true; ++ } ++ if ( config.showDurations() == ShowDurations::Never ) { ++ return false; ++ } ++ const double min = config.minDuration(); ++ return min >= 0 && duration >= min; ++ } ++ + std::string serializeFilters( std::vector<std::string> const& container ) { + ReusableStringStream oss; + bool first = true; +@@ -15738,10 +16066,6 @@ + return "Reports test results on a single line, suitable for IDEs"; + } + +- ReporterPreferences CompactReporter::getPreferences() const { +- return m_reporterPrefs; +- } +- + void CompactReporter::noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } +@@ -15768,8 +16092,9 @@ + } + + void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { +- if (m_config->showDurations() == ShowDurations::Always) { +- stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; ++ double dur = _sectionStats.durationInSeconds; ++ if ( shouldShowDuration( *m_config, dur ) ) { ++ stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + } + +@@ -15981,15 +16306,11 @@ + static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; + static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; + +- uint64_t m_inNanoseconds; ++ double m_inNanoseconds; + Unit m_units; + + public: +- explicit Duration(double inNanoseconds, Unit units = Unit::Auto) +- : Duration(static_cast<uint64_t>(inNanoseconds), units) { +- } +- +- explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) ++ explicit Duration(double inNanoseconds, Unit units = Unit::Auto) + : m_inNanoseconds(inNanoseconds), + m_units(units) { + if (m_units == Unit::Auto) { +@@ -16018,7 +16339,7 @@ + case Unit::Minutes: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute); + default: +- return static_cast<double>(m_inNanoseconds); ++ return m_inNanoseconds; + } + } + auto unitsAsString() const -> std::string { +@@ -16137,7 +16458,7 @@ + else + { + return{ +- { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, ++ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, + { "samples mean std dev", 14, ColumnInfo::Right }, + { "iterations low mean low std dev", 14, ColumnInfo::Right }, + { "estimated high mean high std dev", 14, ColumnInfo::Right } +@@ -16193,8 +16514,9 @@ + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } +- if (m_config->showDurations() == ShowDurations::Always) { +- stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; ++ double dur = _sectionStats.durationInSeconds; ++ if (shouldShowDuration(*m_config, dur)) { ++ stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + if (m_headerPrinted) { + m_headerPrinted = false; +@@ -16454,8 +16776,10 @@ + } + + void ConsoleReporter::printTestFilters() { +- if (m_config->testSpec().hasFilters()) +- stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n'; ++ if (m_config->testSpec().hasFilters()) { ++ Colour guard(Colour::BrightYellow); ++ stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n'; ++ } + } + + CATCH_REGISTER_REPORTER("console", ConsoleReporter) +@@ -16476,6 +16800,7 @@ + #include <sstream> + #include <ctime> + #include <algorithm> ++#include <iomanip> + + namespace Catch { + +@@ -16503,7 +16828,7 @@ + #else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); + #endif +- return std::string(timeStamp); ++ return std::string(timeStamp, timeStampSize-1); + } + + std::string fileNameTag(const std::vector<std::string> &tags) { +@@ -16514,6 +16839,17 @@ + return it->substr(1); + return std::string(); + } ++ ++ // Formats the duration in seconds to 3 decimal places. ++ // This is done because some genius defined Maven Surefire schema ++ // in a way that only accepts 3 decimal places, and tools like ++ // Jenkins use that schema for validation JUnit reporter output. ++ std::string formatDuration( double seconds ) { ++ ReusableStringStream rss; ++ rss << std::fixed << std::setprecision( 3 ) << seconds; ++ return rss.str(); ++ } ++ + } // anonymous namespace + + JunitReporter::JunitReporter( ReporterConfig const& _config ) +@@ -16583,7 +16919,7 @@ + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else +- xml.writeAttribute( "time", suiteTime ); ++ xml.writeAttribute( "time", formatDuration( suiteTime ) ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write properties if there are any +@@ -16628,12 +16964,13 @@ + if ( !m_config->name().empty() ) + className = m_config->name() + "." + className; + +- writeSection( className, "", rootSection ); ++ writeSection( className, "", rootSection, stats.testInfo.okToFail() ); + } + +- void JunitReporter::writeSection( std::string const& className, +- std::string const& rootName, +- SectionNode const& sectionNode ) { ++ void JunitReporter::writeSection( std::string const& className, ++ std::string const& rootName, ++ SectionNode const& sectionNode, ++ bool testOkToFail) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; +@@ -16650,7 +16987,17 @@ + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } +- xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); ++ xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) ); ++ // This is not ideal, but it should be enough to mimic gtest's ++ // junit output. ++ // Ideally the JUnit reporter would also handle `skipTest` ++ // events and write those out appropriately. ++ xml.writeAttribute( "status", "run" ); ++ ++ if (sectionNode.stats.assertions.failedButOk) { ++ xml.scopedElement("skipped") ++ .writeAttribute("message", "TEST_CASE tagged with !mayfail"); ++ } + + writeAssertions( sectionNode ); + +@@ -16661,9 +17008,9 @@ + } + for( auto const& childNode : sectionNode.childSections ) + if( className.empty() ) +- writeSection( name, "", *childNode ); ++ writeSection( name, "", *childNode, testOkToFail ); + else +- writeSection( className, name, *childNode ); ++ writeSection( className, name, *childNode, testOkToFail ); + } + + void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { +@@ -16681,11 +17028,7 @@ + elementName = "error"; + break; + case ResultWas::ExplicitFailure: +- elementName = "failure"; +- break; + case ResultWas::ExpressionFailed: +- elementName = "failure"; +- break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; +@@ -17089,6 +17432,10 @@ + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); ++ m_xml.scopedElement( "OverallResultsCases") ++ .writeAttribute( "successes", testGroupStats.totals.testCases.passed ) ++ .writeAttribute( "failures", testGroupStats.totals.testCases.failed ) ++ .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk ); + m_xml.endElement(); + } + +@@ -17098,6 +17445,10 @@ + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); ++ m_xml.scopedElement( "OverallResultsCases") ++ .writeAttribute( "successes", testRunStats.totals.testCases.passed ) ++ .writeAttribute( "failures", testRunStats.totals.testCases.failed ) ++ .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk ); + m_xml.endElement(); + } + +@@ -17111,16 +17462,16 @@ + m_xml.writeAttribute("samples", info.samples) + .writeAttribute("resamples", info.resamples) + .writeAttribute("iterations", info.iterations) +- .writeAttribute("clockResolution", static_cast<uint64_t>(info.clockResolution)) +- .writeAttribute("estimatedDuration", static_cast<uint64_t>(info.estimatedDuration)) ++ .writeAttribute("clockResolution", info.clockResolution) ++ .writeAttribute("estimatedDuration", info.estimatedDuration) + .writeComment("All values in nano seconds"); + } + + void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { + m_xml.startElement("mean") +- .writeAttribute("value", static_cast<uint64_t>(benchmarkStats.mean.point.count())) +- .writeAttribute("lowerBound", static_cast<uint64_t>(benchmarkStats.mean.lower_bound.count())) +- .writeAttribute("upperBound", static_cast<uint64_t>(benchmarkStats.mean.upper_bound.count())) ++ .writeAttribute("value", benchmarkStats.mean.point.count()) ++ .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count()) ++ .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count()) + .writeAttribute("ci", benchmarkStats.mean.confidence_interval); + m_xml.endElement(); + m_xml.startElement("standardDeviation") +@@ -17171,7 +17522,7 @@ + + #ifndef __OBJC__ + +-#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) ++#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) + // Standard C/C++ Win32 Unicode wmain entry point + extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { + #else +@@ -17304,9 +17655,9 @@ + + #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + #define CATCH_BENCHMARK(...) \ +- INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) ++ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) + #define CATCH_BENCHMARK_ADVANCED(name) \ +- INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) ++ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) + #endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +@@ -17408,9 +17759,9 @@ + + #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + #define BENCHMARK(...) \ +- INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) ++ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) + #define BENCHMARK_ADVANCED(name) \ +- INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) ++ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) + #endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + using Catch::Detail::Approx; +@@ -17457,8 +17808,8 @@ + #define CATCH_WARN( msg ) (void)(0) + #define CATCH_CAPTURE( msg ) (void)(0) + +-#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +-#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) ++#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) ++#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) + #define CATCH_SECTION( ... ) +@@ -17467,7 +17818,7 @@ + #define CATCH_FAIL_CHECK( ... ) (void)(0) + #define CATCH_SUCCEED( ... ) (void)(0) + +-#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) ++#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(__VA_ARGS__) +@@ -17490,8 +17841,8 @@ + #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 ) ++#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 ) + #define CATCH_GIVEN( desc ) + #define CATCH_AND_GIVEN( desc ) + #define CATCH_WHEN( desc ) +@@ -17541,8 +17892,8 @@ + #define WARN( msg ) (void)(0) + #define CAPTURE( msg ) (void)(0) + +-#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +-#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) ++#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) ++#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) + #define METHOD_AS_TEST_CASE( method, ... ) + #define REGISTER_TEST_CASE( Function, ... ) (void)(0) + #define SECTION( ... ) +@@ -17550,7 +17901,7 @@ + #define FAIL( ... ) (void)(0) + #define FAIL_CHECK( ... ) (void)(0) + #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____ )) ++#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(__VA_ARGS__) +@@ -17580,8 +17931,8 @@ + #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + + // "BDD-style" convenience wrappers +-#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) +-#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) ++#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) ) ++#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) + + #define GIVEN( desc ) + #define AND_GIVEN( desc )