summaryrefslogtreecommitdiffstats
path: root/libmemcached-awesome-catch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'libmemcached-awesome-catch.patch')
-rw-r--r--libmemcached-awesome-catch.patch957
1 files changed, 957 insertions, 0 deletions
diff --git a/libmemcached-awesome-catch.patch b/libmemcached-awesome-catch.patch
new file mode 100644
index 0000000..79e7d93
--- /dev/null
+++ b/libmemcached-awesome-catch.patch
@@ -0,0 +1,957 @@
+From ec4b275c7dab0af781c8e2571021d4821736eef9 Mon Sep 17 00:00:00 2001
+From: Michael Wallner <mike@php.net>
+Date: Fri, 25 Jun 2021 08:17:53 +0200
+Subject: [PATCH] fix gh issue #113
+
+---
+ ChangeLog-1.1.md | 8 +
+ docs/source/ChangeLog-1.1.rst | 12 +
+ scripts/download_catch2.sh | 5 +
+ test/lib/catch.hpp | 548 +++++++++++++++++++++-------------
+ 4 files changed, 368 insertions(+), 205 deletions(-)
+ create mode 100755 scripts/download_catch2.sh
+
+diff --git a/ChangeLog-1.1.md b/ChangeLog-1.1.md
+index c5ff5971..719140ff 100644
+--- a/ChangeLog-1.1.md
++++ b/ChangeLog-1.1.md
+@@ -1,5 +1,13 @@
+ # ChangeLog v1.1
+
++## v 1.1.1
++
++> released TBD
++
++* Fix [gh #113](https://github.com/awesomized/libmemcached/issues/105):
++ Build failure with Catch2 < 2.13.5.
++
++
+ ## v 1.1.0
+
+ > released 2021-06-23
+diff --git a/docs/source/ChangeLog-1.1.rst b/docs/source/ChangeLog-1.1.rst
+index 6a9cb3c1..4e31142d 100644
+--- a/docs/source/ChangeLog-1.1.rst
++++ b/docs/source/ChangeLog-1.1.rst
+@@ -5,6 +5,18 @@
+ ChangeLog v1.1
+ ==============
+
++v 1.1.1
++-------
++
++..
++
++ released TBD
++
++
++
++* Fix `gh #113 <https://github.com/awesomized/libmemcached/issues/105>`_\ :
++ Build failure with Catch2 < 2.13.5.
++
+ v 1.1.0
+ -------
+
+diff --git a/scripts/download_catch2.sh b/scripts/download_catch2.sh
+new file mode 100755
+index 00000000..24383983
+--- /dev/null
++++ b/scripts/download_catch2.sh
+@@ -0,0 +1,5 @@
++#!/bin/bash
++curl -sSLO $(curl -sSI https://github.com/catchorg/Catch2/releases/latest | sed -ne '\,^[Ll]ocation: *, !d
++s,[Ll]ocation: *\(.*\)/tag/,\1/download/,
++s,.$,/catch.hpp,
++p')
+diff --git a/test/lib/catch.hpp b/test/lib/catch.hpp
+index cf1fae15..36eaeb27 100644
+--- a/test/lib/catch.hpp
++++ b/test/lib/catch.hpp
+@@ -1,9 +1,9 @@
+ /*
+- * Catch v2.13.0
+- * Generated: 2020-07-12 20:07:49.015950
++ * Catch v2.13.6
++ * Generated: 2021-04-16 18:23:38.044268
+ * ----------------------------------------------------------
+ * This file has been merged from multiple headers. Please don't edit it directly
+- * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved.
++ * Copyright (c) 2021 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)
+@@ -15,7 +15,7 @@
+
+ #define CATCH_VERSION_MAJOR 2
+ #define CATCH_VERSION_MINOR 13
+-#define CATCH_VERSION_PATCH 0
++#define CATCH_VERSION_PATCH 6
+
+ #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,13 +135,9 @@ namespace Catch {
+
+ #endif
+
+-#if defined(__cpp_lib_uncaught_exceptions)
+-# 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" )
+
+@@ -162,7 +161,7 @@ namespace Catch {
+ // ```
+ //
+ // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
+-# if !defined(__ibmxl__)
++# 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
+
+@@ -244,10 +243,6 @@ namespace Catch {
+ # 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)
+@@ -330,7 +325,10 @@ namespace Catch {
+
+ // 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 __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
+@@ -373,10 +371,6 @@ namespace Catch {
+ # 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
+@@ -1105,7 +1099,7 @@ struct AutoReg : NonCopyable {
+ 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 ) = [](){\
+@@ -1151,7 +1145,7 @@ struct AutoReg : NonCopyable {
+ 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 ) = [](){ \
+@@ -1195,7 +1189,7 @@ struct AutoReg : NonCopyable {
+ 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 ) = [](){ \
+@@ -1229,7 +1223,7 @@ struct AutoReg : NonCopyable {
+ 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 ) = [](){\
+@@ -1278,7 +1272,7 @@ struct AutoReg : NonCopyable {
+ 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 ) = [](){\
+@@ -1325,7 +1319,7 @@ struct AutoReg : NonCopyable {
+ 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 ) = [](){\
+@@ -1829,8 +1823,8 @@ namespace Catch {
+ #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) {
+@@ -7063,8 +7057,8 @@ namespace Catch {
+ 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 };
+ }
+@@ -7133,7 +7127,9 @@ namespace Catch {
+ }
+ 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) {
+@@ -7611,6 +7607,10 @@ namespace TestCaseTracking {
+
+ 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
+@@ -7776,7 +7776,7 @@ namespace Catch {
+ 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;
+
+@@ -7795,7 +7795,7 @@ namespace Catch {
+ 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) {
+@@ -7985,86 +7985,58 @@ namespace Catch {
+
+ // 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>
+@@ -8190,6 +8162,7 @@ namespace Catch {
+ 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;
+@@ -10062,6 +10035,36 @@ namespace Catch {
+ }
+
+ // 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 {
+@@ -10578,7 +10581,7 @@ namespace Catch {
+ // 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;
+@@ -10740,25 +10743,47 @@ namespace Catch {
+ // 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.
+@@ -10771,7 +10796,7 @@ namespace Catch {
+ { 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);
+@@ -10782,38 +10807,50 @@ namespace Catch {
+ 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 {
+
+@@ -10822,10 +10859,6 @@ namespace Catch {
+ 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" },
+@@ -10835,7 +10868,32 @@ namespace Catch {
+ { 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) {
+@@ -10843,16 +10901,33 @@ namespace Catch {
+ 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 = { };
+@@ -10864,40 +10939,17 @@ namespace Catch {
+ }
+ }
+
+- 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
+
+@@ -11452,7 +11504,8 @@ namespace {
+ 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;
+ }
+
+@@ -11626,7 +11679,6 @@ Floating::WithinRelMatcher WithinRel(float target) {
+
+ } // namespace Matchers
+ } // namespace Catch
+-
+ // end catch_matchers_floating.cpp
+ // start catch_matchers_generic.cpp
+
+@@ -12042,7 +12094,7 @@ namespace Catch {
+ 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");
+@@ -12580,13 +12632,53 @@ namespace Catch {
+ // `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 =
+- !m_children.empty() &&
+- std::find_if( m_children.begin(),
+- m_children.end(),
+- []( TestCaseTracking::ITrackerPtr tracker ) {
+- return tracker->hasStarted();
+- } ) == m_children.end();
++ 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
+@@ -12920,9 +13012,8 @@ namespace Catch {
+ }
+
+ void RunContext::invokeActiveTestCase() {
+- FatalConditionHandler fatalConditionHandler; // Handle signals
++ FatalConditionHandlerGuard _(&m_fatalConditionhandler);
+ m_activeTestCase->invoke();
+- fatalConditionHandler.reset();
+ }
+
+ void RunContext::handleUnfinishedSections() {
+@@ -14091,24 +14182,28 @@ namespace Catch {
+
+ namespace {
+ struct TestHasher {
+- explicit TestHasher(Catch::SimplePcg32& rng) {
+- basis = rng();
+- basis <<= 32;
+- basis |= rng();
+- }
++ using hash_t = uint64_t;
+
+- uint64_t basis;
++ explicit TestHasher( hash_t hashSuffix ):
++ m_hashSuffix{ hashSuffix } {}
+
+- uint64_t operator()(TestCase const& t) const {
+- // Modified FNV-1a hash
+- static constexpr uint64_t prime = 1099511628211;
+- uint64_t hash = basis;
+- for (const char c : t.name) {
++ 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;
+ }
+- return hash;
++ 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
+
+@@ -14126,9 +14221,9 @@ namespace Catch {
+
+ case RunTests::InRandomOrder: {
+ seedRng( config );
+- TestHasher h( rng() );
++ TestHasher h{ config.rngSeed() };
+
+- using hashedTest = std::pair<uint64_t, TestCase const*>;
++ using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;
+ std::vector<hashedTest> indexed_tests;
+ indexed_tests.reserve( unsortedTestCases.size() );
+
+@@ -14458,6 +14553,14 @@ namespace TestCaseTracking {
+ 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;
+@@ -15192,6 +15295,41 @@ namespace Catch {
+ // 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 {
+@@ -15238,7 +15376,7 @@ namespace Catch {
+ }
+
+ Version const& libraryVersion() {
+- static Version version( 2, 13, 0, "", 0 );
++ static Version version( 2, 13, 6, "", 0 );
+ return version;
+ }
+