Updated catch2

master
Martin Felis 2021-05-27 14:17:30 +02:00
parent 9356ec14f8
commit 82de09ad8b
1 changed files with 336 additions and 201 deletions

View File

@ -1,9 +1,9 @@
/* /*
* Catch v2.13.1 * Catch v2.13.6
* Generated: 2020-09-07 12:12:38.090364 * Generated: 2021-04-16 18:23:38.044268
* ---------------------------------------------------------- * ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly * 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 * 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) * 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_MAJOR 2
#define CATCH_VERSION_MINOR 13 #define CATCH_VERSION_MINOR 13
#define CATCH_VERSION_PATCH 1 #define CATCH_VERSION_PATCH 6
#ifdef __clang__ #ifdef __clang__
# pragma clang system_header # pragma clang system_header
@ -66,13 +66,16 @@
#if !defined(CATCH_CONFIG_IMPL_ONLY) #if !defined(CATCH_CONFIG_IMPL_ONLY)
// start catch_platform.h // start catch_platform.h
// See e.g.:
// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
#ifdef __APPLE__ #ifdef __APPLE__
# include <TargetConditionals.h> # include <TargetConditionals.h>
# if TARGET_OS_OSX == 1 # if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
# define CATCH_PLATFORM_MAC (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
# elif TARGET_OS_IPHONE == 1 # define CATCH_PLATFORM_MAC
# define CATCH_PLATFORM_IPHONE # elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
# endif # define CATCH_PLATFORM_IPHONE
# endif
#elif defined(linux) || defined(__linux) || defined(__linux__) #elif defined(linux) || defined(__linux) || defined(__linux__)
# define CATCH_PLATFORM_LINUX # define CATCH_PLATFORM_LINUX
@ -132,13 +135,9 @@ namespace Catch {
#endif #endif
#if defined(__cpp_lib_uncaught_exceptions) // Only GCC compiler should be used in this block, so other compilers trying to
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // mask themselves as GCC should be ignored.
#endif #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
// 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)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) # 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. // 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) */ # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
# endif # endif
@ -244,10 +243,6 @@ namespace Catch {
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) # 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 // Universal Windows platform does not support SEH
// Or console colours (or console at all...) // Or console colours (or console at all...)
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
@ -376,10 +371,6 @@ namespace Catch {
# define CATCH_CONFIG_CPP17_OPTIONAL # define CATCH_CONFIG_CPP17_OPTIONAL
#endif #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) #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 # define CATCH_CONFIG_CPP17_STRING_VIEW
#endif #endif
@ -7066,8 +7057,8 @@ namespace Catch {
double b2 = bias - z1; double b2 = bias - z1;
double a1 = a(b1); double a1 = a(b1);
double a2 = a(b2); double a2 = a(b2);
auto lo = std::max(cumn(a1), 0); auto lo = (std::max)(cumn(a1), 0);
auto hi = std::min(cumn(a2), n - 1); auto hi = (std::min)(cumn(a2), n - 1);
return { point, resample[lo], resample[hi], confidence_level }; return { point, resample[lo], resample[hi], confidence_level };
} }
@ -7136,7 +7127,9 @@ namespace Catch {
} }
template <typename Clock> template <typename Clock>
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) { 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) { auto time_clock = [](int k) {
return Detail::measure<Clock>([k] { return Detail::measure<Clock>([k] {
for (int i = 0; i < k; ++i) { for (int i = 0; i < k; ++i) {
@ -7614,6 +7607,10 @@ namespace TestCaseTracking {
void addInitialFilters( std::vector<std::string> const& filters ); void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( 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 } // namespace TestCaseTracking
@ -7779,7 +7776,7 @@ namespace Catch {
double sb = stddev.point; double sb = stddev.point;
double mn = mean.point / n; double mn = mean.point / n;
double mg_min = mn / 2.; 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 sg2 = sg * sg;
double sb2 = sb * sb; double sb2 = sb * sb;
@ -7798,7 +7795,7 @@ namespace Catch {
return (nc / n) * (sb2 - nc * sg2); 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) { bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
@ -7988,86 +7985,58 @@ namespace Catch {
// start catch_fatal_condition.h // start catch_fatal_condition.h
// start catch_windows_h_proxy.h #include <cassert>
#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 )
namespace Catch { namespace Catch {
struct FatalConditionHandler { // Wrapper for platform-specific fatal error (signals/SEH) handlers
//
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); // Tries to be cooperative with other handlers, and not step over
FatalConditionHandler(); // other handlers. This means that unknown structured exceptions
static void reset(); // are passed on, previous signal handlers are called, and so on.
~FatalConditionHandler(); //
// Can only be instantiated once, and assumes that once a signal
private: // is caught, the binary will end up terminating. Thus, there
static bool isSet; class FatalConditionHandler {
static ULONG guaranteeSize; bool m_started = false;
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 );
// 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(); FatalConditionHandler();
~FatalConditionHandler(); ~FatalConditionHandler();
static void reset();
void engage() {
assert(!m_started && "Handler cannot be installed twice.");
m_started = true;
engage_platform();
}
void disengage() {
assert(m_started && "Handler cannot be uninstalled without being installed first");
m_started = false;
disengage_platform();
}
}; };
} // namespace Catch //! Simple RAII guard for (dis)engaging the FatalConditionHandler
class FatalConditionHandlerGuard {
#else FatalConditionHandler* m_handler;
public:
namespace Catch { FatalConditionHandlerGuard(FatalConditionHandler* handler):
struct FatalConditionHandler { m_handler(handler) {
void reset(); m_handler->engage();
}
~FatalConditionHandlerGuard() {
m_handler->disengage();
}
}; };
}
#endif } // end namespace Catch
// end catch_fatal_condition.h // end catch_fatal_condition.h
#include <string> #include <string>
@ -8193,6 +8162,7 @@ namespace Catch {
std::vector<SectionEndInfo> m_unfinishedSections; std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections; std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext; TrackerContext m_trackerContext;
FatalConditionHandler m_fatalConditionhandler;
bool m_lastAssertionPassed = false; bool m_lastAssertionPassed = false;
bool m_shouldReportUnexpected = true; bool m_shouldReportUnexpected = true;
bool m_includeSuccessfulResults; bool m_includeSuccessfulResults;
@ -10065,6 +10035,36 @@ namespace Catch {
} }
// end catch_errno_guard.h // 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> #include <sstream>
namespace Catch { namespace Catch {
@ -10581,7 +10581,7 @@ namespace Catch {
// Extracts the actual name part of an enum instance // Extracts the actual name part of an enum instance
// In other words, it returns the Blue part of Bikeshed::Colour::Blue // In other words, it returns the Blue part of Bikeshed::Colour::Blue
StringRef extractInstanceName(StringRef enumInstance) { StringRef extractInstanceName(StringRef enumInstance) {
// Find last occurence of ":" // Find last occurrence of ":"
size_t name_start = enumInstance.size(); size_t name_start = enumInstance.size();
while (name_start > 0 && enumInstance[name_start - 1] != ':') { while (name_start > 0 && enumInstance[name_start - 1] != ':') {
--name_start; --name_start;
@ -10743,25 +10743,47 @@ namespace Catch {
// end catch_exception_translator_registry.cpp // end catch_exception_translator_registry.cpp
// start catch_fatal_condition.cpp // start catch_fatal_condition.cpp
#if defined(__GNUC__) #include <algorithm>
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" #if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
#endif
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 ) #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace { namespace {
// Report the error condition //! Signals fatal error message to the run context
void reportFatal( char const * const message ) { void reportFatal( char const * const message ) {
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( 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 ) #if defined( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch { namespace Catch {
struct SignalDefs { DWORD id; const char* name; }; struct SignalDefs { DWORD id; const char* name; };
// There is no 1-1 mapping between signals and windows exceptions. // There is no 1-1 mapping between signals and windows exceptions.
@ -10774,7 +10796,7 @@ namespace Catch {
{ static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, { 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) { for (auto const& def : signalDefs) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
reportFatal(def.name); reportFatal(def.name);
@ -10785,38 +10807,50 @@ namespace Catch {
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
FatalConditionHandler::FatalConditionHandler() { // Since we do not support multiple instantiations, we put these
isSet = true; // into global variables and rely on cleaning them up in outlined
// 32k seems enough for Catch to handle stack overflow, // constructors/destructors
// but the value was found experimentally, so there is no strong guarantee static PVOID exceptionHandlerHandle = nullptr;
guaranteeSize = 32 * 1024;
exceptionHandlerHandle = nullptr;
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
}
void FatalConditionHandler::reset() { // For MSVC, we reserve part of the stack memory for handling
if (isSet) { // memory overflow structured exception.
RemoveVectoredExceptionHandler(exceptionHandlerHandle); FatalConditionHandler::FatalConditionHandler() {
SetThreadStackGuarantee(&guaranteeSize); ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
exceptionHandlerHandle = nullptr; if (!SetThreadStackGuarantee(&guaranteeSize)) {
isSet = false; // 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.";
} }
} }
FatalConditionHandler::~FatalConditionHandler() { // We do not attempt to unset the stack guarantee, because
reset(); // 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);
if (!exceptionHandlerHandle) {
CATCH_RUNTIME_ERROR("Could not register vectored exception handler");
}
} }
bool FatalConditionHandler::isSet = false; void FatalConditionHandler::disengage_platform() {
ULONG FatalConditionHandler::guaranteeSize = 0; if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");
}
exceptionHandlerHandle = nullptr;
}
} // namespace Catch } // end namespace Catch
#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) #endif // CATCH_CONFIG_WINDOWS_SEH
#if defined( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch { namespace Catch {
@ -10825,10 +10859,6 @@ namespace Catch {
const char* name; 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[] = { static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" }, { SIGILL, "SIGILL - Illegal instruction signal" },
@ -10838,7 +10868,32 @@ namespace Catch {
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } { 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>"; char const * name = "<unknown signal>";
for (auto const& def : signalDefs) { for (auto const& def : signalDefs) {
if (sig == def.id) { if (sig == def.id) {
@ -10846,16 +10901,33 @@ namespace Catch {
break; break;
} }
} }
reset(); // We need to restore previous signal handlers and let them do
reportFatal(name); // their thing, so that the users can have the debugger break
// when a signal is raised, and so on.
restorePreviousSignalHandlers();
reportFatal( name );
raise( sig ); raise( sig );
} }
FatalConditionHandler::FatalConditionHandler() { 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; stack_t sigStack;
sigStack.ss_sp = altStackMem; sigStack.ss_sp = altStackMem;
sigStack.ss_size = sigStackSize; sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0; sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack); sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { }; struct sigaction sa = { };
@ -10867,40 +10939,17 @@ namespace Catch {
} }
} }
FatalConditionHandler::~FatalConditionHandler() {
reset();
}
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;
}
}
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
#if defined(__GNUC__) #if defined(__GNUC__)
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
void FatalConditionHandler::disengage_platform() {
restorePreviousSignalHandlers();
}
} // end namespace Catch
#endif // CATCH_CONFIG_POSIX_SIGNALS
// end catch_fatal_condition.cpp // end catch_fatal_condition.cpp
// start catch_generators.cpp // start catch_generators.cpp
@ -11455,7 +11504,8 @@ namespace {
return lhs == rhs; 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; return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
} }
@ -11629,7 +11679,6 @@ Floating::WithinRelMatcher WithinRel(float target) {
} // namespace Matchers } // namespace Matchers
} // namespace Catch } // namespace Catch
// end catch_matchers_floating.cpp // end catch_matchers_floating.cpp
// start catch_matchers_generic.cpp // start catch_matchers_generic.cpp
@ -12045,7 +12094,7 @@ namespace Catch {
if (tmpnam_s(m_buffer)) { if (tmpnam_s(m_buffer)) {
CATCH_RUNTIME_ERROR("Could not get a temp filename"); 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]; char buffer[100];
if (strerror_s(buffer, errno)) { if (strerror_s(buffer, errno)) {
CATCH_RUNTIME_ERROR("Could not translate errno to a string"); CATCH_RUNTIME_ERROR("Could not translate errno to a string");
@ -12583,13 +12632,53 @@ namespace Catch {
// `SECTION`s. // `SECTION`s.
// **The check for m_children.empty cannot be removed**. // **The check for m_children.empty cannot be removed**.
// doing so would break `GENERATE` _not_ followed by `SECTION`s. // doing so would break `GENERATE` _not_ followed by `SECTION`s.
const bool should_wait_for_child = const bool should_wait_for_child = [&]() {
!m_children.empty() && // No children -> nobody to wait for
std::find_if( m_children.begin(), if ( m_children.empty() ) {
m_children.end(), return false;
[]( TestCaseTracking::ITrackerPtr tracker ) { }
return tracker->hasStarted(); // If at least one child started executing, don't wait
} ) == m_children.end(); 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() // This check is a bit tricky, because m_generator->next()
// has a side-effect, where it consumes generator's current // has a side-effect, where it consumes generator's current
@ -12923,9 +13012,8 @@ namespace Catch {
} }
void RunContext::invokeActiveTestCase() { void RunContext::invokeActiveTestCase() {
FatalConditionHandler fatalConditionHandler; // Handle signals FatalConditionHandlerGuard _(&m_fatalConditionhandler);
m_activeTestCase->invoke(); m_activeTestCase->invoke();
fatalConditionHandler.reset();
} }
void RunContext::handleUnfinishedSections() { void RunContext::handleUnfinishedSections() {
@ -14094,24 +14182,28 @@ namespace Catch {
namespace { namespace {
struct TestHasher { struct TestHasher {
explicit TestHasher(Catch::SimplePcg32& rng) { using hash_t = uint64_t;
basis = rng();
basis <<= 32;
basis |= rng();
}
uint64_t basis; explicit TestHasher( hash_t hashSuffix ):
m_hashSuffix{ hashSuffix } {}
uint64_t operator()(TestCase const& t) const { uint32_t operator()( TestCase const& t ) const {
// Modified FNV-1a hash // FNV-1a hash with multiplication fold.
static constexpr uint64_t prime = 1099511628211; const hash_t prime = 1099511628211u;
uint64_t hash = basis; hash_t hash = 14695981039346656037u;
for (const char c : t.name) { for ( const char c : t.name ) {
hash ^= c; hash ^= c;
hash *= prime; 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 } // end unnamed namespace
@ -14129,9 +14221,9 @@ namespace Catch {
case RunTests::InRandomOrder: { case RunTests::InRandomOrder: {
seedRng( config ); 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; std::vector<hashedTest> indexed_tests;
indexed_tests.reserve( unsortedTestCases.size() ); indexed_tests.reserve( unsortedTestCases.size() );
@ -14461,6 +14553,14 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); 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 } // namespace TestCaseTracking
using TestCaseTracking::ITracker; using TestCaseTracking::ITracker;
@ -15195,6 +15295,41 @@ namespace Catch {
// end catch_totals.cpp // end catch_totals.cpp
// start catch_uncaught_exceptions.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> #include <exception>
namespace Catch { namespace Catch {
@ -15241,7 +15376,7 @@ namespace Catch {
} }
Version const& libraryVersion() { Version const& libraryVersion() {
static Version version( 2, 13, 1, "", 0 ); static Version version( 2, 13, 6, "", 0 );
return version; return version;
} }