[neon/3rdparty/zug] debian: New packaging needed by krita

Scarlett Moore null at kde.org
Tue Sep 26 17:44:44 BST 2023


Git commit 2b7e6632a68e685148aec8b8557741df3590bb2f by Scarlett Moore.
Committed on 26/09/2023 at 18:44.
Pushed by scarlettmoore into branch 'master'.

New packaging needed by krita

A  +1    -0    debian/.gitattributes
A  +13   -0    debian/changelog
A  +28   -0    debian/control
A  +42   -0    debian/copyright
A  +1    -0    debian/patches/series
A  +5905 -0    debian/patches/update-catch2.diff
A  +14   -0    debian/rules
A  +6    -0    debian/salsa-ci.yml
A  +1    -0    debian/source/format
A  +5    -0    debian/upstream/metadata
A  +5    -0    debian/watch

https://invent.kde.org/neon/3rdparty/zug/-/commit/2b7e6632a68e685148aec8b8557741df3590bb2f

diff --git a/debian/.gitattributes b/debian/.gitattributes
new file mode 100644
index 0000000..6a03163
--- /dev/null
+++ b/debian/.gitattributes
@@ -0,0 +1 @@
+changelog merge=dpkg-mergechangelogs
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..c9cb368
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,13 @@
+zug (0.1.0-2) unstable; urgency=medium
+
+  * Upload to unstable.
+  * update-catch2.diff: mention https://github.com/arximboldi/zug/pull/36 that
+    will fix the issue in the long term.
+
+ -- Pino Toscano <pino at debian.org>  Sun, 06 Aug 2023 22:04:48 +0200
+
+zug (0.1.0-1) experimental; urgency=medium
+
+  * Initial packaging.
+
+ -- Pino Toscano <pino at debian.org>  Fri, 28 Jul 2023 13:47:27 +0200
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..44e2d3a
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,28 @@
+Source: zug
+Section: libs
+Priority: optional
+Maintainer: Debian Qt/KDE Maintainers <debian-qt-kde at lists.debian.org>
+Uploaders: Pino Toscano <pino at debian.org>,
+Build-Depends: cmake (>= 3.8~),
+               debhelper-compat (= 13),
+               libboost-dev,
+Standards-Version: 4.6.2
+Rules-Requires-Root: no
+Homepage: https://github.com/arximboldi/zug
+Vcs-Browser: https://salsa.debian.org/qt-kde-team/3rdparty/zug
+Vcs-Git: https://salsa.debian.org/qt-kde-team/3rdparty/zug.git
+
+Package: libzug-dev
+Architecture: any
+Multi-Arch: same
+Section: libdevel
+Depends: ${misc:Depends},
+         libboost-dev,
+Description: C++ library providing transducers -- development files
+ zug is a C++ library providing transducers. Transducers are composable
+ sequential transformations independent of the source. They are extremely
+ lightweight, and can be used to express algorithms over pull-based sequences
+ (iterators, files) but also push based sequences (signals, events,
+ asynchronous streams) in a generic way.
+ .
+ This package contains the development files.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..1a89bd8
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,42 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: zug
+Source: https://github.com/arximboldi/zug
+
+Files: *
+Copyright: 2016-2020, Juan Pedro Bolivar Puente
+           2019, Juan Pedro Bolivar Puente (and Carl Bussey, maybe?)
+           2019, Juan Pedro Bolivar Puente and Carl Bussey
+License: BSL-1.0
+
+Files: tools/include/catch2/catch.hpp
+Copyright: 2019, Two Blue Cubes Ltd. All rights reserved.
+License: BSL-1.0
+
+Files: debian/*
+Copyright: 2023, Pino Toscano <pino at debian.org>
+License: BSL-1.0
+
+License: BSL-1.0
+ Boost Software License - Version 1.0 - August 17th, 2003
+ .
+ Permission is hereby granted, free of charge, to any person or organization
+ obtaining a copy of the software and accompanying documentation covered by
+ this license (the "Software") to use, reproduce, display, distribute,
+ execute, and transmit the Software, and to prepare derivative works of the
+ Software, and to permit third-parties to whom the Software is furnished to
+ do so, all subject to the following:
+ .
+ The copyright notices in the Software and this entire statement, including
+ the above license grant, this restriction and the following disclaimer,
+ must be included in all copies of the Software, in whole or in part, and
+ all derivative works of the Software, unless such copies or derivative
+ works are solely in the form of machine-executable object code generated by
+ a source language processor.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..cf51af9
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+update-catch2.diff
diff --git a/debian/patches/update-catch2.diff b/debian/patches/update-catch2.diff
new file mode 100644
index 0000000..fd3af07
--- /dev/null
+++ b/debian/patches/update-catch2.diff
@@ -0,0 +1,5905 @@
+Author: Pino Toscano <pino at debian.org>
+Description: Update catch2
+ Update the catch2 copy from the version shipped in immer:
+ https://github.com/arximboldi/immer/blob/master/tools/include/catch.hpp
+ .
+ This is needed until the next upstream release, as this embedded copy of
+ catch2 is replaced by the usage of a system-installed version:
+ https://github.com/arximboldi/zug/pull/36
+Last-Update: 2023-07-28
+Forwarded: not-needed
+
+--- a/tools/include/catch2/catch.hpp
++++ b/tools/include/catch2/catch.hpp
+@@ -1,9 +1,9 @@
+ /*
+- *  Catch v2.9.1
+- *  Generated: 2019-06-17 11:59:24.363643
++ *  Catch v2.13.7
++ *  Generated: 2021-07-28 20:29:27.753164
+  *  ----------------------------------------------------------
+  *  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) 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)
+@@ -14,8 +14,8 @@
+ 
+ 
+ #define CATCH_VERSION_MAJOR 2
+-#define CATCH_VERSION_MINOR 9
+-#define CATCH_VERSION_PATCH 1
++#define CATCH_VERSION_MINOR 13
++#define CATCH_VERSION_PATCH 7
+ 
+ #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,36 +135,51 @@ namespace Catch {
+ 
+ #endif
+ 
+-#if defined(CATCH_CPP17_OR_GREATER)
+-#  define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
++// 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
+ 
+-#ifdef __clang__
++#if defined(__clang__)
++
++#    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\"")
++
++#    define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
++         _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
++
++#    define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
++         _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
+ 
+-#       define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+-            _Pragma( "clang diagnostic push" ) \
+-            _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
+-            _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
+-#       define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+-            _Pragma( "clang diagnostic pop" )
+-
+-#       define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+-            _Pragma( "clang diagnostic push" ) \
+-            _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+-#       define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+-            _Pragma( "clang diagnostic pop" )
+-
+-#       define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+-            _Pragma( "clang diagnostic push" ) \
+-            _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
+-#       define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
+-            _Pragma( "clang diagnostic pop" )
+-
+-#       define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+-            _Pragma( "clang diagnostic push" ) \
+-            _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
+-#       define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \
+-            _Pragma( "clang diagnostic pop" )
++#    define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
++         _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
++
++#    define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
++         _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
+ 
+ #endif // __clang__
+ 
+@@ -186,6 +204,7 @@ namespace Catch {
+ // Android somehow still does not support std::to_string
+ #if defined(__ANDROID__)
+ #    define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
++#    define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
+ #endif
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -219,11 +238,10 @@ namespace Catch {
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ // Visual C++
+-#ifdef _MSC_VER
++#if defined(_MSC_VER)
+ 
+-#  if _MSC_VER >= 1900 // Visual Studio 2015 or newer
+-#    define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+-#  endif
++#  define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
++#  define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION  __pragma( warning(pop) )
+ 
+ // Universal Windows platform does not support SEH
+ // Or console colours (or console at all...)
+@@ -236,9 +254,12 @@ namespace Catch {
+ // MSVC traditional preprocessor needs some workaround for __VA_ARGS__
+ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor
+ // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
+-#  if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
+-#    define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+-#  endif
++#  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
++#  endif // __clang__
++
+ #endif // _MSC_VER
+ 
+ #if defined(_REENTRANT) || defined(_MSC_VER)
+@@ -276,40 +297,56 @@ namespace Catch {
+ #endif
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+-// Check if string_view is available and usable
+-// The check is split apart to work around v140 (VS2015) preprocessor issue...
+-#if defined(__has_include)
+-#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
+-#    define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
+-#endif
++
++// RTX is a special version of Windows that is real time.
++// This means that it is detected as Windows, but does not provide
++// the same set of capabilities as real Windows does.
++#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
++    #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
++    #define CATCH_INTERNAL_CONFIG_NO_ASYNC
++    #define CATCH_CONFIG_COLOUR_NONE
+ #endif
+ 
+-////////////////////////////////////////////////////////////////////////////////
+-// Check if optional is available and usable
+-#if defined(__has_include)
+-#  if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+-#    define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+-#  endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+-#endif // __has_include
++#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
++#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
++#endif
+ 
+-////////////////////////////////////////////////////////////////////////////////
+-// Check if variant is available and usable
++// Various stdlib support checks that require __has_include
+ #if defined(__has_include)
+-#  if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+-#    if defined(__clang__) && (__clang_major__ < 8)
+-       // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
+-       // fix should be in clang 8, workaround in libstdc++ 8.2
+-#      include <ciso646>
+-#      if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+-#        define CATCH_CONFIG_NO_CPP17_VARIANT
+-#      else
+-#        define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+-#      endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+-#    else
+-#      define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+-#    endif // defined(__clang__) && (__clang_major__ < 8)
+-#  endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+-#endif // __has_include
++  // Check if string_view is available and usable
++  #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
++  #    define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
++  #endif
++
++  // Check if optional is available and usable
++  #  if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
++  #    define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
++  #  endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
++
++  // Check if byte is available and usable
++  #  if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
++  #    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
++  #  if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
++  #    if defined(__clang__) && (__clang_major__ < 8)
++         // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
++         // fix should be in clang 8, workaround in libstdc++ 8.2
++  #      include <ciso646>
++  #      if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
++  #        define CATCH_CONFIG_NO_CPP17_VARIANT
++  #      else
++  #        define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
++  #      endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
++  #    else
++  #      define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
++  #    endif // defined(__clang__) && (__clang_major__ < 8)
++  #  endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
++#endif // defined(__has_include)
+ 
+ #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
+ #   define CATCH_CONFIG_COUNTER
+@@ -334,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
+@@ -346,6 +379,10 @@ namespace Catch {
+ #  define CATCH_CONFIG_CPP17_VARIANT
+ #endif
+ 
++#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
++#  define CATCH_CONFIG_CPP17_BYTE
++#endif
++
+ #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+ #  define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
+ #endif
+@@ -362,25 +399,53 @@ namespace Catch {
+ #  define CATCH_CONFIG_POLYFILL_ISNAN
+ #endif
+ 
+-#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC)  && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
++#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC)  && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
+ #  define CATCH_CONFIG_USE_ASYNC
+ #endif
+ 
++#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE)
++#  define CATCH_CONFIG_ANDROID_LOGWRITE
++#endif
++
++#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
++#  define CATCH_CONFIG_GLOBAL_NEXTAFTER
++#endif
++
++// Even if we do not think the compiler has that warning, we still have
++// to provide a macro that can be used by the code.
++#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
++#   define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
++#endif
++#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
++#   define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
++#endif
+ #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
+ #   define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
+-#   define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
+ #endif
+ #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
+ #   define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+-#   define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ #endif
+ #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
+ #   define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
+-#   define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+ #endif
+ #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
+ #   define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
+-#   define CATCH_INTERNAL_UNSUPPRESS_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)
++#   undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
++#endif
++
++#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)
++#   define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+ #endif
+ 
+ #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+@@ -445,7 +510,7 @@ namespace Catch {
+         SourceLineInfo( SourceLineInfo&& )              noexcept = default;
+         SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
+ 
+-        bool empty() const noexcept;
++        bool empty() const noexcept { return file[0] == '\0'; }
+         bool operator == ( SourceLineInfo const& other ) const noexcept;
+         bool operator < ( SourceLineInfo const& other ) const noexcept;
+ 
+@@ -486,9 +551,10 @@ namespace Catch {
+ } // end namespace Catch
+ 
+ #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
++    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+     CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+     namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
+-    CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
++    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ 
+ // end catch_tag_alias_autoregistrar.h
+ // start catch_test_registry.h
+@@ -515,6 +581,7 @@ namespace Catch {
+         virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
+     };
+ 
++    bool isThrowSafe( TestCase const& testCase, IConfig const& config );
+     bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+     std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+     std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+@@ -527,53 +594,30 @@ namespace Catch {
+ #include <cstddef>
+ #include <string>
+ #include <iosfwd>
++#include <cassert>
+ 
+ namespace Catch {
+ 
+     /// A non-owning string class (similar to the forthcoming std::string_view)
+     /// Note that, because a StringRef may be a substring of another string,
+-    /// it may not be null terminated. c_str() must return a null terminated
+-    /// string, however, and so the StringRef will internally take ownership
+-    /// (taking a copy), if necessary. In theory this ownership is not externally
+-    /// visible - but it does mean (substring) StringRefs should not be shared between
+-    /// threads.
++    /// it may not be null terminated.
+     class StringRef {
+     public:
+         using size_type = std::size_t;
++        using const_iterator = const char*;
+ 
+     private:
+-        friend struct StringRefTestAccess;
+-
+-        char const* m_start;
+-        size_type m_size;
+-
+-        char* m_data = nullptr;
+-
+-        void takeOwnership();
+-
+         static constexpr char const* const s_empty = "";
+ 
+-    public: // construction/ assignment
+-        StringRef() noexcept
+-        :   StringRef( s_empty, 0 )
+-        {}
++        char const* m_start = s_empty;
++        size_type m_size = 0;
+ 
+-        StringRef( StringRef const& other ) noexcept
+-        :   m_start( other.m_start ),
+-            m_size( other.m_size )
+-        {}
+-
+-        StringRef( StringRef&& other ) noexcept
+-        :   m_start( other.m_start ),
+-            m_size( other.m_size ),
+-            m_data( other.m_data )
+-        {
+-            other.m_data = nullptr;
+-        }
++    public: // construction
++        constexpr StringRef() noexcept = default;
+ 
+         StringRef( char const* rawChars ) noexcept;
+ 
+-        StringRef( char const* rawChars, size_type size ) noexcept
++        constexpr StringRef( char const* rawChars, size_type size ) noexcept
+         :   m_start( rawChars ),
+             m_size( size )
+         {}
+@@ -583,101 +627,64 @@ namespace Catch {
+             m_size( stdString.size() )
+         {}
+ 
+-        ~StringRef() noexcept {
+-            delete[] m_data;
++        explicit operator std::string() const {
++            return std::string(m_start, m_size);
+         }
+ 
+-        auto operator = ( StringRef const &other ) noexcept -> StringRef& {
+-            delete[] m_data;
+-            m_data = nullptr;
+-            m_start = other.m_start;
+-            m_size = other.m_size;
+-            return *this;
+-        }
+-
+-        operator std::string() const;
+-
+-        void swap( StringRef& other ) noexcept;
+-
+     public: // operators
+         auto operator == ( StringRef const& other ) const noexcept -> bool;
+-        auto operator != ( StringRef const& other ) const noexcept -> bool;
++        auto operator != (StringRef const& other) const noexcept -> bool {
++            return !(*this == other);
++        }
+ 
+-        auto operator[] ( size_type index ) const noexcept -> char;
++        auto operator[] ( size_type index ) const noexcept -> char {
++            assert(index < m_size);
++            return m_start[index];
++        }
+ 
+     public: // named queries
+-        auto empty() const noexcept -> bool {
++        constexpr auto empty() const noexcept -> bool {
+             return m_size == 0;
+         }
+-        auto size() const noexcept -> size_type {
++        constexpr auto size() const noexcept -> size_type {
+             return m_size;
+         }
+ 
+-        auto numberOfCharacters() const noexcept -> size_type;
++        // Returns the current start pointer. If the StringRef is not
++        // null-terminated, throws std::domain_exception
+         auto c_str() const -> char const*;
+ 
+     public: // substrings and searches
+-        auto substr( size_type start, size_type size ) const noexcept -> StringRef;
++        // Returns a substring of [start, start + length).
++        // If start + length > size(), then the substring is [start, size()).
++        // If start > size(), then the substring is empty.
++        auto substr( size_type start, size_type length ) const noexcept -> StringRef;
+ 
+-        // Returns the current start pointer.
+-        // Note that the pointer can change when if the StringRef is a substring
+-        auto currentData() const noexcept -> char const*;
++        // Returns the current start pointer. May not be null-terminated.
++        auto data() const noexcept -> char const*;
+ 
+-    private: // ownership queries - may not be consistent between calls
+-        auto isOwned() const noexcept -> bool;
+-        auto isSubstring() const noexcept -> bool;
+-    };
++        constexpr auto isNullTerminated() const noexcept -> bool {
++            return m_start[m_size] == '\0';
++        }
+ 
+-    auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string;
+-    auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string;
+-    auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string;
++    public: // iterators
++        constexpr const_iterator begin() const { return m_start; }
++        constexpr const_iterator end() const { return m_start + m_size; }
++    };
+ 
+     auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
+     auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
+ 
+-    inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
++    constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
+         return StringRef( rawChars, size );
+     }
+-
+ } // namespace Catch
+ 
+-inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
++constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+     return Catch::StringRef( rawChars, size );
+ }
+ 
+ // end catch_stringref.h
+-// start catch_type_traits.hpp
+-
+-
+-#include <type_traits>
+-
+-namespace Catch{
+-
+-#ifdef CATCH_CPP17_OR_GREATER
+-	template <typename...>
+-	inline constexpr auto is_unique = std::true_type{};
+-
+-	template <typename T, typename... Rest>
+-	inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
+-		(!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
+-	>{};
+-#else
+-
+-template <typename...>
+-struct is_unique : std::true_type{};
+-
+-template <typename T0, typename T1, typename... Rest>
+-struct is_unique<T0, T1, Rest...> : std::integral_constant
+-<bool,
+-     !std::is_same<T0, T1>::value
+-     && is_unique<T0, Rest...>::value
+-     && is_unique<T1, Rest...>::value
+->{};
+-
+-#endif
+-}
+-
+-// end catch_type_traits.hpp
+ // start catch_preprocessor.hpp
+ 
+ 
+@@ -762,7 +769,7 @@ struct is_unique<T0, T1, Rest...> : std:
+ #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)
+@@ -774,35 +781,49 @@ struct is_unique<T0, T1, Rest...> : std:
+     template<typename...> struct TypeList {};\
+     template<typename...Ts>\
+     constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
++    template<template<typename...> class...> struct TemplateTypeList{};\
++    template<template<typename...> class...Cs>\
++    constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
++    template<typename...>\
++    struct append;\
++    template<typename...>\
++    struct rewrap;\
++    template<template<typename...> class, typename...>\
++    struct create;\
++    template<template<typename...> class, typename>\
++    struct convert;\
+     \
+-    template<template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2> \
+-    constexpr auto append(L1<E1...>, L2<E2...>) noexcept -> L1<E1...,E2...> { return {}; }\
++    template<typename T> \
++    struct append<T> { using type = T; };\
+     template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
+-    constexpr auto append(L1<E1...>, L2<E2...>, Rest...) noexcept -> decltype(append(L1<E1...,E2...>{}, Rest{}...)) { return {}; }\
++    struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
+     template< template<typename...> class L1, typename...E1, typename...Rest>\
+-    constexpr auto append(L1<E1...>, TypeList<mpl_::na>, Rest...) noexcept -> L1<E1...> { return {}; }\
++    struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
+     \
+     template< template<typename...> class Container, template<typename...> class List, typename...elems>\
+-    constexpr auto rewrap(List<elems...>) noexcept -> TypeList<Container<elems...>> { return {}; }\
++    struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
+     template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
+-    constexpr auto rewrap(List<Elems...>,Elements...) noexcept -> decltype(append(TypeList<Container<Elems...>>{}, rewrap<Container>(Elements{}...))) { return {}; }\
++    struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
+     \
+     template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
+-    constexpr auto create(TypeList<Types...>) noexcept -> decltype(append(Final<>{}, rewrap<Containers>(Types{}...)...)) { return {}; }\
++    struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
+     template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
+-    constexpr auto convert(List<Ts...>) noexcept -> decltype(append(Final<>{},TypeList<Ts>{}...)) { return {}; }
++    struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
+ 
+ #define INTERNAL_CATCH_NTTP_1(signature, ...)\
+     template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
+     template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+     constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
++    template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
++    template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
++    constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
+     \
+     template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+-    constexpr auto rewrap(List<__VA_ARGS__>) noexcept -> TypeList<Container<__VA_ARGS__>> { return {}; }\
++    struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
+     template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
+-    constexpr auto rewrap(List<__VA_ARGS__>,Elements...elems) noexcept -> decltype(append(TypeList<Container<__VA_ARGS__>>{}, rewrap<Container>(elems...))) { return {}; }\
++    struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
+     template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
+-    constexpr auto create(TypeList<Types...>) noexcept -> decltype(append(Final<>{}, rewrap<Containers>(Types{}...)...)) { return {}; }
++    struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
+ 
+ #define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
+ #define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
+@@ -898,22 +919,33 @@ struct is_unique<T0, T1, Rest...> : std:
+ #include <type_traits>
+ 
+ namespace Catch {
+-template<typename T>
+-struct always_false : std::false_type {};
++    template<typename T>
++    struct always_false : std::false_type {};
+ 
+-template <typename> struct true_given : std::true_type {};
+-struct is_callable_tester {
+-    template <typename Fun, typename... Args>
+-    true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
+-    template <typename...>
+-    std::false_type static test(...);
+-};
++    template <typename> struct true_given : std::true_type {};
++    struct is_callable_tester {
++        template <typename Fun, typename... Args>
++        true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
++        template <typename...>
++        std::false_type static test(...);
++    };
+ 
+-template <typename T>
+-struct is_callable;
++    template <typename T>
++    struct is_callable;
++
++    template <typename Fun, typename... Args>
++    struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
+ 
+-template <typename Fun, typename... Args>
+-struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
++#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.
++    template <typename Func, typename... U>
++    using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
++#else
++    // 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
+ 
+@@ -1012,21 +1044,24 @@ struct AutoReg : NonCopyable {
+     ///////////////////////////////////////////////////////////////////////////////
+     #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
+         static void TestName(); \
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+         namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
++        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__ )
+ 
+     ///////////////////////////////////////////////////////////////////////////////
+     #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+         namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
++        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ 
+     ///////////////////////////////////////////////////////////////////////////////
+     #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+         namespace{ \
+             struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
+@@ -1034,21 +1069,24 @@ struct AutoReg : NonCopyable {
+             }; \
+             Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
+         } \
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
++        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__ )
+ 
+     ///////////////////////////////////////////////////////////////////////////////
+     #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+         Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
++        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ 
+     ///////////////////////////////////////////////////////////////////////////////
+     #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+         CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
++        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+         INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+         namespace {\
+         namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+@@ -1061,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 ) = [](){\
+@@ -1070,8 +1108,7 @@ struct AutoReg : NonCopyable {
+         }();\
+         }\
+         }\
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+-        CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \
++        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+         INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
+ 
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+@@ -1091,8 +1128,10 @@ struct AutoReg : NonCopyable {
+ #endif
+ 
+     #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION                      \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS                      \
+         CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS                \
++        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS              \
+         template<typename TestType> static void TestFuncName();       \
+         namespace {\
+         namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) {                                     \
+@@ -1106,19 +1145,18 @@ 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 ) = [](){ \
+-                using TestInit = decltype(create<TestName, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>{})); \
++                using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
+                 TestInit t;                                           \
+                 t.reg_tests();                                        \
+                 return 0;                                             \
+             }();                                                      \
+         }                                                             \
+         }                                                             \
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS                    \
+-        CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS              \
++        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION                       \
+         template<typename TestType>                                   \
+         static void TestFuncName()
+ 
+@@ -1139,7 +1177,9 @@ struct AutoReg : NonCopyable {
+ #endif
+ 
+     #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
++        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+         template<typename TestType> static void TestFunc();       \
+         namespace {\
+         namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+@@ -1149,17 +1189,17 @@ 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 ) = [](){ \
+-                using TestInit = decltype(convert<TestName>(TmplList {})); \
++                using TestInit = typename convert<TestName, TmplList>::type; \
+                 TestInit t;                                           \
+                 t.reg_tests();                                        \
+                 return 0;                                             \
+-            }();                                                        \
++            }();                                                      \
+         }}\
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS                    \
++        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION                       \
+         template<typename TestType>                                   \
+         static void TestFunc()
+ 
+@@ -1167,8 +1207,10 @@ struct AutoReg : NonCopyable {
+         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 \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+         CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
++        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+         namespace {\
+         namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+             INTERNAL_CATCH_TYPE_GEN\
+@@ -1181,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 ) = [](){\
+@@ -1190,8 +1232,7 @@ struct AutoReg : NonCopyable {
+         }();\
+         }\
+         }\
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
+-        CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS\
++        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+         INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+ 
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+@@ -1211,8 +1252,10 @@ struct AutoReg : NonCopyable {
+ #endif
+ 
+     #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+         CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
++        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+         template<typename TestType> \
+             struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+                 void test();\
+@@ -1229,19 +1272,18 @@ 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 ) = [](){\
+-                using TestInit = decltype(create<TestNameClass, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>{}));\
++                using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
+                 TestInit t;\
+                 t.reg_tests();\
+                 return 0;\
+             }(); \
+         }\
+         }\
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+-        CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \
++        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+         template<typename TestType> \
+         void TestName<TestType>::test()
+ 
+@@ -1262,7 +1304,9 @@ struct AutoReg : NonCopyable {
+ #endif
+ 
+     #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
++        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
++        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+         template<typename TestType> \
+         struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+             void test();\
+@@ -1275,17 +1319,17 @@ 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 ) = [](){\
+-                using TestInit = decltype(convert<TestNameClass>(TmplList {}));\
++                using TestInit = typename convert<TestNameClass, TmplList>::type;\
+                 TestInit t;\
+                 t.reg_tests();\
+                 return 0;\
+             }(); \
+         }}\
+-        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
++        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+         template<typename TestType> \
+         void TestName<TestType>::test()
+ 
+@@ -1391,7 +1435,7 @@ namespace Catch {
+ 
+     auto makeStream( StringRef const &filename ) -> IStream const*;
+ 
+-    class ReusableStringStream {
++    class ReusableStringStream : NonCopyable {
+         std::size_t m_index;
+         std::ostream* m_oss;
+     public:
+@@ -1419,7 +1463,7 @@ namespace Catch {
+     namespace Detail {
+         struct EnumInfo {
+             StringRef m_name;
+-            std::vector<std::pair<int, std::string>> m_values;
++            std::vector<std::pair<int, StringRef>> m_values;
+ 
+             ~EnumInfo();
+ 
+@@ -1434,6 +1478,7 @@ namespace Catch {
+ 
+         template<typename E>
+         Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
++            static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
+             std::vector<int> intValues;
+             intValues.reserve( values.size() );
+             for( auto enumValue : values )
+@@ -1515,9 +1560,9 @@ namespace Catch {
+ 
+         template<typename T>
+         class IsStreamInsertable {
+-            template<typename SS, typename TT>
++            template<typename Stream, typename U>
+             static auto test(int)
+-                -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
++                -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
+ 
+             template<typename, typename>
+             static auto test(...)->std::false_type;
+@@ -1679,6 +1724,12 @@ namespace Catch {
+         }
+     };
+ 
++#if defined(CATCH_CONFIG_CPP17_BYTE)
++    template<>
++    struct StringMaker<std::byte> {
++        static std::string convert(std::byte value);
++    };
++#endif // defined(CATCH_CONFIG_CPP17_BYTE)
+     template<>
+     struct StringMaker<int> {
+         static std::string convert(int value);
+@@ -1772,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) {
+@@ -1931,20 +1982,27 @@ namespace Catch {
+ #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
+@@ -2114,7 +2172,7 @@ namespace Catch { \
+     template<> struct StringMaker<enumName> { \
+         static std::string convert( enumName value ) { \
+             static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
+-            return enumInfo.lookup( static_cast<int>( value ) ); \
++            return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
+         } \
+     }; \
+ }
+@@ -2312,6 +2370,18 @@ namespace Catch {
+         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 {
+@@ -2392,7 +2462,7 @@ namespace Catch {
+         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;
+@@ -2630,15 +2700,16 @@ namespace Catch {
+ ///////////////////////////////////////////////////////////////////////////////
+ #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 \
+             CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+             catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
+-            CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
++            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, ... ) \
+@@ -2855,14 +2926,16 @@ namespace Catch {
+ } // end namespace Catch
+ 
+ #define INTERNAL_CATCH_SECTION( ... ) \
++    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+     CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+     if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
+-    CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
++    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ 
+ #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
++    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+     CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+     if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
+-    CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
++    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ 
+ // end catch_section.h
+ // start catch_interfaces_exception.h
+@@ -2953,6 +3026,9 @@ namespace Catch {
+             {}
+ 
+             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());
+@@ -2962,6 +3038,7 @@ namespace Catch {
+                 catch( T& ex ) {
+                     return m_translateFunction( ex );
+                 }
++#endif
+             }
+ 
+         protected:
+@@ -2980,9 +3057,10 @@ namespace Catch {
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
+     static std::string translatorName( signature ); \
++    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+     CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+     namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
+-    CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
++    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+     static std::string translatorName( signature )
+ 
+ #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+@@ -3124,7 +3202,10 @@ namespace Catch {
+     bool contains( std::string const& s, std::string const& infix );
+     void toLowerInPlace( std::string& s );
+     std::string toLower( std::string const& s );
++    //! Returns a new string without whitespace at the start/end
+     std::string trim( std::string const& str );
++    //! Returns a substring of the original ref without whitespace. Beware lifetimes!
++    StringRef trim(StringRef ref);
+ 
+     // !!! Be aware, returns refs into original string - make sure original string outlives them
+     std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
+@@ -3180,6 +3261,15 @@ namespace Matchers {
+             virtual bool match( ObjectT const& arg ) const = 0;
+         };
+ 
++#if defined(__OBJC__)
++        // Hack to fix Catch GH issue #1661. Could use id for generic Object support.
++        // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation
++        template<>
++        struct MatcherMethod<NSString*> {
++            virtual bool match( NSString* arg ) const = 0;
++        };
++#endif
++
+ #ifdef __clang__
+ #    pragma clang diagnostic pop
+ #endif
+@@ -3217,9 +3307,10 @@ namespace Matchers {
+                 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;
+@@ -3250,9 +3341,10 @@ namespace Matchers {
+                 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;
+@@ -3296,10 +3388,34 @@ using Matchers::Impl::MatcherBase;
+ } // namespace Catch
+ 
+ // end catch_matchers.h
+-// start catch_matchers_floating.h
++// start catch_matchers_exception.hpp
+ 
+-#include <type_traits>
+-#include <cmath>
++namespace Catch {
++namespace Matchers {
++namespace Exception {
++
++class ExceptionMessageMatcher : public MatcherBase<std::exception> {
++    std::string m_message;
++public:
++
++    ExceptionMessageMatcher(std::string const& message):
++        m_message(message)
++    {}
++
++    bool match(std::exception const& ex) const override;
++
++    std::string describe() const override;
++};
++
++} // namespace Exception
++
++Exception::ExceptionMessageMatcher Message(std::string const& message);
++
++} // namespace Matchers
++} // namespace Catch
++
++// end catch_matchers_exception.hpp
++// start catch_matchers_floating.h
+ 
+ namespace Catch {
+ namespace Matchers {
+@@ -3318,22 +3434,43 @@ namespace Matchers {
+         };
+ 
+         struct WithinUlpsMatcher : MatcherBase<double> {
+-            WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
++            WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
+             bool match(double const& matchee) const override;
+             std::string describe() const override;
+         private:
+             double m_target;
+-            int m_ulps;
++            uint64_t m_ulps;
+             FloatingPointKind m_type;
+         };
+ 
++        // Given IEEE-754 format for floats and doubles, we can assume
++        // that float -> double promotion is lossless. Given this, we can
++        // assume that if we do the standard relative comparison of
++        // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
++        // the same result if we do this for floats, as if we do this for
++        // doubles that were promoted from floats.
++        struct WithinRelMatcher : MatcherBase<double> {
++            WithinRelMatcher(double target, double epsilon);
++            bool match(double const& matchee) const override;
++            std::string describe() const override;
++        private:
++            double m_target;
++            double m_epsilon;
++        };
++
+     } // namespace Floating
+ 
+     // The following functions create the actual matcher objects.
+     // This allows the types to be inferred
+-    Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
+-    Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
++    Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
++    Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
+     Floating::WithinAbsMatcher WithinAbs(double target, double margin);
++    Floating::WithinRelMatcher WithinRel(double target, double eps);
++    // defaults epsilon to 100*numeric_limits<double>::epsilon()
++    Floating::WithinRelMatcher WithinRel(double target);
++    Floating::WithinRelMatcher WithinRel(float target, float eps);
++    // defaults epsilon to 100*numeric_limits<float>::epsilon()
++    Floating::WithinRelMatcher WithinRel(float target);
+ 
+ } // namespace Matchers
+ } // namespace Catch
+@@ -3464,12 +3601,12 @@ namespace Catch {
+ 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;
+@@ -3485,12 +3622,12 @@ namespace Matchers {
+             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;
+@@ -3512,18 +3649,18 @@ namespace Matchers {
+                 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;
+@@ -3535,15 +3672,15 @@ namespace Matchers {
+             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)
+@@ -3570,16 +3707,14 @@ namespace Matchers {
+                 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;
+                 }
+@@ -3590,7 +3725,7 @@ namespace Matchers {
+                 return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
+             }
+         private:
+-            std::vector<T> const& m_target;
++            std::vector<T, AllocComp> const& m_target;
+         };
+ 
+     } // namespace Vector
+@@ -3598,29 +3733,29 @@ namespace Matchers {
+     // 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
+@@ -3758,13 +3893,13 @@ namespace Catch {
+     (Catch::ReusableStringStream() << __VA_ARGS__).str()
+ 
+ #define CATCH_INTERNAL_ERROR(...) \
+-    Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__));
++    Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
+ 
+ #define CATCH_ERROR(...) \
+-    Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ));
++    Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+ 
+ #define CATCH_RUNTIME_ERROR(...) \
+-    Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ));
++    Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+ 
+ #define CATCH_ENFORCE( condition, ... ) \
+     do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
+@@ -3816,7 +3951,6 @@ namespace Generators {
+     class SingleValueGenerator final : public IGenerator<T> {
+         T m_value;
+     public:
+-        SingleValueGenerator(T const& value) : m_value( value ) {}
+         SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
+ 
+         T const& get() const override {
+@@ -3829,6 +3963,9 @@ namespace Generators {
+ 
+     template<typename T>
+     class FixedValuesGenerator final : public IGenerator<T> {
++        static_assert(!std::is_same<T, bool>::value,
++            "FixedValuesGenerator does not support bools because of std::vector<bool>"
++            "specialization, use SingleValue Generator instead.");
+         std::vector<T> m_values;
+         size_t m_idx = 0;
+     public:
+@@ -3876,21 +4013,21 @@ namespace Generators {
+             m_generators.emplace_back(std::move(generator));
+         }
+         void populate(T&& val) {
+-            m_generators.emplace_back(value(std::move(val)));
++            m_generators.emplace_back(value(std::forward<T>(val)));
+         }
+         template<typename U>
+         void populate(U&& val) {
+-            populate(T(std::move(val)));
++            populate(T(std::forward<U>(val)));
+         }
+         template<typename U, typename... Gs>
+-        void populate(U&& valueOrGenerator, Gs... moreGenerators) {
++        void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {
+             populate(std::forward<U>(valueOrGenerator));
+             populate(std::forward<Gs>(moreGenerators)...);
+         }
+ 
+     public:
+         template <typename... Gs>
+-        Generators(Gs... moreGenerators) {
++        Generators(Gs &&... moreGenerators) {
+             m_generators.reserve(sizeof...(Gs));
+             populate(std::forward<Gs>(moreGenerators)...);
+         }
+@@ -3921,7 +4058,7 @@ namespace Generators {
+     struct as {};
+ 
+     template<typename T, typename... Gs>
+-    auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
++    auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
+         return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
+     }
+     template<typename T>
+@@ -3929,24 +4066,24 @@ namespace Generators {
+         return Generators<T>(std::move(generator));
+     }
+     template<typename T, typename... Gs>
+-    auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
++    auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {
+         return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+     }
+     template<typename T, typename U, typename... Gs>
+-    auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
++    auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
+         return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+     }
+ 
+-    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
++    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()));
+         }
+@@ -3959,11 +4096,17 @@ namespace Generators {
+ } // namespace Catch
+ 
+ #define GENERATE( ... ) \
+-    Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
++    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__ ); } )
++    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__ ); } )
++    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
+@@ -4048,6 +4191,9 @@ namespace Generators {
+ 
+     template <typename T>
+     class RepeatGenerator : public IGenerator<T> {
++        static_assert(!std::is_same<T, bool>::value,
++            "RepeatGenerator currently does not support bools"
++            "because of std::vector<bool> specialization");
+         GeneratorWrapper<T> m_generator;
+         mutable std::vector<T> m_returned;
+         size_t m_target_repeats;
+@@ -4126,18 +4272,7 @@ namespace Generators {
+         }
+     };
+ 
+-#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 MapFunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
+-#else
+-    template <typename Func, typename U>
+-    using MapFunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
+-#endif
+-
+-    template <typename Func, typename U, typename T = MapFunctionReturnType<Func, U>>
++    template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
+     GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+         return GeneratorWrapper<T>(
+             pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
+@@ -4162,12 +4297,14 @@ namespace Generators {
+             m_chunk_size(size), m_generator(std::move(generator))
+         {
+             m_chunk.reserve(m_chunk_size);
+-            m_chunk.push_back(m_generator.get());
+-            for (size_t i = 1; i < m_chunk_size; ++i) {
+-                if (!m_generator.next()) {
+-                    Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
+-                }
++            if (m_chunk_size != 0) {
+                 m_chunk.push_back(m_generator.get());
++                for (size_t i = 1; i < m_chunk_size; ++i) {
++                    if (!m_generator.next()) {
++                        Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
++                    }
++                    m_chunk.push_back(m_generator.get());
++                }
+             }
+         }
+         std::vector<T> const& get() const override {
+@@ -4238,6 +4375,7 @@ namespace Catch {
+     {
+         if( !IMutableContext::currentContext )
+             IMutableContext::createContext();
++        // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
+         return *IMutableContext::currentContext;
+     }
+ 
+@@ -4247,6 +4385,9 @@ namespace Catch {
+     }
+ 
+     void cleanUpContext();
++
++    class SimplePcg32;
++    SimplePcg32& rng();
+ }
+ 
+ // end catch_context.h
+@@ -4317,6 +4458,7 @@ namespace Catch {
+ } // end namespace Catch
+ 
+ // end catch_option.hpp
++#include <chrono>
+ #include <iosfwd>
+ #include <string>
+ #include <vector>
+@@ -4374,6 +4516,7 @@ namespace Catch {
+         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;
+@@ -4387,12 +4530,63 @@ namespace Catch {
+         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>;
+ }
+ 
+ // end catch_interfaces_config.h
++// start catch_random_number_generator.h
++
++#include <cstdint>
++
++namespace Catch {
++
++    // This is a simple implementation of C++11 Uniform Random Number
++    // Generator. It does not provide all operators, because Catch2
++    // does not use it, but it should behave as expected inside stdlib's
++    // distributions.
++    // The implementation is based on the PCG family (http://pcg-random.org)
++    class SimplePcg32 {
++        using state_type = std::uint64_t;
++    public:
++        using result_type = std::uint32_t;
++        static constexpr result_type (min)() {
++            return 0;
++        }
++        static constexpr result_type (max)() {
++            return static_cast<result_type>(-1);
++        }
++
++        // Provide some default initial state for the default constructor
++        SimplePcg32():SimplePcg32(0xed743cc4U) {}
++
++        explicit SimplePcg32(result_type seed_);
++
++        void seed(result_type seed_);
++        void discard(uint64_t skip);
++
++        result_type operator()();
++
++    private:
++        friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
++        friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
++
++        // In theory we also need operator<< and operator>>
++        // In practice we do not use them, so we will skip them for now
++
++        std::uint64_t m_state;
++        // This part of the state determines which "stream" of the numbers
++        // is chosen -- we take it as a constant for Catch2, so we only
++        // need to deal with seeding the main state.
++        // Picked by reading 8 bytes from `/dev/random` :-)
++        static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
++    };
++
++} // end namespace Catch
++
++// end catch_random_number_generator.h
+ #include <random>
+ 
+ namespace Catch {
+@@ -4400,14 +4594,13 @@ namespace Generators {
+ 
+ template <typename Float>
+ class RandomFloatingGenerator final : public IGenerator<Float> {
+-    // FIXME: What is the right seed?
+-    std::minstd_rand m_rand;
++    Catch::SimplePcg32& m_rng;
+     std::uniform_real_distribution<Float> m_dist;
+     Float m_current_number;
+ public:
+ 
+     RandomFloatingGenerator(Float a, Float b):
+-        m_rand(getCurrentContext().getConfig()->rngSeed()),
++        m_rng(rng()),
+         m_dist(a, b) {
+         static_cast<void>(next());
+     }
+@@ -4416,20 +4609,20 @@ public:
+         return m_current_number;
+     }
+     bool next() override {
+-        m_current_number = m_dist(m_rand);
++        m_current_number = m_dist(m_rng);
+         return true;
+     }
+ };
+ 
+ template <typename Integer>
+ class RandomIntegerGenerator final : public IGenerator<Integer> {
+-    std::minstd_rand m_rand;
++    Catch::SimplePcg32& m_rng;
+     std::uniform_int_distribution<Integer> m_dist;
+     Integer m_current_number;
+ public:
+ 
+     RandomIntegerGenerator(Integer a, Integer b):
+-        m_rand(getCurrentContext().getConfig()->rngSeed()),
++        m_rng(rng()),
+         m_dist(a, b) {
+         static_cast<void>(next());
+     }
+@@ -4438,7 +4631,7 @@ public:
+         return m_current_number;
+     }
+     bool next() override {
+-        m_current_number = m_dist(m_rand);
++        m_current_number = m_dist(m_rng);
+         return true;
+     }
+ };
+@@ -4498,7 +4691,7 @@ public:
+ 
+ template <typename T>
+ GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
+-    static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
++    static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
+     return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
+ }
+ 
+@@ -4508,6 +4701,45 @@ GeneratorWrapper<T> range(T const& start
+     return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
+ }
+ 
++template <typename T>
++class IteratorGenerator final : public IGenerator<T> {
++    static_assert(!std::is_same<T, bool>::value,
++        "IteratorGenerator currently does not support bools"
++        "because of std::vector<bool> specialization");
++
++    std::vector<T> m_elems;
++    size_t m_current = 0;
++public:
++    template <typename InputIterator, typename InputSentinel>
++    IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
++        if (m_elems.empty()) {
++            Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values"));
++        }
++    }
++
++    T const& get() const override {
++        return m_elems[m_current];
++    }
++
++    bool next() override {
++        ++m_current;
++        return m_current != m_elems.size();
++    }
++};
++
++template <typename InputIterator,
++          typename InputSentinel,
++          typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
++GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
++    return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));
++}
++
++template <typename Container,
++          typename ResultType = typename Container::value_type>
++GeneratorWrapper<ResultType> from_range(Container const& cnt) {
++    return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));
++}
++
+ } // namespace Generators
+ } // namespace Catch
+ 
+@@ -4711,7 +4943,7 @@ namespace Catch {
+                     arcSafeRelease( m_substr );
+                 }
+ 
+-                bool match( NSString* const& str ) const override {
++                bool match( NSString* str ) const override {
+                     return false;
+                 }
+ 
+@@ -4721,7 +4953,7 @@ namespace Catch {
+             struct Equals : StringHolder {
+                 Equals( NSString* substr ) : StringHolder( substr ){}
+ 
+-                bool match( NSString* const& str ) const override {
++                bool match( NSString* str ) const override {
+                     return  (str != nil || m_substr == nil ) &&
+                             [str isEqualToString:m_substr];
+                 }
+@@ -4734,7 +4966,7 @@ namespace Catch {
+             struct Contains : StringHolder {
+                 Contains( NSString* substr ) : StringHolder( substr ){}
+ 
+-                bool match( NSString* const& str ) const override {
++                bool match( NSString* str ) const override {
+                     return  (str != nil || m_substr == nil ) &&
+                             [str rangeOfString:m_substr].location != NSNotFound;
+                 }
+@@ -4747,7 +4979,7 @@ namespace Catch {
+             struct StartsWith : StringHolder {
+                 StartsWith( NSString* substr ) : StringHolder( substr ){}
+ 
+-                bool match( NSString* const& str ) const override {
++                bool match( NSString* str ) const override {
+                     return  (str != nil || m_substr == nil ) &&
+                             [str rangeOfString:m_substr].location == 0;
+                 }
+@@ -4759,7 +4991,7 @@ namespace Catch {
+             struct EndsWith : StringHolder {
+                 EndsWith( NSString* substr ) : StringHolder( substr ){}
+ 
+-                bool match( NSString* const& str ) const override {
++                bool match( NSString* str ) const override {
+                     return  (str != nil || m_substr == nil ) &&
+                             [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+                 }
+@@ -4853,7 +5085,7 @@ namespace Catch
+         virtual bool matches( std::string const& str ) const;
+ 
+     private:
+-        std::string adjustCase( std::string const& str ) const;
++        std::string normaliseString( std::string const& str ) const;
+         CaseSensitive::Choice m_caseSensitivity;
+         WildcardPosition m_wildcard = NoWildcard;
+         std::string m_pattern;
+@@ -4867,17 +5099,23 @@ namespace Catch
+ 
+ namespace Catch {
+ 
++    struct IConfig;
++
+     class TestSpec {
+-        struct Pattern {
++        class Pattern {
++        public:
++            explicit Pattern( std::string const& name );
+             virtual ~Pattern();
+             virtual bool matches( TestCaseInfo const& testCase ) const = 0;
++            std::string const& name() const;
++        private:
++            std::string const m_name;
+         };
+         using PatternPtr = std::shared_ptr<Pattern>;
+ 
+         class NamePattern : public Pattern {
+         public:
+-            NamePattern( std::string const& name );
+-            virtual ~NamePattern();
++            explicit NamePattern( std::string const& name, std::string const& filterString );
+             bool matches( TestCaseInfo const& testCase ) const override;
+         private:
+             WildcardPattern m_wildcardPattern;
+@@ -4885,8 +5123,7 @@ namespace Catch {
+ 
+         class TagPattern : public Pattern {
+         public:
+-            TagPattern( std::string const& tag );
+-            virtual ~TagPattern();
++            explicit TagPattern( std::string const& tag, std::string const& filterString );
+             bool matches( TestCaseInfo const& testCase ) const override;
+         private:
+             std::string m_tag;
+@@ -4894,8 +5131,7 @@ namespace Catch {
+ 
+         class ExcludedPattern : public Pattern {
+         public:
+-            ExcludedPattern( PatternPtr const& underlyingPattern );
+-            virtual ~ExcludedPattern();
++            explicit ExcludedPattern( PatternPtr const& underlyingPattern );
+             bool matches( TestCaseInfo const& testCase ) const override;
+         private:
+             PatternPtr m_underlyingPattern;
+@@ -4905,15 +5141,25 @@ namespace Catch {
+             std::vector<PatternPtr> m_patterns;
+ 
+             bool matches( TestCaseInfo const& testCase ) const;
++            std::string name() const;
+         };
+ 
+     public:
++        struct FilterMatch {
++            std::string name;
++            std::vector<TestCase const*> tests;
++        };
++        using Matches = std::vector<FilterMatch>;
++        using vectorStrings = std::vector<std::string>;
++
+         bool hasFilters() const;
+         bool matches( TestCaseInfo const& testCase ) const;
++        Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;
++        const vectorStrings & getInvalidArgs() const;
+ 
+     private:
+         std::vector<Filter> m_filters;
+-
++        std::vector<std::string> m_invalidArgs;
+         friend class TestSpecParser;
+     };
+ }
+@@ -4948,9 +5194,13 @@ namespace Catch {
+     class TestSpecParser {
+         enum Mode{ None, Name, QuotedName, Tag, EscapedName };
+         Mode m_mode = None;
++        Mode lastMode = None;
+         bool m_exclusion = false;
+-        std::size_t m_start = std::string::npos, m_pos = 0;
++        std::size_t m_pos = 0;
++        std::size_t m_realPatternPos = 0;
+         std::string m_arg;
++        std::string m_substring;
++        std::string m_patternName;
+         std::vector<std::size_t> m_escapeChars;
+         TestSpec::Filter m_currentFilter;
+         TestSpec m_testSpec;
+@@ -4963,32 +5213,32 @@ namespace Catch {
+         TestSpec testSpec();
+ 
+     private:
+-        void visitChar( char c );
+-        void startNewMode( Mode mode, std::size_t start );
++        bool visitChar( char c );
++        void startNewMode( Mode mode );
++        bool processNoneChar( char c );
++        void processNameChar( char c );
++        bool processOtherChar( char c );
++        void endMode();
+         void escape();
+-        std::string subString() const;
++        bool isControlChar( char c ) const;
++        void saveLastMode();
++        void revertBackToLastMode();
++        void addFilter();
++        bool separate();
+ 
+-        template<typename T>
+-        void addPattern() {
+-            std::string token = subString();
+-            for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
+-                token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
+-            m_escapeChars.clear();
+-            if( startsWith( token, "exclude:" ) ) {
+-                m_exclusion = true;
+-                token = token.substr( 8 );
+-            }
+-            if( !token.empty() ) {
+-                TestSpec::PatternPtr pattern = std::make_shared<T>( token );
+-                if( m_exclusion )
+-                    pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
+-                m_currentFilter.m_patterns.push_back( pattern );
+-            }
+-            m_exclusion = false;
+-            m_mode = None;
++        // Handles common preprocessing of the pattern for name/tag patterns
++        std::string preprocessPattern();
++        // Adds the current pattern as a test name
++        void addNamePattern();
++        // Adds the current pattern as a tag
++        void addTagPattern();
++
++        inline void addCharToPattern(char c) {
++            m_substring += c;
++            m_patternName += c;
++            m_realPatternPos++;
+         }
+ 
+-        void addFilter();
+     };
+     TestSpec parseTestSpec( std::string const& arg );
+ 
+@@ -5034,10 +5284,12 @@ namespace Catch {
+         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;
+@@ -5088,6 +5340,7 @@ namespace Catch {
+         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;
+@@ -5099,6 +5352,7 @@ namespace Catch {
+         int benchmarkSamples() const override;
+         double benchmarkConfidenceInterval() const override;
+         unsigned int benchmarkResamples() const override;
++        std::chrono::milliseconds benchmarkWarmupTime() const override;
+ 
+     private:
+ 
+@@ -5204,6 +5458,8 @@ namespace Catch {
+ } // namespace Catch
+ 
+ // end catch_outlier_classification.hpp
++
++#include <iterator>
+ #endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+ 
+ #include <string>
+@@ -5396,6 +5652,8 @@ namespace Catch {
+ 
+         virtual void noMatchingTestCases( std::string const& spec ) = 0;
+ 
++        virtual void reportInvalidArguments(std::string const&) {}
++
+         virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+         virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+ 
+@@ -5462,6 +5720,9 @@ namespace Catch {
+     // 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>
+@@ -5488,6 +5749,8 @@ namespace Catch {
+ 
+         void noMatchingTestCases(std::string const&) override {}
+ 
++        void reportInvalidArguments(std::string const&) override {}
++
+         void testRunStarting(TestRunInfo const& _testRunInfo) override {
+             currentTestRunInfo = _testRunInfo;
+         }
+@@ -5822,14 +6085,16 @@ namespace Catch {
+ #if !defined(CATCH_CONFIG_DISABLE)
+ 
+ #define CATCH_REGISTER_REPORTER( name, reporterType ) \
++    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION         \
+     CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS          \
+     namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
+-    CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
++    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ 
+ #define CATCH_REGISTER_LISTENER( listenerType ) \
+-     CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS   \
+-     namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
+-     CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
++    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION   \
++    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS    \
++    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
++    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ #else // CATCH_CONFIG_DISABLE
+ 
+ #define CATCH_REGISTER_REPORTER(name, reporterType)
+@@ -5851,8 +6116,6 @@ namespace Catch {
+ 
+         static std::string getDescription();
+ 
+-        ReporterPreferences getPreferences() const override;
+-
+         void noMatchingTestCases(std::string const& spec) override;
+ 
+         void assertionStarting(AssertionInfo const&) override;
+@@ -5891,6 +6154,8 @@ namespace Catch {
+ 
+         void noMatchingTestCases(std::string const& spec) override;
+ 
++        void reportInvalidArguments(std::string const&arg) override;
++
+         void assertionStarting(AssertionInfo const&) override;
+ 
+         bool assertionEnded(AssertionStats const& _assertionStats) override;
+@@ -5950,6 +6215,14 @@ namespace Catch {
+ #include <vector>
+ 
+ namespace Catch {
++    enum class XmlFormatting {
++        None = 0x00,
++        Indent = 0x01,
++        Newline = 0x02,
++    };
++
++    XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
++    XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
+ 
+     class XmlEncode {
+     public:
+@@ -5971,14 +6244,14 @@ namespace Catch {
+ 
+         class ScopedElement {
+         public:
+-            ScopedElement( XmlWriter* writer );
++            ScopedElement( XmlWriter* writer, XmlFormatting fmt );
+ 
+             ScopedElement( ScopedElement&& other ) noexcept;
+             ScopedElement& operator=( ScopedElement&& other ) noexcept;
+ 
+             ~ScopedElement();
+ 
+-            ScopedElement& writeText( std::string const& text, bool indent = true );
++            ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );
+ 
+             template<typename T>
+             ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+@@ -5988,6 +6261,7 @@ namespace Catch {
+ 
+         private:
+             mutable XmlWriter* m_writer = nullptr;
++            XmlFormatting m_fmt;
+         };
+ 
+         XmlWriter( std::ostream& os = Catch::cout() );
+@@ -5996,11 +6270,11 @@ namespace Catch {
+         XmlWriter( XmlWriter const& ) = delete;
+         XmlWriter& operator=( XmlWriter const& ) = delete;
+ 
+-        XmlWriter& startElement( std::string const& name );
++        XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+ 
+-        ScopedElement scopedElement( std::string const& name );
++        ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+ 
+-        XmlWriter& endElement();
++        XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+ 
+         XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
+ 
+@@ -6013,9 +6287,9 @@ namespace Catch {
+             return writeAttribute( name, rss.str() );
+         }
+ 
+-        XmlWriter& writeText( std::string const& text, bool indent = true );
++        XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+ 
+-        XmlWriter& writeComment( std::string const& text );
++        XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+ 
+         void writeStylesheetRef( std::string const& url );
+ 
+@@ -6025,6 +6299,8 @@ namespace Catch {
+ 
+     private:
+ 
++        void applyFormatting(XmlFormatting fmt);
++
+         void writeDeclaration();
+ 
+         void newlineIfNecessary();
+@@ -6068,9 +6344,10 @@ namespace Catch {
+ 
+         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);
+@@ -6126,6 +6403,7 @@ namespace Catch {
+         void testRunEnded(TestRunStats const& testRunStats) override;
+ 
+ #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
++        void benchmarkPreparing(std::string const& name) override;
+         void benchmarkStarting(BenchmarkInfo const&) override;
+         void benchmarkEnded(BenchmarkStats<> const&) override;
+         void benchmarkFailed(std::string const&) override;
+@@ -6145,6 +6423,12 @@ namespace Catch {
+ #endif
+ 
+ #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
++// start catch_benchmarking_all.hpp
++
++// A proxy header that includes all of the benchmarking headers to allow
++// concise include of the benchmarking features. You should prefer the
++// individual includes in standard use.
++
+ // start catch_benchmark.hpp
+ 
+  // Benchmark
+@@ -6280,20 +6564,18 @@ namespace Catch {
+                     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{
+@@ -6538,8 +6820,8 @@ namespace Catch {
+             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
+ 
+@@ -6550,7 +6832,7 @@ namespace Catch {
+     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();
+@@ -6569,11 +6851,11 @@ namespace Catch {
+     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));
+ 
+@@ -6590,7 +6872,7 @@ namespace Catch {
+             };
+ 
+             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)>());
+@@ -6600,7 +6882,7 @@ namespace Catch {
+                     }
+                     iters *= 2;
+                 }
+-                throw optimized_away_error{};
++                Catch::throw_exception(optimized_away_error{});
+             }
+         } // namespace Detail
+     } // namespace Benchmark
+@@ -6608,6 +6890,7 @@ namespace Catch {
+ 
+ // end catch_run_for_at_least.hpp
+ #include <algorithm>
++#include <iterator>
+ 
+ namespace Catch {
+     namespace Benchmark {
+@@ -6658,11 +6941,13 @@ namespace Catch {
+ #include <algorithm>
+ #include <functional>
+ #include <vector>
++#include <iterator>
+ #include <numeric>
+ #include <tuple>
+ #include <cmath>
+ #include <utility>
+ #include <cstddef>
++#include <random>
+ 
+ namespace Catch {
+     namespace Benchmark {
+@@ -6776,8 +7061,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 };
+             }
+@@ -6846,7 +7131,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) {
+@@ -7012,10 +7299,10 @@ namespace Catch {
+             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>
+@@ -7047,7 +7334,7 @@ namespace Catch {
+                     });
+ 
+                     auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
+-                    BenchmarkStats<std::chrono::duration<double, std::nano>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
++                    BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
+                     getResultCapture().benchmarkEnded(stats);
+ 
+                 } CATCH_CATCH_ALL{
+@@ -7088,6 +7375,77 @@ namespace Catch {
+         BenchmarkName = [&]
+ 
+ // end catch_benchmark.hpp
++// start catch_constructor.hpp
++
++// Constructor and destructor helpers
++
++
++#include <type_traits>
++
++namespace Catch {
++    namespace Benchmark {
++        namespace Detail {
++            template <typename T, bool Destruct>
++            struct ObjectStorage
++            {
++                using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
++
++                ObjectStorage() : data() {}
++
++                ObjectStorage(const ObjectStorage& other)
++                {
++                    new(&data) T(other.stored_object());
++                }
++
++                ObjectStorage(ObjectStorage&& other)
++                {
++                    new(&data) T(std::move(other.stored_object()));
++                }
++
++                ~ObjectStorage() { destruct_on_exit<T>(); }
++
++                template <typename... Args>
++                void construct(Args&&... args)
++                {
++                    new (&data) T(std::forward<Args>(args)...);
++                }
++
++                template <bool AllowManualDestruction = !Destruct>
++                typename std::enable_if<AllowManualDestruction>::type destruct()
++                {
++                    stored_object().~T();
++                }
++
++            private:
++                // If this is a constructor benchmark, destruct the underlying object
++                template <typename U>
++                void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
++                // Otherwise, don't
++                template <typename U>
++                void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
++
++                T& stored_object() {
++                    return *static_cast<T*>(static_cast<void*>(&data));
++                }
++
++                T const& stored_object() const {
++                    return *static_cast<T*>(static_cast<void*>(&data));
++                }
++
++                TStorage data;
++            };
++        }
++
++        template <typename T>
++        using storage_for = Detail::ObjectStorage<T, true>;
++
++        template <typename T>
++        using destructable_object = Detail::ObjectStorage<T, false>;
++    }
++}
++
++// end catch_constructor.hpp
++// end catch_benchmarking_all.hpp
+ #endif
+ 
+ #endif // ! CATCH_CONFIG_IMPL_ONLY
+@@ -7115,23 +7473,37 @@ namespace TestCaseTracking {
+         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;
+ 
+@@ -7186,7 +7558,6 @@ namespace TestCaseTracking {
+         };
+ 
+         using Children = std::vector<ITrackerPtr>;
+-        NameAndLocation m_nameAndLocation;
+         TrackerContext& m_ctx;
+         ITracker* m_parent;
+         Children m_children;
+@@ -7195,11 +7566,13 @@ namespace TestCaseTracking {
+     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;
+ 
+@@ -7224,6 +7597,7 @@ namespace TestCaseTracking {
+ 
+     class SectionTracker : public TrackerBase {
+         std::vector<std::string> m_filters;
++        std::string m_trimmed_name;
+     public:
+         SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
+ 
+@@ -7237,6 +7611,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
+@@ -7402,7 +7780,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;
+ 
+@@ -7421,13 +7799,14 @@ 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) {
++                CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+                 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+                 static std::random_device entropy;
+-                CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
++                CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ 
+                 auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
+ 
+@@ -7515,7 +7894,8 @@ namespace Detail {
+     bool Approx::equalityComparisonImpl(const double other) const {
+         // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
+         // Thanks to Richard Harris for his help refining the scaled margin value
+-        return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
++        return marginComparison(m_value, other, m_margin)
++            || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
+     }
+ 
+     void Approx::setMargin(double newMargin) {
+@@ -7559,7 +7939,24 @@ namespace Catch {
+ 
+ #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)
++
++    // use inline assembler
++    #if defined(__i386__) || defined(__x86_64__)
++        #define CATCH_TRAP()  __asm__("int $3")
++    #elif defined(__aarch64__)
++        #define CATCH_TRAP()  __asm__(".inst 0xd4200000")
++    #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)
+     // If we can use inline assembler, do it because this allows us to break
+@@ -7579,10 +7976,12 @@ namespace Catch {
+     #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
+@@ -7590,86 +7989,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>
+@@ -7729,7 +8100,7 @@ namespace Catch {
+         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;
+@@ -7795,11 +8166,14 @@ 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;
+     };
+ 
++    void seedRng(IConfig const& config);
++    unsigned int rngSeed();
+ } // end namespace Catch
+ 
+ // end catch_run_context.h
+@@ -7946,7 +8320,7 @@ namespace Catch {
+     }
+ 
+     bool AssertionResult::hasExpression() const {
+-        return m_info.capturedExpression[0] != 0;
++        return !m_info.capturedExpression.empty();
+     }
+ 
+     bool AssertionResult::hasMessage() const {
+@@ -7954,16 +8328,22 @@ namespace Catch {
+     }
+ 
+     std::string AssertionResult::getExpression() const {
+-        if( isFalseTest( m_info.resultDisposition ) )
+-            return "!(" + m_info.capturedExpression + ")";
+-        else
+-            return m_info.capturedExpression;
++        // Possibly overallocating by 3 characters should be basically free
++        std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
++        if (isFalseTest(m_info.resultDisposition)) {
++            expr += "!(";
++        }
++        expr += m_info.capturedExpression;
++        if (isFalseTest(m_info.resultDisposition)) {
++            expr += ')';
++        }
++        return expr;
+     }
+ 
+     std::string AssertionResult::getExpressionInMacro() const {
+         std::string expr;
+-        if( m_info.macroName[0] == 0 )
+-            expr = m_info.capturedExpression;
++        if( m_info.macroName.empty() )
++            expr = static_cast<std::string>(m_info.capturedExpression);
+         else {
+             expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
+             expr += m_info.macroName;
+@@ -8697,7 +9077,7 @@ namespace detail {
+     }
+     inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
+         std::string srcLC = source;
+-        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( 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")
+@@ -9345,9 +9725,14 @@ namespace Catch {
+                     if( !line.empty() && !startsWith( line, '#' ) ) {
+                         if( !startsWith( line, '"' ) )
+                             line = '"' + line + '"';
+-                        config.testsOrTags.push_back( line + ',' );
++                        config.testsOrTags.push_back( line );
++                        config.testsOrTags.emplace_back( "," );
+                     }
+                 }
++                //Remove comma in the end
++                if(!config.testsOrTags.empty())
++                    config.testsOrTags.erase( config.testsOrTags.end()-1 );
++
+                 return ParserResult::ok( ParseResultType::Matched );
+             };
+         auto const setTestOrder = [&]( std::string const& order ) {
+@@ -9382,14 +9767,16 @@ namespace Catch {
+             };
+         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 ) {
+@@ -9459,6 +9846,9 @@ namespace Catch {
+             | 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" )
+@@ -9489,7 +9879,7 @@ namespace Catch {
+             | 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" )
+@@ -9504,7 +9894,10 @@ namespace Catch {
+             | 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;
+@@ -9519,9 +9912,6 @@ namespace Catch {
+ 
+ namespace Catch {
+ 
+-    bool SourceLineInfo::empty() const noexcept {
+-        return file[0] == '\0';
+-    }
+     bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
+         return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
+     }
+@@ -9557,11 +9947,23 @@ namespace Catch {
+     :   m_data( data ),
+         m_stream( openStream() )
+     {
++        // We need to trim filter specs to avoid trouble with superfluous
++        // whitespace (esp. important for bdd macros, as those are manually
++        // aligned with whitespace).
++
++        for (auto& elem : m_data.testsOrTags) {
++            elem = trim(elem);
++        }
++        for (auto& elem : m_data.sectionsToRun) {
++            elem = trim(elem);
++        }
++
+         TestSpecParser parser(ITagAliasRegistry::get());
+-        if (!data.testsOrTags.empty()) {
++        if (!m_data.testsOrTags.empty()) {
+             m_hasTestFilters = true;
+-            for( auto const& testOrTags : data.testsOrTags )
+-                parser.parse( testOrTags );
++            for (auto const& testOrTags : m_data.testsOrTags) {
++                parser.parse(testOrTags);
++            }
+         }
+         m_testSpec = parser.testSpec();
+     }
+@@ -9594,6 +9996,7 @@ namespace Catch {
+     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; }
+@@ -9602,10 +10005,11 @@ namespace Catch {
+     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);
+@@ -9635,6 +10039,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 {
+@@ -9646,7 +10080,7 @@ namespace Catch {
+         };
+ 
+         struct NoColourImpl : IColourImpl {
+-            void use( Colour::Code ) {}
++            void use( Colour::Code ) override {}
+ 
+             static IColourImpl* instance() {
+                 static NoColourImpl s_instance;
+@@ -9778,7 +10212,7 @@ namespace {
+ 
+     bool useColourOnPlatform() {
+         return
+-#ifdef CATCH_PLATFORM_MAC
++#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
+             !isDebuggerActive() &&
+ #endif
+ #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
+@@ -9819,13 +10253,13 @@ namespace Catch {
+ 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;
+     }
+ 
+@@ -9837,7 +10271,7 @@ namespace Catch {
+         // 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 );
+         }
+     }
+@@ -9906,6 +10340,12 @@ namespace Catch {
+     IContext::~IContext() = default;
+     IMutableContext::~IMutableContext() = default;
+     Context::~Context() = default;
++
++    SimplePcg32& rng() {
++        static SimplePcg32 s_rng;
++        return s_rng;
++    }
++
+ }
+ // end catch_context.cpp
+ // start catch_debug_console.cpp
+@@ -9919,7 +10359,16 @@ namespace Catch {
+ }
+ 
+ // end catch_debug_console.h
+-#ifdef CATCH_PLATFORM_WINDOWS
++#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
++#include <android/log.h>
++
++    namespace Catch {
++        void writeToDebugConsole( std::string const& text ) {
++            __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
++        }
++    }
++
++#elif defined(CATCH_PLATFORM_WINDOWS)
+ 
+     namespace Catch {
+         void writeToDebugConsole( std::string const& text ) {
+@@ -9940,10 +10389,9 @@ namespace Catch {
+ // end catch_debug_console.cpp
+ // start catch_debugger.cpp
+ 
+-#ifdef CATCH_PLATFORM_MAC
++#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>
+@@ -10116,7 +10564,7 @@ namespace Catch {
+             EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
+         };
+ 
+-        std::vector<std::string> parseEnums( StringRef enums );
++        std::vector<StringRef> parseEnums( StringRef enums );
+ 
+     } // Detail
+ 
+@@ -10133,13 +10581,25 @@ namespace Catch {
+ 
+     namespace Detail {
+ 
+-        std::vector<std::string> parseEnums( StringRef enums ) {
++        namespace {
++            // 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 occurrence of ":"
++                size_t name_start = enumInstance.size();
++                while (name_start > 0 && enumInstance[name_start - 1] != ':') {
++                    --name_start;
++                }
++                return enumInstance.substr(name_start, enumInstance.size() - name_start);
++            }
++        }
++
++        std::vector<StringRef> parseEnums( StringRef enums ) {
+             auto enumValues = splitStringRef( enums, ',' );
+-            std::vector<std::string> parsed;
++            std::vector<StringRef> parsed;
+             parsed.reserve( enumValues.size() );
+             for( auto const& enumValue : enumValues ) {
+-                auto identifiers = splitStringRef( enumValue, ':' );
+-                parsed.push_back( Catch::trim( identifiers.back() ) );
++                parsed.push_back(trim(extractInstanceName(enumValue)));
+             }
+             return parsed;
+         }
+@@ -10151,7 +10611,7 @@ namespace Catch {
+                 if( valueToName.first == value )
+                     return valueToName.second;
+             }
+-            return "{** unexpected enum value **}";
++            return "{** unexpected enum value **}"_sr;
+         }
+ 
+         std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+@@ -10163,16 +10623,14 @@ namespace Catch {
+             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;
+         }
+ 
+         EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+-            auto enumInfo = makeEnumInfo( enumName, allValueNames, values );
+-            EnumInfo* raw = enumInfo.get();
+-            m_enumInfos.push_back( std::move( enumInfo ) );
+-            return *raw;
++            m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
++            return *m_enumInfos.back();
+         }
+ 
+     } // Detail
+@@ -10289,25 +10747,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.
+@@ -10320,7 +10800,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);
+@@ -10331,38 +10811,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 {
+ 
+@@ -10371,10 +10863,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.
+-    constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
+-
+     static SignalDefs signalDefs[] = {
+         { SIGINT,  "SIGINT - Terminal interrupt signal" },
+         { SIGILL,  "SIGILL - Illegal instruction signal" },
+@@ -10384,7 +10872,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) {
+@@ -10392,16 +10905,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 = { };
+@@ -10413,59 +10943,20 @@ 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__)
+ #    pragma GCC diagnostic pop
+ #endif
+-// end catch_fatal_condition.cpp
+-// start catch_generators.cpp
+ 
+-// start catch_random_number_generator.h
+-
+-#include <algorithm>
+-#include <random>
+-
+-namespace Catch {
+-
+-    struct IConfig;
++    void FatalConditionHandler::disengage_platform() {
++        restorePreviousSignalHandlers();
++    }
+ 
+-    std::mt19937& rng();
+-    void seedRng( IConfig const& config );
+-    unsigned int rngSeed();
++} // end namespace Catch
+ 
+-}
++#endif // CATCH_CONFIG_POSIX_SIGNALS
++// end catch_fatal_condition.cpp
++// start catch_generators.cpp
+ 
+-// end catch_random_number_generator.h
+ #include <limits>
+ #include <set>
+ 
+@@ -10481,8 +10972,8 @@ namespace Generators {
+ 
+     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
+@@ -10538,6 +11029,8 @@ namespace Catch {
+ 
+         void noMatchingTestCases( std::string const& spec ) override;
+ 
++        void reportInvalidArguments(std::string const&arg) override;
++
+         static std::set<Verbosity> getSupportedVerbosities();
+ 
+ #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+@@ -10755,7 +11248,7 @@ namespace Catch {
+ 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 {
+@@ -10789,7 +11282,7 @@ namespace Catch {
+     }
+ 
+     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 ) {
+@@ -10811,14 +11304,23 @@ namespace Catch {
+     }
+ 
+     std::string TagInfo::all() const {
+-        std::string out;
+-        for( auto const& spelling : spellings )
+-            out += "[" + spelling + "]";
++        size_t size = 0;
++        for (auto const& spelling : spellings) {
++            // Add 2 for the brackes
++            size += spelling.size() + 2;
++        }
++
++        std::string out; out.reserve(size);
++        for (auto const& spelling : spellings) {
++            out += '[';
++            out += spelling;
++            out += ']';
++        }
+         return out;
+     }
+ 
+     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 {
+@@ -10912,6 +11414,29 @@ using Matchers::Impl::MatcherBase;
+ 
+ } // namespace Catch
+ // end catch_matchers.cpp
++// start catch_matchers_exception.cpp
++
++namespace Catch {
++namespace Matchers {
++namespace Exception {
++
++bool ExceptionMessageMatcher::match(std::exception const& ex) const {
++    return ex.what() == m_message;
++}
++
++std::string ExceptionMessageMatcher::describe() const {
++    return "exception message matches \"" + m_message + "\"";
++}
++
++}
++Exception::ExceptionMessageMatcher Message(std::string const& message) {
++    return Exception::ExceptionMessageMatcher(message);
++}
++
++// namespace Exception
++} // namespace Matchers
++} // namespace Catch
++// end catch_matchers_exception.cpp
+ // start catch_matchers_floating.cpp
+ 
+ // start catch_polyfills.hpp
+@@ -10940,85 +11465,101 @@ namespace Catch {
+ } // end namespace Catch
+ 
+ // end catch_to_string.hpp
++#include <algorithm>
++#include <cmath>
+ #include <cstdlib>
+ #include <cstdint>
+ #include <cstring>
+ #include <sstream>
++#include <type_traits>
+ #include <iomanip>
+ #include <limits>
+ 
+ namespace Catch {
+-namespace Matchers {
+-namespace Floating {
+-enum class FloatingPointKind : uint8_t {
+-    Float,
+-    Double
+-};
+-}
+-}
+-}
+-
+ namespace {
+ 
+-template <typename T>
+-struct Converter;
+-
+-template <>
+-struct Converter<float> {
+-    static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
+-    Converter(float f) {
++    int32_t convert(float f) {
++        static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
++        int32_t i;
+         std::memcpy(&i, &f, sizeof(f));
++        return i;
+     }
+-    int32_t i;
+-};
+ 
+-template <>
+-struct Converter<double> {
+-    static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
+-    Converter(double d) {
++    int64_t convert(double d) {
++        static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
++        int64_t i;
+         std::memcpy(&i, &d, sizeof(d));
++        return i;
+     }
+-    int64_t i;
+-};
+ 
+-template <typename T>
+-auto convert(T t) -> Converter<T> {
+-    return Converter<T>(t);
+-}
++    template <typename FP>
++    bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
++        // Comparison with NaN should always be false.
++        // This way we can rule it out before getting into the ugly details
++        if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
++            return false;
++        }
+ 
+-template <typename FP>
+-bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
+-    // Comparison with NaN should always be false.
+-    // This way we can rule it out before getting into the ugly details
+-    if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
+-        return false;
++        auto lc = convert(lhs);
++        auto rc = convert(rhs);
++
++        if ((lc < 0) != (rc < 0)) {
++            // Potentially we can have +0 and -0
++            return lhs == rhs;
++        }
++
++        // static cast as a workaround for IBM XLC
++        auto ulpDiff = std::abs(static_cast<FP>(lc - rc));
++        return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
+     }
+ 
+-    auto lc = convert(lhs);
+-    auto rc = convert(rhs);
++#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+ 
+-    if ((lc.i < 0) != (rc.i < 0)) {
+-        // Potentially we can have +0 and -0
+-        return lhs == rhs;
++    float nextafter(float x, float y) {
++        return ::nextafterf(x, y);
+     }
+ 
+-    auto ulpDiff = std::abs(lc.i - rc.i);
+-    return ulpDiff <= maxUlpDiff;
+-}
++    double nextafter(double x, double y) {
++        return ::nextafter(x, y);
++    }
++
++#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
+ 
+ template <typename FP>
+-FP step(FP start, FP direction, int steps) {
+-    for (int i = 0; i < steps; ++i) {
++FP step(FP start, FP direction, uint64_t steps) {
++    for (uint64_t i = 0; i < steps; ++i) {
++#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
++        start = Catch::nextafter(start, direction);
++#else
+         start = std::nextafter(start, direction);
++#endif
+     }
+     return start;
+ }
+ 
++// Performs equivalent check of std::fabs(lhs - rhs) <= margin
++// But without the subtraction to allow for INFINITY in comparison
++bool marginComparison(double lhs, double rhs, double margin) {
++    return (lhs + margin >= rhs) && (rhs + margin >= lhs);
++}
++
++template <typename FloatingPoint>
++void write(std::ostream& out, FloatingPoint num) {
++    out << std::scientific
++        << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
++        << num;
++}
++
+ } // end anonymous namespace
+ 
+-namespace Catch {
+ namespace Matchers {
+ namespace Floating {
++
++    enum class FloatingPointKind : uint8_t {
++        Float,
++        Double
++    };
++
+     WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
+         :m_target{ target }, m_margin{ margin } {
+         CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
+@@ -11035,10 +11576,11 @@ namespace Floating {
+         return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
+     }
+ 
+-    WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
++    WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)
+         :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
+-        CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
+-            << " ULPs have to be non-negative.");
++        CATCH_ENFORCE(m_type == FloatingPointKind::Double
++                   || m_ulps < (std::numeric_limits<uint32_t>::max)(),
++            "Provided ULP is impossibly large for a float comparison.");
+     }
+ 
+ #if defined(__clang__)
+@@ -11065,36 +11607,57 @@ namespace Floating {
+     std::string WithinUlpsMatcher::describe() const {
+         std::stringstream ret;
+ 
+-        ret << "is within " << m_ulps << " ULPs of " << ::Catch::Detail::stringify(m_target);
++        ret << "is within " << m_ulps << " ULPs of ";
+ 
+         if (m_type == FloatingPointKind::Float) {
++            write(ret, static_cast<float>(m_target));
+             ret << 'f';
++        } else {
++            write(ret, m_target);
+         }
+ 
+         ret << " ([";
+-        ret << std::fixed << std::setprecision(std::numeric_limits<double>::max_digits10);
+         if (m_type == FloatingPointKind::Double) {
+-            ret << step(m_target, static_cast<double>(-INFINITY), m_ulps)
+-                << ", "
+-                << step(m_target, static_cast<double>(INFINITY), m_ulps);
++            write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));
++            ret << ", ";
++            write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));
+         } else {
+-            ret << step<float>(static_cast<float>(m_target), -INFINITY, m_ulps)
+-                << ", "
+-                << step<float>(static_cast<float>(m_target), INFINITY, m_ulps);
++            // We have to cast INFINITY to float because of MinGW, see #1782
++            write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));
++            ret << ", ";
++            write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));
+         }
+         ret << "])";
+ 
+         return ret.str();
+-        //return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
++    }
++
++    WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
++        m_target(target),
++        m_epsilon(epsilon){
++        CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon <  0 does not make sense.");
++        CATCH_ENFORCE(m_epsilon  < 1., "Relative comparison with epsilon >= 1 does not make sense.");
++    }
++
++    bool WithinRelMatcher::match(double const& matchee) const {
++        const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
++        return marginComparison(matchee, m_target,
++                                std::isinf(relMargin)? 0 : relMargin);
++    }
++
++    std::string WithinRelMatcher::describe() const {
++        Catch::ReusableStringStream sstr;
++        sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";
++        return sstr.str();
+     }
+ 
+ }// namespace Floating
+ 
+-Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
++Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
+     return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
+ }
+ 
+-Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
++Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
+     return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
+ }
+ 
+@@ -11102,9 +11665,24 @@ Floating::WithinAbsMatcher WithinAbs(dou
+     return Floating::WithinAbsMatcher(target, margin);
+ }
+ 
++Floating::WithinRelMatcher WithinRel(double target, double eps) {
++    return Floating::WithinRelMatcher(target, eps);
++}
++
++Floating::WithinRelMatcher WithinRel(double target) {
++    return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
++}
++
++Floating::WithinRelMatcher WithinRel(float target, float eps) {
++    return Floating::WithinRelMatcher(target, eps);
++}
++
++Floating::WithinRelMatcher WithinRel(float target) {
++    return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
++}
++
+ } // namespace Matchers
+ } // namespace Catch
+-
+ // end catch_matchers_floating.cpp
+ // start catch_matchers_generic.cpp
+ 
+@@ -11282,10 +11860,10 @@ namespace Catch {
+ 
+     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);
+@@ -11324,17 +11902,17 @@ namespace Catch {
+                 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 = trimmed(start, pos);
++                    m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
+                     m_messages.back().message += " := ";
+                     start = pos;
+                 }
+             }
+         }
+-        assert(openings.size() == 0 && "Mismatched openings");
++        assert(openings.empty() && "Mismatched openings");
+         m_messages.emplace_back(macroName, lineInfo, resultType);
+-        m_messages.back().message = trimmed(start, names.size() - 1);
++        m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
+         m_messages.back().message += " := ";
+     }
+     Capturer::~Capturer() {
+@@ -11520,7 +12098,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");
+@@ -11628,20 +12206,61 @@ namespace Catch {
+ 
+ namespace Catch {
+ 
+-    std::mt19937& rng() {
+-        static std::mt19937 s_rng;
+-        return s_rng;
++namespace {
++
++#if defined(_MSC_VER)
++#pragma warning(push)
++#pragma warning(disable:4146) // we negate uint32 during the rotate
++#endif
++        // Safe rotr implementation thanks to John Regehr
++        uint32_t rotate_right(uint32_t val, uint32_t count) {
++            const uint32_t mask = 31;
++            count &= mask;
++            return (val >> count) | (val << (-count & mask));
++        }
++
++#if defined(_MSC_VER)
++#pragma warning(pop)
++#endif
++
++}
++
++    SimplePcg32::SimplePcg32(result_type seed_) {
++        seed(seed_);
++    }
++
++    void SimplePcg32::seed(result_type seed_) {
++        m_state = 0;
++        (*this)();
++        m_state += seed_;
++        (*this)();
+     }
+ 
+-    void seedRng( IConfig const& config ) {
+-        if( config.rngSeed() != 0 ) {
+-            std::srand( config.rngSeed() );
+-            rng().seed( config.rngSeed() );
++    void SimplePcg32::discard(uint64_t skip) {
++        // We could implement this to run in O(log n) steps, but this
++        // should suffice for our use case.
++        for (uint64_t s = 0; s < skip; ++s) {
++            static_cast<void>((*this)());
+         }
+     }
+ 
+-    unsigned int rngSeed() {
+-        return getCurrentContext().getConfig()->rngSeed();
++    SimplePcg32::result_type SimplePcg32::operator()() {
++        // prepare the output value
++        const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
++        const auto output = rotate_right(xorshifted, m_state >> 59u);
++
++        // advance state
++        m_state = m_state * 6364136223846793005ULL + s_inc;
++
++        return output;
++    }
++
++    bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
++        return lhs.m_state == rhs.m_state;
++    }
++
++    bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
++        return lhs.m_state != rhs.m_state;
+     }
+ }
+ // end catch_random_number_generator.cpp
+@@ -11660,6 +12279,8 @@ namespace Catch {
+     struct IConfig;
+ 
+     std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
++
++    bool isThrowSafe( TestCase const& testCase, IConfig const& config );
+     bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+ 
+     void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
+@@ -11772,11 +12393,13 @@ namespace Catch {
+ 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
+@@ -11859,7 +12482,11 @@ namespace Catch {
+                 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;
+@@ -11963,17 +12590,32 @@ namespace Catch {
+                 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, &currentTracker );
+                     currentTracker.addChild( tracker );
+                 }
+ 
+-                if( !ctx.completedCycle() && !tracker->isComplete() ) {
++                if( !tracker->isComplete() ) {
+                     tracker->open();
+                 }
+ 
+@@ -11987,8 +12629,68 @@ namespace Catch {
+             }
+             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;
+                 }
+@@ -12124,10 +12826,10 @@ namespace Catch {
+ 
+         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;
+     }
+@@ -12170,17 +12872,17 @@ namespace Catch {
+ 
+ #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) {
+@@ -12216,7 +12918,7 @@ namespace Catch {
+         // Don't rebuild the result -- the stringification itself can cause more fatal errors
+         // Instead, fake a result data.
+         AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
+-        tempResult.message = message;
++        tempResult.message = static_cast<std::string>(message);
+         AssertionResult result(m_lastAssertionInfo, tempResult);
+ 
+         assertionEnded(result);
+@@ -12314,9 +13016,8 @@ namespace Catch {
+     }
+ 
+     void RunContext::invokeActiveTestCase() {
+-        FatalConditionHandler fatalConditionHandler; // Handle signals
++        FatalConditionHandlerGuard _(&m_fatalConditionhandler);
+         m_activeTestCase->invoke();
+-        fatalConditionHandler.reset();
+     }
+ 
+     void RunContext::handleUnfinishedSections() {
+@@ -12379,7 +13080,7 @@ namespace Catch {
+         m_lastAssertionInfo = info;
+ 
+         AssertionResultData data( resultType, LazyExpression( false ) );
+-        data.message = message;
++        data.message = static_cast<std::string>(message);
+         AssertionResult assertionResult{ m_lastAssertionInfo, data };
+         assertionEnded( assertionResult );
+         if( !assertionResult.isOk() )
+@@ -12442,6 +13143,18 @@ namespace Catch {
+         else
+             CATCH_INTERNAL_ERROR("No result capture instance");
+     }
++
++    void seedRng(IConfig const& config) {
++        if (config.rngSeed() != 0) {
++            std::srand(config.rngSeed());
++            rng().seed(config.rngSeed());
++        }
++    }
++
++    unsigned int rngSeed() {
++        return getCurrentContext().getConfig()->rngSeed();
++    }
++
+ }
+ // end catch_run_context.cpp
+ // start catch_section.cpp
+@@ -12503,7 +13216,7 @@ namespace Catch {
+         void libIdentify();
+ 
+         int applyCommandLine( int argc, char const * const * argv );
+-    #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
++    #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
+         int applyCommandLine( int argc, wchar_t const * const * argv );
+     #endif
+ 
+@@ -12570,6 +13283,8 @@ namespace Catch {
+ // end catch_version.h
+ #include <cstdlib>
+ #include <iomanip>
++#include <set>
++#include <iterator>
+ 
+ namespace Catch {
+ 
+@@ -12603,45 +13318,61 @@ namespace Catch {
+             return ret;
+         }
+ 
+-        Catch::Totals runTests(std::shared_ptr<Config> const& config) {
+-            auto reporter = makeReporter(config);
+-
+-            RunContext context(config, std::move(reporter));
+-
+-            Totals totals;
+-
+-            context.testGroupStarting(config->name(), 1, 1);
+-
+-            TestSpec testSpec = config->testSpec();
+-
+-            auto const& allTestCases = getAllTestCasesSorted(*config);
+-            for (auto const& testCase : allTestCases) {
+-                bool matching = (!testSpec.hasFilters() && !testCase.isHidden()) ||
+-                                 (testSpec.hasFilters() && matchTest(testCase, testSpec, *config));
+-
+-                if (!context.aborting() && matching)
+-                    totals += context.runTest(testCase);
+-                else
+-                    context.reporter().skipTest(testCase);
++        class TestGroup {
++        public:
++            explicit TestGroup(std::shared_ptr<Config> const& config)
++            : m_config{config}
++            , m_context{config, makeReporter(config)}
++            {
++                auto const& allTestCases = getAllTestCasesSorted(*m_config);
++                m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
++                auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
++
++                if (m_matches.empty() && invalidArgs.empty()) {
++                    for (auto const& test : allTestCases)
++                        if (!test.isHidden())
++                            m_tests.emplace(&test);
++                } else {
++                    for (auto const& match : m_matches)
++                        m_tests.insert(match.tests.begin(), match.tests.end());
++                }
+             }
+ 
+-            if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
+-                ReusableStringStream testConfig;
++            Totals execute() {
++                auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
++                Totals totals;
++                m_context.testGroupStarting(m_config->name(), 1, 1);
++                for (auto const& testCase : m_tests) {
++                    if (!m_context.aborting())
++                        totals += m_context.runTest(*testCase);
++                    else
++                        m_context.reporter().skipTest(*testCase);
++                }
+ 
+-                bool first = true;
+-                for (const auto& input : config->getTestsOrTags()) {
+-                    if (!first) { testConfig << ' '; }
+-                    first = false;
+-                    testConfig << input;
++                for (auto const& match : m_matches) {
++                    if (match.tests.empty()) {
++                        m_context.reporter().noMatchingTestCases(match.name);
++                        totals.error = -1;
++                    }
++                }
++
++                if (!invalidArgs.empty()) {
++                    for (auto const& invalidArg: invalidArgs)
++                         m_context.reporter().reportInvalidArguments(invalidArg);
+                 }
+ 
+-                context.reporter().noMatchingTestCases(testConfig.str());
+-                totals.error = -1;
++                m_context.testGroupEnded(m_config->name(), totals, 1, 1);
++                return totals;
+             }
+ 
+-            context.testGroupEnded(config->name(), totals, 1, 1);
+-            return totals;
+-        }
++        private:
++            using Tests = std::set<TestCase const*>;
++
++            std::shared_ptr<Config> m_config;
++            RunContext m_context;
++            Tests m_tests;
++            TestSpec::Matches m_matches;
++        };
+ 
+         void applyFilenamesAsTags(Catch::IConfig const& config) {
+             auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
+@@ -12710,7 +13441,7 @@ namespace Catch {
+     }
+     void Session::libIdentify() {
+         Catch::cout()
+-                << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
++                << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
+                 << std::left << std::setw(16) << "category: " << "testframework\n"
+                 << std::left << std::setw(16) << "framework: " << "Catch Test\n"
+                 << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
+@@ -12741,17 +13472,17 @@ namespace Catch {
+         return 0;
+     }
+ 
+-#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
++#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
+     int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
+ 
+         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 );
+@@ -12818,7 +13549,12 @@ namespace Catch {
+             if( Option<std::size_t> listed = list( m_config ) )
+                 return static_cast<int>( *listed );
+ 
+-            auto totals = runTests( m_config );
++            TestGroup tests { m_config };
++            auto const totals = tests.execute();
++
++            if( m_config->warnAboutNoTests() && totals.error == -1 )
++                return 2;
++
+             // Note that on unices only the lower 8 bits are usually used, clamping
+             // the return value to 255 prevents false negative when some multiple
+             // of 256 tests has failed
+@@ -12866,6 +13602,7 @@ namespace Catch {
+ // 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 {
+@@ -12881,6 +13618,7 @@ void StartupExceptionRegistry::add( std:
+     }
+ 
+ } // end namespace Catch
++#endif
+ // end catch_startup_exception_registry.cpp
+ // start catch_stream.cpp
+ 
+@@ -13065,7 +13803,7 @@ namespace Catch {
+ 
+     namespace {
+         char toLowerCh(char c) {
+-            return static_cast<char>( std::tolower( c ) );
++            return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) );
+         }
+     }
+ 
+@@ -13100,6 +13838,18 @@ namespace Catch {
+         return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
+     }
+ 
++    StringRef trim(StringRef ref) {
++        const auto is_ws = [](char c) {
++            return c == ' ' || c == '\t' || c == '\n' || c == '\r';
++        };
++        size_t real_begin = 0;
++        while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
++        size_t real_end = ref.size();
++        while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
++
++        return ref.substr(real_begin, real_end - real_begin);
++    }
++
+     bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+         bool replaced = false;
+         std::size_t i = str.find( replaceThis );
+@@ -13145,124 +13895,46 @@ namespace Catch {
+ // end catch_string_manip.cpp
+ // start catch_stringref.cpp
+ 
+-#if defined(__clang__)
+-#    pragma clang diagnostic push
+-#    pragma clang diagnostic ignored "-Wexit-time-destructors"
+-#endif
+-
++#include <algorithm>
+ #include <ostream>
+ #include <cstring>
+ #include <cstdint>
+ 
+-namespace {
+-    const uint32_t byte_2_lead = 0xC0;
+-    const uint32_t byte_3_lead = 0xE0;
+-    const uint32_t byte_4_lead = 0xF0;
+-}
+-
+ namespace Catch {
+     StringRef::StringRef( char const* rawChars ) noexcept
+     : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
+     {}
+ 
+-    StringRef::operator std::string() const {
+-        return std::string( m_start, m_size );
+-    }
+-
+-    void StringRef::swap( StringRef& other ) noexcept {
+-        std::swap( m_start, other.m_start );
+-        std::swap( m_size, other.m_size );
+-        std::swap( m_data, other.m_data );
+-    }
+-
+     auto StringRef::c_str() const -> char const* {
+-        if( !isSubstring() )
+-            return m_start;
+-
+-        const_cast<StringRef *>( this )->takeOwnership();
+-        return m_data;
+-    }
+-    auto StringRef::currentData() const noexcept -> char const* {
++        CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");
+         return m_start;
+     }
+-
+-    auto StringRef::isOwned() const noexcept -> bool {
+-        return m_data != nullptr;
+-    }
+-    auto StringRef::isSubstring() const noexcept -> bool {
+-        return m_start[m_size] != '\0';
++    auto StringRef::data() const noexcept -> char const* {
++        return m_start;
+     }
+ 
+-    void StringRef::takeOwnership() {
+-        if( !isOwned() ) {
+-            m_data = new char[m_size+1];
+-            memcpy( m_data, m_start, m_size );
+-            m_data[m_size] = '\0';
+-        }
+-    }
+     auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
+-        if( start < m_size )
+-            return StringRef( m_start+start, size );
+-        else
++        if (start < m_size) {
++            return StringRef(m_start + start, (std::min)(m_size - start, size));
++        } else {
+             return StringRef();
+-    }
+-    auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
+-        return
+-            size() == other.size() &&
+-            (std::strncmp( m_start, other.m_start, size() ) == 0);
+-    }
+-    auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool {
+-        return !operator==( other );
+-    }
+-
+-    auto StringRef::operator[](size_type index) const noexcept -> char {
+-        return m_start[index];
+-    }
+-
+-    auto StringRef::numberOfCharacters() const noexcept -> size_type {
+-        size_type noChars = m_size;
+-        // Make adjustments for uft encodings
+-        for( size_type i=0; i < m_size; ++i ) {
+-            char c = m_start[i];
+-            if( ( c & byte_2_lead ) == byte_2_lead ) {
+-                noChars--;
+-                if (( c & byte_3_lead ) == byte_3_lead )
+-                    noChars--;
+-                if( ( c & byte_4_lead ) == byte_4_lead )
+-                    noChars--;
+-            }
+         }
+-        return noChars;
+     }
+-
+-    auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string {
+-        std::string str;
+-        str.reserve( lhs.size() + rhs.size() );
+-        str += lhs;
+-        str += rhs;
+-        return str;
+-    }
+-    auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string {
+-        return std::string( lhs ) + std::string( rhs );
+-    }
+-    auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string {
+-        return std::string( lhs ) + std::string( rhs );
++    auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
++        return m_size == other.m_size
++            && (std::memcmp( m_start, other.m_start, m_size ) == 0);
+     }
+ 
+     auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
+-        return os.write(str.currentData(), str.size());
++        return os.write(str.data(), str.size());
+     }
+ 
+     auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
+-        lhs.append(rhs.currentData(), rhs.size());
++        lhs.append(rhs.data(), rhs.size());
+         return lhs;
+     }
+ 
+ } // namespace Catch
+-
+-#if defined(__clang__)
+-#    pragma clang diagnostic pop
+-#endif
+ // end catch_stringref.cpp
+ // start catch_tag_alias.cpp
+ 
+@@ -13381,8 +14053,7 @@ namespace Catch {
+         std::vector<std::string> tags;
+         std::string desc, tag;
+         bool inTag = false;
+-        std::string _descOrTags = nameAndTags.tags;
+-        for (char c : _descOrTags) {
++        for (char c : nameAndTags.tags) {
+             if( !inTag ) {
+                 if( c == '[' )
+                     inTag = true;
+@@ -13412,10 +14083,11 @@ namespace Catch {
+             }
+         }
+         if( isHidden ) {
+-            tags.push_back( "." );
++            // Add all "hidden" tags to make them behave identically
++            tags.insert( tags.end(), { ".", "!hide" } );
+         }
+ 
+-        TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
++        TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );
+         return TestCase( _testCase, std::move(info) );
+     }
+ 
+@@ -13507,30 +14179,89 @@ namespace Catch {
+ // 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 ) {
++        return !testCase.throws() || config.allowThrows();
++    }
++
+     bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
+-        return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
++        return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
+     }
+ 
+     void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
+@@ -13591,7 +14322,7 @@ namespace Catch {
+     }
+ 
+     std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
+-        std::string className = classOrQualifiedMethodName;
++        std::string className(classOrQualifiedMethodName);
+         if( startsWith( className, '&' ) )
+         {
+             std::size_t lastColons = className.rfind( "::" );
+@@ -13659,15 +14390,12 @@ namespace TestCaseTracking {
+         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;
+     }
+@@ -13733,7 +14461,7 @@ namespace TestCaseTracking {
+                 m_runState = CompletedSuccessfully;
+                 break;
+             case ExecutingChildren:
+-                if( m_children.empty() || m_children.back()->isComplete() )
++                if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
+                     m_runState = CompletedSuccessfully;
+                 break;
+ 
+@@ -13768,7 +14496,8 @@ namespace TestCaseTracking {
+     }
+ 
+     SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+-    :   TrackerBase( nameAndLocation, ctx, parent )
++    :   TrackerBase( nameAndLocation, ctx, parent ),
++        m_trimmed_name(trim(nameAndLocation.name))
+     {
+         if( parent ) {
+             while( !parent->isSectionTracker() )
+@@ -13782,12 +14511,12 @@ namespace TestCaseTracking {
+     bool SectionTracker::isComplete() const {
+         bool complete = true;
+ 
+-        if ((m_filters.empty() || m_filters[0] == "") ||
+-             std::find(m_filters.begin(), m_filters.end(),
+-                       m_nameAndLocation.name) != m_filters.end())
++        if (m_filters.empty()
++            || m_filters[0] == ""
++            || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
+             complete = TrackerBase::isComplete();
++        }
+         return complete;
+-
+     }
+ 
+     bool SectionTracker::isSectionTracker() const { return true; }
+@@ -13811,20 +14540,29 @@ namespace TestCaseTracking {
+     }
+ 
+     void SectionTracker::tryOpen() {
+-        if( !isComplete() && (m_filters.empty() || m_filters[0].empty() ||  m_filters[0] == m_nameAndLocation.name ) )
++        if( !isComplete() )
+             open();
+     }
+ 
+     void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
+         if( !filters.empty() ) {
+-            m_filters.push_back(""); // Root - should never be consulted
+-            m_filters.push_back(""); // Test Case - not a section filter
++            m_filters.reserve( m_filters.size() + filters.size() + 2 );
++            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() );
+         }
+     }
+     void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {
+         if( filters.size() > 1 )
+-            m_filters.insert( m_filters.end(), ++filters.begin(), 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
+@@ -13876,47 +14614,81 @@ namespace Catch {
+ 
+ namespace Catch {
+ 
++    TestSpec::Pattern::Pattern( std::string const& name )
++    : m_name( name )
++    {}
++
+     TestSpec::Pattern::~Pattern() = default;
+-    TestSpec::NamePattern::~NamePattern() = default;
+-    TestSpec::TagPattern::~TagPattern() = default;
+-    TestSpec::ExcludedPattern::~ExcludedPattern() = default;
+ 
+-    TestSpec::NamePattern::NamePattern( std::string const& name )
+-    : m_wildcardPattern( toLower( name ), CaseSensitive::No )
++    std::string const& TestSpec::Pattern::name() const {
++        return m_name;
++    }
++
++    TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
++    : Pattern( filterString )
++    , m_wildcardPattern( toLower( name ), CaseSensitive::No )
+     {}
++
+     bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
+-        return m_wildcardPattern.matches( toLower( testCase.name ) );
++        return m_wildcardPattern.matches( testCase.name );
+     }
+ 
+-    TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
++    TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
++    : Pattern( filterString )
++    , m_tag( toLower( tag ) )
++    {}
++
+     bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
+         return std::find(begin(testCase.lcaseTags),
+                          end(testCase.lcaseTags),
+                          m_tag) != end(testCase.lcaseTags);
+     }
+ 
+-    TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
+-    bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
++    TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )
++    : Pattern( underlyingPattern->name() )
++    , m_underlyingPattern( underlyingPattern )
++    {}
++
++    bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {
++        return !m_underlyingPattern->matches( testCase );
++    }
+ 
+     bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
+-        // All patterns in a filter must match for the filter to be a match
+-        for( auto const& pattern : m_patterns ) {
+-            if( !pattern->matches( testCase ) )
+-                return false;
+-        }
+-        return true;
++        return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );
++    }
++
++    std::string TestSpec::Filter::name() const {
++        std::string name;
++        for( auto const& p : m_patterns )
++            name += p->name();
++        return name;
+     }
+ 
+     bool TestSpec::hasFilters() const {
+         return !m_filters.empty();
+     }
++
+     bool TestSpec::matches( TestCaseInfo const& testCase ) const {
+-        // A TestSpec matches if any filter matches
+-        for( auto const& filter : m_filters )
+-            if( filter.matches( testCase ) )
+-                return true;
+-        return false;
++        return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
++    }
++
++    TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const
++    {
++        Matches matches( m_filters.size() );
++        std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){
++            std::vector<TestCase const*> currentMatches;
++            for( auto const& test : testCases )
++                if( isThrowSafe( test, config ) && filter.matches( test ) )
++                    currentMatches.emplace_back( &test );
++            return FilterMatch{ filter.name(), currentMatches };
++        } );
++        return matches;
+     }
++
++    const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{
++        return  (m_invalidArgs);
++    }
++
+ }
+ // end catch_test_spec.cpp
+ // start catch_test_spec_parser.cpp
+@@ -13928,64 +14700,136 @@ namespace Catch {
+     TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
+         m_mode = None;
+         m_exclusion = false;
+-        m_start = std::string::npos;
+         m_arg = m_tagAliases->expandAliases( arg );
+         m_escapeChars.clear();
++        m_substring.reserve(m_arg.size());
++        m_patternName.reserve(m_arg.size());
++        m_realPatternPos = 0;
++
+         for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+-            visitChar( m_arg[m_pos] );
+-        if( m_mode == Name )
+-            addPattern<TestSpec::NamePattern>();
++          //if visitChar fails
++           if( !visitChar( m_arg[m_pos] ) ){
++               m_testSpec.m_invalidArgs.push_back(arg);
++               break;
++           }
++        endMode();
+         return *this;
+     }
+     TestSpec TestSpecParser::testSpec() {
+         addFilter();
+         return m_testSpec;
+     }
++    bool TestSpecParser::visitChar( char c ) {
++        if( (m_mode != EscapedName) && (c == '\\') ) {
++            escape();
++            addCharToPattern(c);
++            return true;
++        }else if((m_mode != EscapedName) && (c == ',') )  {
++            return separate();
++        }
+ 
+-    void TestSpecParser::visitChar( char c ) {
+-        if( m_mode == None ) {
+-            switch( c ) {
+-            case ' ': return;
+-            case '~': m_exclusion = true; return;
+-            case '[': return startNewMode( Tag, ++m_pos );
+-            case '"': return startNewMode( QuotedName, ++m_pos );
+-            case '\\': return escape();
+-            default: startNewMode( Name, m_pos ); break;
+-            }
+-        }
+-        if( m_mode == Name ) {
+-            if( c == ',' ) {
+-                addPattern<TestSpec::NamePattern>();
+-                addFilter();
+-            }
+-            else if( c == '[' ) {
+-                if( subString() == "exclude:" )
+-                    m_exclusion = true;
+-                else
+-                    addPattern<TestSpec::NamePattern>();
+-                startNewMode( Tag, ++m_pos );
+-            }
+-            else if( c == '\\' )
+-                escape();
++        switch( m_mode ) {
++        case None:
++            if( processNoneChar( c ) )
++                return true;
++            break;
++        case Name:
++            processNameChar( c );
++            break;
++        case EscapedName:
++            endMode();
++            addCharToPattern(c);
++            return true;
++        default:
++        case Tag:
++        case QuotedName:
++            if( processOtherChar( c ) )
++                return true;
++            break;
+         }
+-        else if( m_mode == EscapedName )
+-            m_mode = Name;
+-        else if( m_mode == QuotedName && c == '"' )
+-            addPattern<TestSpec::NamePattern>();
+-        else if( m_mode == Tag && c == ']' )
+-            addPattern<TestSpec::TagPattern>();
++
++        m_substring += c;
++        if( !isControlChar( c ) ) {
++            m_patternName += c;
++            m_realPatternPos++;
++        }
++        return true;
+     }
+-    void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
++    // Two of the processing methods return true to signal the caller to return
++    // without adding the given character to the current pattern strings
++    bool TestSpecParser::processNoneChar( char c ) {
++        switch( c ) {
++        case ' ':
++            return true;
++        case '~':
++            m_exclusion = true;
++            return false;
++        case '[':
++            startNewMode( Tag );
++            return false;
++        case '"':
++            startNewMode( QuotedName );
++            return false;
++        default:
++            startNewMode( Name );
++            return false;
++        }
++    }
++    void TestSpecParser::processNameChar( char c ) {
++        if( c == '[' ) {
++            if( m_substring == "exclude:" )
++                m_exclusion = true;
++            else
++                endMode();
++            startNewMode( Tag );
++        }
++    }
++    bool TestSpecParser::processOtherChar( char c ) {
++        if( !isControlChar( c ) )
++            return false;
++        m_substring += c;
++        endMode();
++        return true;
++    }
++    void TestSpecParser::startNewMode( Mode mode ) {
+         m_mode = mode;
+-        m_start = start;
++    }
++    void TestSpecParser::endMode() {
++        switch( m_mode ) {
++        case Name:
++        case QuotedName:
++            return addNamePattern();
++        case Tag:
++            return addTagPattern();
++        case EscapedName:
++            revertBackToLastMode();
++            return;
++        case None:
++        default:
++            return startNewMode( None );
++        }
+     }
+     void TestSpecParser::escape() {
+-        if( m_mode == None )
+-            m_start = m_pos;
++        saveLastMode();
+         m_mode = EscapedName;
+-        m_escapeChars.push_back( m_pos );
++        m_escapeChars.push_back(m_realPatternPos);
++    }
++    bool TestSpecParser::isControlChar( char c ) const {
++        switch( m_mode ) {
++            default:
++                return false;
++            case None:
++                return c == '~';
++            case Name:
++                return c == '[';
++            case EscapedName:
++                return true;
++            case QuotedName:
++                return c == '"';
++            case Tag:
++                return c == '[' || c == ']';
++        }
+     }
+-    std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
+ 
+     void TestSpecParser::addFilter() {
+         if( !m_currentFilter.m_patterns.empty() ) {
+@@ -13994,6 +14838,86 @@ namespace Catch {
+         }
+     }
+ 
++    void TestSpecParser::saveLastMode() {
++      lastMode = m_mode;
++    }
++
++    void TestSpecParser::revertBackToLastMode() {
++      m_mode = lastMode;
++    }
++
++    bool TestSpecParser::separate() {
++      if( (m_mode==QuotedName) || (m_mode==Tag) ){
++         //invalid argument, signal failure to previous scope.
++         m_mode = None;
++         m_pos = m_arg.size();
++         m_substring.clear();
++         m_patternName.clear();
++         m_realPatternPos = 0;
++         return false;
++      }
++      endMode();
++      addFilter();
++      return true; //success
++    }
++
++    std::string TestSpecParser::preprocessPattern() {
++        std::string token = m_patternName;
++        for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
++            token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
++        m_escapeChars.clear();
++        if (startsWith(token, "exclude:")) {
++            m_exclusion = true;
++            token = token.substr(8);
++        }
++
++        m_patternName.clear();
++        m_realPatternPos = 0;
++
++        return token;
++    }
++
++    void TestSpecParser::addNamePattern() {
++        auto token = preprocessPattern();
++
++        if (!token.empty()) {
++            TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);
++            if (m_exclusion)
++                pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
++            m_currentFilter.m_patterns.push_back(pattern);
++        }
++        m_substring.clear();
++        m_exclusion = false;
++        m_mode = None;
++    }
++
++    void TestSpecParser::addTagPattern() {
++        auto token = preprocessPattern();
++
++        if (!token.empty()) {
++            // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
++            // we have to create a separate hide tag and shorten the real one
++            if (token.size() > 1 && token[0] == '.') {
++                token.erase(token.begin());
++                TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring);
++                if (m_exclusion) {
++                    pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
++                }
++                m_currentFilter.m_patterns.push_back(pattern);
++            }
++
++            TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);
++
++            if (m_exclusion) {
++                pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
++            }
++            m_currentFilter.m_patterns.push_back(pattern);
++        }
++        m_substring.clear();
++        m_exclusion = false;
++        m_mode = None;
++    }
++
+     TestSpec parseTestSpec( std::string const& arg ) {
+         return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+     }
+@@ -14095,13 +15019,11 @@ namespace Detail {
+             enum Arch { Big, Little };
+ 
+             static Arch which() {
+-                union _{
+-                    int asInt;
+-                    char asChar[sizeof (int)];
+-                } u;
+-
+-                u.asInt = 1;
+-                return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
++                int one = 1;
++                // If the lowest byte we read is non-zero, we can assume
++                // that little endian format is used.
++                auto value = *reinterpret_cast<char*>(&one);
++                return value ? Little : Big;
+             }
+         };
+     }
+@@ -14225,6 +15147,13 @@ std::string StringMaker<wchar_t *>::conv
+ }
+ #endif
+ 
++#if defined(CATCH_CONFIG_CPP17_BYTE)
++#include <cstddef>
++std::string StringMaker<std::byte>::convert(std::byte value) {
++    return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
++}
++#endif // defined(CATCH_CONFIG_CPP17_BYTE)
++
+ std::string StringMaker<int>::convert(int value) {
+     return ::Catch::Detail::stringify(static_cast<long long>(value));
+ }
+@@ -14370,11 +15299,48 @@ 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 {
+     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();
+@@ -14414,7 +15380,7 @@ namespace Catch {
+     }
+ 
+     Version const& libraryVersion() {
+-        static Version version( 2, 9, 1, "", 0 );
++        static Version version( 2, 13, 7, "", 0 );
+         return version;
+     }
+ 
+@@ -14422,14 +15388,12 @@ namespace Catch {
+ // end catch_version.cpp
+ // start catch_wildcard_pattern.cpp
+ 
+-#include <sstream>
+-
+ namespace Catch {
+ 
+     WildcardPattern::WildcardPattern( std::string const& pattern,
+                                       CaseSensitive::Choice caseSensitivity )
+     :   m_caseSensitivity( caseSensitivity ),
+-        m_pattern( adjustCase( pattern ) )
++        m_pattern( normaliseString( pattern ) )
+     {
+         if( startsWith( m_pattern, '*' ) ) {
+             m_pattern = m_pattern.substr( 1 );
+@@ -14444,28 +15408,27 @@ namespace Catch {
+     bool WildcardPattern::matches( std::string const& str ) const {
+         switch( m_wildcard ) {
+             case NoWildcard:
+-                return m_pattern == adjustCase( str );
++                return m_pattern == normaliseString( str );
+             case WildcardAtStart:
+-                return endsWith( adjustCase( str ), m_pattern );
++                return endsWith( normaliseString( str ), m_pattern );
+             case WildcardAtEnd:
+-                return startsWith( adjustCase( str ), m_pattern );
++                return startsWith( normaliseString( str ), m_pattern );
+             case WildcardAtBothEnds:
+-                return contains( adjustCase( str ), m_pattern );
++                return contains( normaliseString( str ), m_pattern );
+             default:
+                 CATCH_INTERNAL_ERROR( "Unknown enum" );
+         }
+     }
+ 
+-    std::string WildcardPattern::adjustCase( std::string const& str ) const {
+-        return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
++    std::string WildcardPattern::normaliseString( std::string const& str ) const {
++        return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
+     }
+ }
+ // end catch_wildcard_pattern.cpp
+ // start catch_xmlwriter.cpp
+ 
+ #include <iomanip>
+-
+-using uchar = unsigned char;
++#include <type_traits>
+ 
+ namespace Catch {
+ 
+@@ -14505,8 +15468,30 @@ namespace {
+         os.flags(f);
+     }
+ 
++    bool shouldNewline(XmlFormatting fmt) {
++        return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline));
++    }
++
++    bool shouldIndent(XmlFormatting fmt) {
++        return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent));
++    }
++
+ } // anonymous namespace
+ 
++    XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {
++        return static_cast<XmlFormatting>(
++            static_cast<std::underlying_type<XmlFormatting>::type>(lhs) |
++            static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
++        );
++    }
++
++    XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {
++        return static_cast<XmlFormatting>(
++            static_cast<std::underlying_type<XmlFormatting>::type>(lhs) &
++            static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
++        );
++    }
++
+     XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
+     :   m_str( str ),
+         m_forWhat( forWhat )
+@@ -14517,7 +15502,7 @@ namespace {
+         // (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;
+@@ -14577,7 +15562,7 @@ namespace {
+                 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);
+                 }
+@@ -14611,13 +15596,17 @@ namespace {
+         return os;
+     }
+ 
+-    XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
+-    :   m_writer( writer )
++    XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
++    :   m_writer( writer ),
++        m_fmt(fmt)
+     {}
+ 
+     XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
+-    :   m_writer( other.m_writer ){
++    :   m_writer( other.m_writer ),
++        m_fmt(other.m_fmt)
++    {
+         other.m_writer = nullptr;
++        other.m_fmt = XmlFormatting::None;
+     }
+     XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
+         if ( m_writer ) {
+@@ -14625,16 +15614,19 @@ namespace {
+         }
+         m_writer = other.m_writer;
+         other.m_writer = nullptr;
++        m_fmt = other.m_fmt;
++        other.m_fmt = XmlFormatting::None;
+         return *this;
+     }
+ 
+     XmlWriter::ScopedElement::~ScopedElement() {
+-        if( m_writer )
+-            m_writer->endElement();
++        if (m_writer) {
++            m_writer->endElement(m_fmt);
++        }
+     }
+ 
+-    XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
+-        m_writer->writeText( text, indent );
++    XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {
++        m_writer->writeText( text, fmt );
+         return *this;
+     }
+ 
+@@ -14644,37 +15636,47 @@ namespace {
+     }
+ 
+     XmlWriter::~XmlWriter() {
+-        while( !m_tags.empty() )
++        while (!m_tags.empty()) {
+             endElement();
++        }
++        newlineIfNecessary();
+     }
+ 
+-    XmlWriter& XmlWriter::startElement( std::string const& name ) {
++    XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
+         ensureTagClosed();
+         newlineIfNecessary();
+-        m_os << m_indent << '<' << name;
++        if (shouldIndent(fmt)) {
++            m_os << m_indent;
++            m_indent += "  ";
++        }
++        m_os << '<' << name;
+         m_tags.push_back( name );
+-        m_indent += "  ";
+         m_tagIsOpen = true;
++        applyFormatting(fmt);
+         return *this;
+     }
+ 
+-    XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
+-        ScopedElement scoped( this );
+-        startElement( name );
++    XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
++        ScopedElement scoped( this, fmt );
++        startElement( name, fmt );
+         return scoped;
+     }
+ 
+-    XmlWriter& XmlWriter::endElement() {
+-        newlineIfNecessary();
+-        m_indent = m_indent.substr( 0, m_indent.size()-2 );
++    XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
++        m_indent = m_indent.substr(0, m_indent.size() - 2);
++
+         if( m_tagIsOpen ) {
+             m_os << "/>";
+             m_tagIsOpen = false;
++        } else {
++            newlineIfNecessary();
++            if (shouldIndent(fmt)) {
++                m_os << m_indent;
++            }
++            m_os << "</" << m_tags.back() << ">";
+         }
+-        else {
+-            m_os << m_indent << "</" << m_tags.back() << ">";
+-        }
+-        m_os << std::endl;
++        m_os << std::flush;
++        applyFormatting(fmt);
+         m_tags.pop_back();
+         return *this;
+     }
+@@ -14690,22 +15692,26 @@ namespace {
+         return *this;
+     }
+ 
+-    XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
++    XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {
+         if( !text.empty() ){
+             bool tagWasOpen = m_tagIsOpen;
+             ensureTagClosed();
+-            if( tagWasOpen && indent )
++            if (tagWasOpen && shouldIndent(fmt)) {
+                 m_os << m_indent;
++            }
+             m_os << XmlEncode( text );
+-            m_needsNewline = true;
++            applyFormatting(fmt);
+         }
+         return *this;
+     }
+ 
+-    XmlWriter& XmlWriter::writeComment( std::string const& text ) {
++    XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {
+         ensureTagClosed();
+-        m_os << m_indent << "<!--" << text << "-->";
+-        m_needsNewline = true;
++        if (shouldIndent(fmt)) {
++            m_os << m_indent;
++        }
++        m_os << "<!--" << text << "-->";
++        applyFormatting(fmt);
+         return *this;
+     }
+ 
+@@ -14721,11 +15727,16 @@ namespace {
+ 
+     void XmlWriter::ensureTagClosed() {
+         if( m_tagIsOpen ) {
+-            m_os << ">" << std::endl;
++            m_os << '>' << std::flush;
++            newlineIfNecessary();
+             m_tagIsOpen = false;
+         }
+     }
+ 
++    void XmlWriter::applyFormatting(XmlFormatting fmt) {
++        m_needsNewline = shouldNewline(fmt);
++    }
++
+     void XmlWriter::writeDeclaration() {
+         m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+     }
+@@ -14771,6 +15782,17 @@ namespace Catch {
+         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;
+@@ -15001,24 +16023,25 @@ private:
+         if (itMessage == messages.end())
+             return;
+ 
+-        // using messages.end() directly yields (or auto) compilation error:
+-        std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+-        const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
++        const auto itEnd = messages.cend();
++        const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+ 
+         {
+             Colour colourGuard(colour);
+             stream << " with " << pluralise(N, "message") << ':';
+         }
+ 
+-        for (; itMessage != itEnd; ) {
++        while (itMessage != itEnd) {
+             // If this assertion is a warning ignore any INFO messages
+             if (printInfoMessages || itMessage->type != ResultWas::Info) {
+-                stream << " '" << itMessage->message << '\'';
+-                if (++itMessage != itEnd) {
++                printMessage();
++                if (itMessage != itEnd) {
+                     Colour colourGuard(dimColour());
+                     stream << " and";
+                 }
++                continue;
+             }
++            ++itMessage;
+         }
+     }
+ 
+@@ -15036,10 +16059,6 @@ private:
+             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;
+         }
+@@ -15066,8 +16085,9 @@ private:
+         }
+ 
+         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;
+             }
+         }
+ 
+@@ -15279,15 +16299,11 @@ class Duration {
+     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) {
+@@ -15316,7 +16332,7 @@ public:
+         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 {
+@@ -15337,7 +16353,7 @@ public:
+ 
+     }
+     friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
+-        return os << duration.value() << " " << duration.unitsAsString();
++        return os << duration.value() << ' ' << duration.unitsAsString();
+     }
+ };
+ } // end anon namespace
+@@ -15369,9 +16385,9 @@ public:
+ 				headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2));
+ 				headerCols += spacer;
+ 			}
+-			m_os << headerCols << "\n";
++			m_os << headerCols << '\n';
+ 
+-            m_os << Catch::getLineOfChars<'-'>() << "\n";
++            m_os << Catch::getLineOfChars<'-'>() << '\n';
+         }
+     }
+     void close() {
+@@ -15390,30 +16406,29 @@ public:
+ 
+     friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
+         auto colStr = tp.m_oss.str();
+-        // This takes account of utf8 encodings
+-        auto strSize = Catch::StringRef(colStr).numberOfCharacters();
++        const auto strSize = colStr.size();
+         tp.m_oss.str("");
+         tp.open();
+         if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
+             tp.m_currentColumn = -1;
+-            tp.m_os << "\n";
++            tp.m_os << '\n';
+         }
+         tp.m_currentColumn++;
+ 
+         auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
+-        auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width))
+-            ? std::string(colInfo.width - (strSize + 2), ' ')
++        auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width))
++            ? std::string(colInfo.width - (strSize + 1), ' ')
+             : std::string();
+         if (colInfo.justification == ColumnInfo::Left)
+-            tp.m_os << colStr << padding << " ";
++            tp.m_os << colStr << padding << ' ';
+         else
+-            tp.m_os << padding << colStr << " ";
++            tp.m_os << padding << colStr << ' ';
+         return tp;
+     }
+ 
+     friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
+         if (tp.m_currentColumn > 0) {
+-            tp.m_os << "\n";
++            tp.m_os << '\n';
+             tp.m_currentColumn = -1;
+         }
+         return tp;
+@@ -15423,12 +16438,26 @@ public:
+ ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
+     : StreamingReporterBase(config),
+     m_tablePrinter(new TablePrinter(config.stream(),
+-    {
+-        { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, 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 }
+-    })) {}
++        [&config]() -> std::vector<ColumnInfo> {
++        if (config.fullConfig()->benchmarkNoAnalysis())
++        {
++            return{
++                { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
++                { "     samples", 14, ColumnInfo::Right },
++                { "  iterations", 14, ColumnInfo::Right },
++                { "        mean", 14, ColumnInfo::Right }
++            };
++        }
++        else
++        {
++            return{
++                { "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 }
++            };
++        }
++    }())) {}
+ ConsoleReporter::~ConsoleReporter() = default;
+ 
+ std::string ConsoleReporter::getDescription() {
+@@ -15439,6 +16468,10 @@ void ConsoleReporter::noMatchingTestCase
+     stream << "No test cases matched '" << spec << '\'' << std::endl;
+ }
+ 
++void ConsoleReporter::reportInvalidArguments(std::string const&arg){
++    stream << "Invalid Filter: " << arg << std::endl;
++}
++
+ void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
+ 
+ bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
+@@ -15474,8 +16507,9 @@ void ConsoleReporter::sectionEnded(Secti
+             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;
+@@ -15501,24 +16535,32 @@ void ConsoleReporter::benchmarkPreparing
+ }
+ 
+ void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
+-	(*m_tablePrinter) << info.samples << ColumnBreak()
+-		<< info.iterations << ColumnBreak()
+-		<< Duration(info.estimatedDuration) << ColumnBreak();
++    (*m_tablePrinter) << info.samples << ColumnBreak()
++        << info.iterations << ColumnBreak();
++    if (!m_config->benchmarkNoAnalysis())
++        (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();
+ }
+ void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
+-	(*m_tablePrinter) << ColumnBreak()
+-		<< Duration(stats.mean.point.count()) << ColumnBreak()
+-		<< Duration(stats.mean.lower_bound.count()) << ColumnBreak()
+-		<< Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
+-		<< Duration(stats.standardDeviation.point.count()) << ColumnBreak()
+-		<< Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
+-		<< Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
++    if (m_config->benchmarkNoAnalysis())
++    {
++        (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
++    }
++    else
++    {
++        (*m_tablePrinter) << ColumnBreak()
++            << Duration(stats.mean.point.count()) << ColumnBreak()
++            << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
++            << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
++            << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
++            << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
++            << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
++    }
+ }
+ 
+ void ConsoleReporter::benchmarkFailed(std::string const& error) {
+ 	Colour colour(Colour::Red);
+     (*m_tablePrinter)
+-        << "Benchmark failed (" << error << ")"
++        << "Benchmark failed (" << error << ')'
+         << ColumnBreak() << RowBreak();
+ }
+ #endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+@@ -15600,11 +16642,9 @@ void ConsoleReporter::printTestCaseAndSe
+ 
+     SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
+ 
+-    if (!lineInfo.empty()) {
+-        stream << getLineOfChars<'-'>() << '\n';
+-        Colour colourGuard(Colour::FileName);
+-        stream << lineInfo << '\n';
+-    }
++    stream << getLineOfChars<'-'>() << '\n';
++    Colour colourGuard(Colour::FileName);
++    stream << lineInfo << '\n';
+     stream << getLineOfChars<'.'>() << '\n' << std::endl;
+ }
+ 
+@@ -15729,8 +16769,10 @@ void ConsoleReporter::printSummaryDivide
+ }
+ 
+ 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)
+@@ -15751,6 +16793,7 @@ CATCH_REGISTER_REPORTER("console", Conso
+ #include <sstream>
+ #include <ctime>
+ #include <algorithm>
++#include <iomanip>
+ 
+ namespace Catch {
+ 
+@@ -15778,7 +16821,7 @@ namespace Catch {
+ #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) {
+@@ -15789,6 +16832,17 @@ namespace Catch {
+                 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 )
+@@ -15858,7 +16912,7 @@ namespace Catch {
+         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
+@@ -15880,8 +16934,8 @@ namespace Catch {
+         for( auto const& child : groupNode.children )
+             writeTestCase( *child );
+ 
+-        xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false );
+-        xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false );
++        xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
++        xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
+     }
+ 
+     void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
+@@ -15903,12 +16957,13 @@ namespace Catch {
+         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;
+@@ -15925,20 +16980,30 @@ namespace Catch {
+                 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 );
+ 
+             if( !sectionNode.stdOut.empty() )
+-                xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
++                xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
+             if( !sectionNode.stdErr.empty() )
+-                xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
++                xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
+         }
+         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 ) {
+@@ -15956,11 +17021,7 @@ namespace Catch {
+                     elementName = "error";
+                     break;
+                 case ResultWas::ExplicitFailure:
+-                    elementName = "failure";
+-                    break;
+                 case ResultWas::ExpressionFailed:
+-                    elementName = "failure";
+-                    break;
+                 case ResultWas::DidntThrowException:
+                     elementName = "failure";
+                     break;
+@@ -15978,10 +17039,25 @@ namespace Catch {
+ 
+             XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+ 
+-            xml.writeAttribute( "message", result.getExpandedExpression() );
++            xml.writeAttribute( "message", result.getExpression() );
+             xml.writeAttribute( "type", result.getTestMacroName() );
+ 
+             ReusableStringStream rss;
++            if (stats.totals.assertions.total() > 0) {
++                rss << "FAILED" << ":\n";
++                if (result.hasExpression()) {
++                    rss << "  ";
++                    rss << result.getExpressionInMacro();
++                    rss << '\n';
++                }
++                if (result.hasExpandedExpression()) {
++                    rss << "with expansion:\n";
++                    rss << Column(result.getExpandedExpression()).indent(2) << '\n';
++                }
++            } else {
++                rss << '\n';
++            }
++
+             if( !result.getMessage().empty() )
+                 rss << result.getMessage() << '\n';
+             for( auto const& msg : stats.infoMessages )
+@@ -15989,7 +17065,7 @@ namespace Catch {
+                     rss << msg.message << '\n';
+ 
+             rss << "at " << result.getSourceInfo();
+-            xml.writeText( rss.str(), false );
++            xml.writeText( rss.str(), XmlFormatting::Newline );
+         }
+     }
+ 
+@@ -16033,6 +17109,13 @@ namespace Catch {
+         m_reporter->noMatchingTestCases( spec );
+     }
+ 
++    void ListeningReporter::reportInvalidArguments(std::string const&arg){
++        for ( auto const& listener : m_listeners ) {
++            listener->reportInvalidArguments( arg );
++        }
++        m_reporter->reportInvalidArguments( arg );
++    }
++
+ #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+     void ListeningReporter::benchmarkPreparing( std::string const& name ) {
+ 		for (auto const& listener : m_listeners) {
+@@ -16328,9 +17411,9 @@ namespace Catch {
+             e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+ 
+         if( !testCaseStats.stdOut.empty() )
+-            m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
++            m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
+         if( !testCaseStats.stdErr.empty() )
+-            m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
++            m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
+ 
+         m_xml.endElement();
+     }
+@@ -16342,6 +17425,10 @@ namespace Catch {
+             .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();
+     }
+ 
+@@ -16351,26 +17438,33 @@ namespace Catch {
+             .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();
+     }
+ 
+ #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+-    void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
++    void XmlReporter::benchmarkPreparing(std::string const& name) {
+         m_xml.startElement("BenchmarkResults")
+-            .writeAttribute("name", info.name)
+-            .writeAttribute("samples", info.samples)
++            .writeAttribute("name", name);
++    }
++
++    void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
++        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")
+@@ -16421,7 +17515,7 @@ namespace Catch {
+ 
+ #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
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..29aa4b2
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,14 @@
+#!/usr/bin/make -f
+
+%:
+	dh $@ --buildsystem=cmake
+
+override_dh_auto_configure:
+	dh_auto_configure --buildsystem=cmake -- \
+	  -Dzug_BUILD_EXAMPLES=OFF \
+	  -Dzug_BUILD_DOCS=OFF
+
+ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
+execute_after_dh_auto_build:
+	dh_auto_build -- tests
+endif
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
new file mode 100644
index 0000000..31e31c9
--- /dev/null
+++ b/debian/salsa-ci.yml
@@ -0,0 +1,6 @@
+include:
+  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
+  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
+variables:
+  SALSA_CI_DISABLE_MISSING_BREAKS: 'no'
+  SALSA_CI_DISABLE_RC_BUGS: 'no'
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
new file mode 100644
index 0000000..464c681
--- /dev/null
+++ b/debian/upstream/metadata
@@ -0,0 +1,5 @@
+---
+Bug-Database: https://github.com/arximboldi/zug/issues
+Bug-Submit: https://github.com/arximboldi/zug/issues/new
+Repository: https://github.com/arximboldi/zug.git
+Repository-Browse: https://github.com/arximboldi/zug
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..6354648
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,5 @@
+version=4
+
+opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%@PACKAGE at -$1.tar.gz%" \
+https://github.com/arximboldi/zug/tags \
+(?:.*?/)?v?(\d[\d.]*)\.tar\.gz


More information about the Neon-commits mailing list