diff options
author | ciappi | 2022-06-19 13:47:28 +0200 |
---|---|---|
committer | ciappi | 2022-06-19 13:47:28 +0200 |
commit | 05780d04bb85244e2749422945c061ffdfc7b3ac (patch) | |
tree | 3935ee8d952376d835ba92d240547e8865185ae1 | |
parent | 73b0490d2f5dbf2d34a8678bf6d9c09b5f2d064a (diff) | |
download | aur-05780d04bb85244e2749422945c061ffdfc7b3ac.tar.gz |
v0.15.0-1
-rw-r--r-- | .SRCINFO | 12 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | PKGBUILD | 11 | ||||
-rw-r--r-- | doctest.patch | 4833 |
4 files changed, 10 insertions, 4847 deletions
@@ -1,17 +1,15 @@ pkgbase = lfortran pkgdesc = Modern interactive LLVM-based Fortran compiler - pkgver = 0.14.0 - pkgrel = 2 + pkgver = 0.15.0 + pkgrel = 1 url = https://lfortran.org arch = x86_64 license = BSD - makedepends = llvm11 + makedepends = llvm makedepends = cmake depends = zlib depends = ncurses - source = https://lfortran.github.io/tarballs/release/lfortran-0.14.0.tar.gz - source = doctest.patch - sha256sums = fc3c1d592c56ae2636065ec0228db747f154f65a0867f6311bc8091efd5c13a7 - sha256sums = c0a8eabdefe530e65a22ac5b19948c7cbf77d8c46a7afeef8792e9e38006c5d5 + source = https://lfortran.github.io/tarballs/release/lfortran-0.15.0.tar.gz + sha256sums = 8712c1b0c886f08937ff4c277ff3fa5c05e4dead1bafe55e3bd789be96470127 pkgname = lfortran diff --git a/.gitignore b/.gitignore index 498667d7dff1..018a3de08144 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ !PKGBUILD !.SRCINFO !.gitignore -!doctest.patch @@ -1,7 +1,7 @@ # Maintainer: Ciappi <marco.scopesi@gmail.com> pkgname=lfortran -pkgver=0.14.0 -pkgrel=2 +pkgver=0.15.0 +pkgrel=1 pkgdesc="Modern interactive LLVM-based Fortran compiler" arch=('x86_64') url="https://lfortran.org" @@ -18,14 +18,12 @@ backup=() options=() install= changelog= -source=("https://lfortran.github.io/tarballs/release/"$pkgname-$pkgver.tar.gz "doctest.patch") -sha256sums=('fc3c1d592c56ae2636065ec0228db747f154f65a0867f6311bc8091efd5c13a7' - 'c0a8eabdefe530e65a22ac5b19948c7cbf77d8c46a7afeef8792e9e38006c5d5') +source=("https://lfortran.github.io/tarballs/release/"$pkgname-$pkgver.tar.gz) +sha256sums=('8712c1b0c886f08937ff4c277ff3fa5c05e4dead1bafe55e3bd789be96470127') noextract=() prepare() { cd "$pkgname-$pkgver" - patch --forward --strip=1 --input="${srcdir}/doctest.patch" } build() { @@ -49,3 +47,4 @@ package() { # vim:set ts=2 sw=2 et: + diff --git a/doctest.patch b/doctest.patch deleted file mode 100644 index 4b812d76e8eb..000000000000 --- a/doctest.patch +++ /dev/null @@ -1,4833 +0,0 @@ -diff --unified --recursive --text package.orig/src/tests/doctest.h package.new/src/tests/doctest.h ---- package.orig/src/tests/doctest.h 2021-09-23 08:22:52.000000000 +0200 -+++ package.new/src/tests/doctest.h 2022-01-10 18:39:35.000000000 +0100 -@@ -4,14 +4,14 @@ - // - // doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD - // --// Copyright (c) 2016-2019 Viktor Kirilov -+// Copyright (c) 2016-2021 Viktor Kirilov - // - // Distributed under the MIT Software License - // See accompanying file LICENSE.txt or copy at - // https://opensource.org/licenses/MIT - // - // The documentation can be found at the library's page: --// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md -+// https://github.com/doctest/doctest/blob/master/doc/markdown/readme.md - // - // ================================================================================================= - // ================================================================================================= -@@ -47,9 +47,17 @@ - // ================================================================================================= - - #define DOCTEST_VERSION_MAJOR 2 --#define DOCTEST_VERSION_MINOR 3 --#define DOCTEST_VERSION_PATCH 4 --#define DOCTEST_VERSION_STR "2.3.4" -+#define DOCTEST_VERSION_MINOR 4 -+#define DOCTEST_VERSION_PATCH 8 -+ -+// util we need here -+#define DOCTEST_TOSTR_IMPL(x) #x -+#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) -+ -+#define DOCTEST_VERSION_STR \ -+ DOCTEST_TOSTR(DOCTEST_VERSION_MAJOR) "." \ -+ DOCTEST_TOSTR(DOCTEST_VERSION_MINOR) "." \ -+ DOCTEST_TOSTR(DOCTEST_VERSION_PATCH) - - #define DOCTEST_VERSION \ - (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) -@@ -137,84 +145,93 @@ - // == COMPILER WARNINGS ============================================================================ - // ================================================================================================= - -+// both the header and the implementation suppress all of these, -+// so it only makes sense to aggregrate them like so -+#define DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH \ -+ DOCTEST_CLANG_SUPPRESS_WARNING_PUSH \ -+ DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") \ -+ DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") \ -+ DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") \ -+ DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") \ -+ DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") \ -+ DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") \ -+ DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") \ -+ \ -+ DOCTEST_GCC_SUPPRESS_WARNING_PUSH \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") \ -+ DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") \ -+ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ -+ /* these 4 also disabled globally via cmake: */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4514) /* unreferenced inline function has been removed */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4571) /* SEH related */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4710) /* function not inlined */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4711) /* function selected for inline expansion*/ \ -+ /* */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4616) /* invalid compiler warning */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4619) /* invalid compiler warning */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4996) /* The compiler encountered a deprecated declaration */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4706) /* assignment within conditional expression */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4512) /* 'class' : assignment operator could not be generated */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4127) /* conditional expression is constant */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4640) /* construction of local static object not thread-safe */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ -+ /* static analysis */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(26439) /* Function may not throw. Declare it 'noexcept' */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(26495) /* Always initialize a member variable */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(26451) /* Arithmetic overflow ... */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(26444) /* Avoid unnamed objects with custom ctor and dtor... */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(26812) /* Prefer 'enum class' over 'enum' */ -+ -+#define DOCTEST_SUPPRESS_COMMON_WARNINGS_POP \ -+ DOCTEST_CLANG_SUPPRESS_WARNING_POP \ -+ DOCTEST_GCC_SUPPRESS_WARNING_POP \ -+ DOCTEST_MSVC_SUPPRESS_WARNING_POP -+ -+DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH -+ - DOCTEST_CLANG_SUPPRESS_WARNING_PUSH --DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") - - DOCTEST_GCC_SUPPRESS_WARNING_PUSH --DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") --DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") --DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") --DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") --DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") - DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") --DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") - DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") --DOCTEST_GCC_SUPPRESS_WARNING("-Winline") --DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") --DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") --DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") - DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") - - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH --DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning --DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning --DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration --DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression --DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated --DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant --DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding --DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted --DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted --DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted --DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted - DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted --DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe --// static analysis --DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept' --DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable --DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ... --DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtr... -- --// 4548 - expression before comma has no effect; expected expression with side - effect --// 4265 - class has virtual functions, but destructor is not virtual --// 4986 - exception specification does not match previous declaration --// 4350 - behavior change: 'member1' called instead of 'member2' --// 4668 - 'x' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' --// 4365 - conversion from 'int' to 'unsigned long', signed/unsigned mismatch --// 4774 - format string expected in argument 'x' is not a string literal --// 4820 - padding in structs -- --// only 4 should be disabled globally: --// - 4514 # unreferenced inline function has been removed --// - 4571 # SEH related --// - 4710 # function not inlined --// - 4711 # function 'x' selected for automatic inline expansion - - #define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4548) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4265) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4986) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4350) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4668) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4365) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4774) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4820) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4625) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4626) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(5027) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(5026) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(4623) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(5039) \ -- DOCTEST_MSVC_SUPPRESS_WARNING(5045) -+ DOCTEST_MSVC_SUPPRESS_WARNING(4548) /* before comma no effect; expected side - effect */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4265) /* virtual functions, but destructor is not virtual */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4986) /* exception specification does not match previous */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4350) /* 'member1' called instead of 'member2' */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4668) /* not defined as a preprocessor macro */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4365) /* signed/unsigned mismatch */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4774) /* format string not a string literal */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(4623) /* default constructor was implicitly deleted */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(5039) /* pointer to pot. throwing function passed to extern C */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ -+ DOCTEST_MSVC_SUPPRESS_WARNING(5105) /* macro producing 'defined' has undefined behavior */ - - #define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP - -@@ -227,6 +244,7 @@ - // GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html - // MSVC version table: - // https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering -+// MSVC++ 14.3 (17) _MSC_VER == 1930 (Visual Studio 2022) - // MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) - // MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017) - // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) -@@ -236,6 +254,10 @@ - // MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) - // MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) - -+// Universal Windows Platform support -+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -+#define DOCTEST_CONFIG_NO_WINDOWS_SEH -+#endif // WINAPI_FAMILY - #if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH) - #define DOCTEST_CONFIG_WINDOWS_SEH - #endif // MSVC -@@ -300,15 +322,39 @@ - #define DOCTEST_NOINLINE __declspec(noinline) - #define DOCTEST_UNUSED - #define DOCTEST_ALIGNMENT(x) --#else // MSVC -+#elif DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 5, 0) -+#define DOCTEST_NOINLINE -+#define DOCTEST_UNUSED -+#define DOCTEST_ALIGNMENT(x) -+#else - #define DOCTEST_NOINLINE __attribute__((noinline)) - #define DOCTEST_UNUSED __attribute__((unused)) - #define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) --#endif // MSVC -+#endif -+ -+#ifndef DOCTEST_NORETURN -+#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) -+#define DOCTEST_NORETURN -+#else // DOCTEST_MSVC -+#define DOCTEST_NORETURN [[noreturn]] -+#endif // DOCTEST_MSVC -+#endif // DOCTEST_NORETURN - --#ifndef DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK --#define DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK 5 --#endif // DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK -+#ifndef DOCTEST_NOEXCEPT -+#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) -+#define DOCTEST_NOEXCEPT -+#else // DOCTEST_MSVC -+#define DOCTEST_NOEXCEPT noexcept -+#endif // DOCTEST_MSVC -+#endif // DOCTEST_NOEXCEPT -+ -+#ifndef DOCTEST_CONSTEXPR -+#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) -+#define DOCTEST_CONSTEXPR const -+#else // DOCTEST_MSVC -+#define DOCTEST_CONSTEXPR constexpr -+#endif // DOCTEST_MSVC -+#endif // DOCTEST_CONSTEXPR - - // ================================================================================================= - // == FEATURE DETECTION END ======================================================================== -@@ -323,8 +369,6 @@ - #define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) - #endif // __COUNTER__ - --#define DOCTEST_TOSTR(x) #x -- - #ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE - #define DOCTEST_REF_WRAP(x) x& - #else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE -@@ -342,23 +386,31 @@ - #define DOCTEST_PLATFORM_LINUX - #endif // DOCTEST_PLATFORM - --// clang-format off --#define DOCTEST_DELETE_COPIES(type) type(const type&) = delete; type& operator=(const type&) = delete --#define DOCTEST_DECLARE_COPIES(type) type(const type&); type& operator=(const type&) --#define DOCTEST_DEFINE_COPIES(type) type::type(const type&) = default; type& type::operator=(const type&) = default --#define DOCTEST_DECLARE_DEFAULTS(type) type(); ~type() --#define DOCTEST_DEFINE_DEFAULTS(type) type::type() = default; type::~type() = default --// clang-format on -+namespace doctest { namespace detail { -+ static DOCTEST_CONSTEXPR int consume(const int*, int) { return 0; } -+}} - --#define DOCTEST_GLOBAL_NO_WARNINGS(var) \ -+#define DOCTEST_GLOBAL_NO_WARNINGS(var, ...) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ -- DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \ -- static int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp) --#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP -+ static const int var = doctest::detail::consume(&var, __VA_ARGS__); \ -+ DOCTEST_CLANG_SUPPRESS_WARNING_POP - -+#ifndef DOCTEST_BREAK_INTO_DEBUGGER - // should probably take a look at https://github.com/scottt/debugbreak --#ifdef DOCTEST_PLATFORM_MAC --#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) -+#ifdef DOCTEST_PLATFORM_LINUX -+#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) -+// Break at the location of the failing check if possible -+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler) -+#else -+#include <signal.h> -+#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP) -+#endif -+#elif defined(DOCTEST_PLATFORM_MAC) -+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) -+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler) -+#else -+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT (hicpp-no-assembler) -+#endif - #elif DOCTEST_MSVC - #define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() - #elif defined(__MINGW32__) -@@ -367,40 +419,40 @@ - DOCTEST_GCC_SUPPRESS_WARNING_POP - #define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() - #else // linux --#define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0) -+#define DOCTEST_BREAK_INTO_DEBUGGER() (static_cast<void>(0)) - #endif // linux -+#endif // DOCTEST_BREAK_INTO_DEBUGGER - - // this is kept here for backwards compatibility since the config option was changed - #ifdef DOCTEST_CONFIG_USE_IOSFWD - #define DOCTEST_CONFIG_USE_STD_HEADERS - #endif // DOCTEST_CONFIG_USE_IOSFWD - --#ifdef DOCTEST_CONFIG_USE_STD_HEADERS --#include <iosfwd> --#include <cstddef> --#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) --// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 --#include <ostream> --#endif // VS 2019 --#else // DOCTEST_CONFIG_USE_STD_HEADERS -- -+// for clang - always include ciso646 (which drags some std stuff) because -+// we want to check if we are using libc++ with the _LIBCPP_VERSION macro in -+// which case we don't want to forward declare stuff from std - for reference: -+// https://github.com/doctest/doctest/issues/126 -+// https://github.com/doctest/doctest/issues/356 - #if DOCTEST_CLANG --// to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier) - #include <ciso646> --#endif // clang -- - #ifdef _LIBCPP_VERSION --#define DOCTEST_STD_NAMESPACE_BEGIN _LIBCPP_BEGIN_NAMESPACE_STD --#define DOCTEST_STD_NAMESPACE_END _LIBCPP_END_NAMESPACE_STD --#else // _LIBCPP_VERSION --#define DOCTEST_STD_NAMESPACE_BEGIN namespace std { --#define DOCTEST_STD_NAMESPACE_END } -+#define DOCTEST_CONFIG_USE_STD_HEADERS - #endif // _LIBCPP_VERSION -+#endif // clang -+ -+#ifdef DOCTEST_CONFIG_USE_STD_HEADERS -+#ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -+#define DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -+#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -+#include <cstddef> -+#include <ostream> -+#include <istream> -+#else // DOCTEST_CONFIG_USE_STD_HEADERS - - // Forward declaring 'X' in namespace std is not permitted by the C++ Standard. - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) - --DOCTEST_STD_NAMESPACE_BEGIN // NOLINT (cert-dcl58-cpp) -+namespace std { // NOLINT (cert-dcl58-cpp) - typedef decltype(nullptr) nullptr_t; - template <class charT> - struct char_traits; -@@ -409,17 +461,20 @@ - template <class charT, class traits> - class basic_ostream; - typedef basic_ostream<char, char_traits<char>> ostream; -+template <class charT, class traits> -+class basic_istream; -+typedef basic_istream<char, char_traits<char>> istream; - template <class... Types> - class tuple; - #if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) --// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 --template <class _Ty> -+// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 -+template <class Ty> - class allocator; --template <class _Elem, class _Traits, class _Alloc> -+template <class Elem, class Traits, class Alloc> - class basic_string; - using string = basic_string<char, char_traits<char>, allocator<char>>; - #endif // VS 2019 --DOCTEST_STD_NAMESPACE_END -+} // namespace std - - DOCTEST_MSVC_SUPPRESS_WARNING_POP - -@@ -471,6 +526,8 @@ - view data; - }; - -+ char* allocate(unsigned sz); -+ - bool isOnStack() const { return (buf[last] & 128) == 0; } - void setOnHeap(); - void setLast(unsigned in = last); -@@ -485,11 +542,12 @@ - String(const char* in); - String(const char* in, unsigned in_size); - -+ String(std::istream& in, unsigned in_size); -+ - String(const String& other); - String& operator=(const String& other); - - String& operator+=(const String& other); -- String operator+(const String& other) const; - - String(String&& other); - String& operator=(String&& other); -@@ -512,6 +570,8 @@ - int compare(const String& other, bool no_case = false) const; - }; - -+DOCTEST_INTERFACE String operator+(const String& lhs, const String& rhs); -+ - DOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs); - DOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs); - DOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs); -@@ -592,6 +652,10 @@ - DT_WARN_THROWS_WITH = is_throws_with | is_warn, - DT_CHECK_THROWS_WITH = is_throws_with | is_check, - DT_REQUIRE_THROWS_WITH = is_throws_with | is_require, -+ -+ DT_WARN_THROWS_WITH_AS = is_throws_with | is_throws_as | is_warn, -+ DT_CHECK_THROWS_WITH_AS = is_throws_with | is_throws_as | is_check, -+ DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require, - - DT_WARN_NOTHROW = is_nothrow | is_warn, - DT_CHECK_NOTHROW = is_nothrow | is_check, -@@ -637,19 +701,18 @@ - - struct DOCTEST_INTERFACE TestCaseData - { -- const char* m_file; // the file in which the test was registered -+ String m_file; // the file in which the test was registered (using String - see #350) - unsigned m_line; // the line where the test was registered - const char* m_name; // name of the test case - const char* m_test_suite; // the test suite in which the test was added - const char* m_description; - bool m_skip; -+ bool m_no_breaks; -+ bool m_no_output; - bool m_may_fail; - bool m_should_fail; - int m_expected_failures; - double m_timeout; -- -- DOCTEST_DECLARE_DEFAULTS(TestCaseData); -- DOCTEST_DECLARE_COPIES(TestCaseData); - }; - - struct DOCTEST_INTERFACE AssertData -@@ -672,9 +735,7 @@ - // for specific exception-related asserts - bool m_threw_as; - const char* m_exception_type; -- -- DOCTEST_DECLARE_DEFAULTS(AssertData); -- DOCTEST_DELETE_COPIES(AssertData); -+ const char* m_exception_string; - }; - - struct DOCTEST_INTERFACE MessageData -@@ -683,39 +744,34 @@ - const char* m_file; - int m_line; - assertType::Enum m_severity; -- -- DOCTEST_DECLARE_DEFAULTS(MessageData); -- DOCTEST_DELETE_COPIES(MessageData); - }; - - struct DOCTEST_INTERFACE SubcaseSignature - { -- const char* m_name; -+ String m_name; - const char* m_file; - int m_line; - -- SubcaseSignature(const char* name, const char* file, int line); -- - bool operator<(const SubcaseSignature& other) const; -- -- DOCTEST_DECLARE_DEFAULTS(SubcaseSignature); -- DOCTEST_DECLARE_COPIES(SubcaseSignature); - }; - - struct DOCTEST_INTERFACE IContextScope - { -- DOCTEST_DELETE_COPIES(IContextScope); -- - IContextScope(); - virtual ~IContextScope(); - virtual void stringify(std::ostream*) const = 0; - }; - -+namespace detail { -+ struct DOCTEST_INTERFACE TestCase; -+} // namespace detail -+ - struct ContextOptions //!OCLINT too many fields - { -- std::ostream* cout; // stdout stream - std::cout by default -- std::ostream* cerr; // stderr stream - std::cerr by default -- String binary_name; // the test binary name -+ std::ostream* cout = nullptr; // stdout stream -+ String binary_name; // the test binary name -+ -+ const detail::TestCase* currentTest = nullptr; - - // == parameters from the command line - String out; // output filename -@@ -732,9 +788,12 @@ - bool case_sensitive; // if filtering should be case sensitive - bool exit; // if the program should be exited after the tests are ran/whatever - bool duration; // print the time duration of each test case -+ bool minimal; // minimal console output (only test failures) -+ bool quiet; // no console output - bool no_throw; // to skip exceptions-related assertion macros - bool no_exitcode; // if the framework should return 0 as the exitcode - bool no_run; // to not run the tests at all (can be done with an "*" exclude) -+ bool no_intro; // to not print the intro of the framework - bool no_version; // to not print the version of the framework - bool no_colors; // if output to the console should be colorized - bool force_colors; // forces the use of colors even when a tty cannot be detected -@@ -743,21 +802,19 @@ - bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): - bool no_path_in_filenames; // if the path to files should be removed from the output - bool no_line_numbers; // if source code line numbers should be omitted from the output -+ bool no_debug_output; // no output in the debug console when a debugger is attached - bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! -+ bool no_time_in_output; // omit any time/timestamps from output !!! UNDOCUMENTED !!! - - bool help; // to print the help - bool version; // to print the version -- bool count; // if only the count of matching tests is to be retreived -+ bool count; // if only the count of matching tests is to be retrieved - bool list_test_cases; // to list all tests matching the filters - bool list_test_suites; // to list all suites matching the filters - bool list_reporters; // lists all registered reporters -- -- DOCTEST_DECLARE_DEFAULTS(ContextOptions); -- DOCTEST_DELETE_COPIES(ContextOptions); - }; - - namespace detail { --#if defined(DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) || defined(DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS) - template <bool CONDITION, typename TYPE = void> - struct enable_if - {}; -@@ -765,15 +822,48 @@ - template <typename TYPE> - struct enable_if<true, TYPE> - { typedef TYPE type; }; --#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) || DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - // clang-format off - template<class T> struct remove_reference { typedef T type; }; - template<class T> struct remove_reference<T&> { typedef T type; }; - template<class T> struct remove_reference<T&&> { typedef T type; }; - -+ template<typename T, typename U = T&&> U declval(int); -+ -+ template<typename T> T declval(long); -+ -+ template<typename T> auto declval() DOCTEST_NOEXCEPT -> decltype(declval<T>(0)) ; -+ -+ template<class T> struct is_lvalue_reference { const static bool value=false; }; -+ template<class T> struct is_lvalue_reference<T&> { const static bool value=true; }; -+ -+ template<class T> struct is_rvalue_reference { const static bool value=false; }; -+ template<class T> struct is_rvalue_reference<T&&> { const static bool value=true; }; -+ -+ template <class T> -+ inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT -+ { -+ return static_cast<T&&>(t); -+ } -+ -+ template <class T> -+ inline T&& forward(typename remove_reference<T>::type&& t) DOCTEST_NOEXCEPT -+ { -+ static_assert(!is_lvalue_reference<T>::value, -+ "Can not forward an rvalue as an lvalue."); -+ return static_cast<T&&>(t); -+ } -+ - template<class T> struct remove_const { typedef T type; }; - template<class T> struct remove_const<const T> { typedef T type; }; -+#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -+ template<class T> struct is_enum : public std::is_enum<T> {}; -+ template<class T> struct underlying_type : public std::underlying_type<T> {}; -+#else -+ // Use compiler intrinsics -+ template<class T> struct is_enum { DOCTEST_CONSTEXPR static bool value = __is_enum(T); }; -+ template<class T> struct underlying_type { typedef __underlying_type(T) type; }; -+#endif - // clang-format on - - template <typename T> -@@ -782,38 +872,27 @@ - { static const bool value = false; }; - - namespace has_insertion_operator_impl { -- typedef char no; -- typedef char yes[2]; -- -- struct any_t -- { -- template <typename T> -- // cppcheck-suppress noExplicitConstructor -- any_t(const DOCTEST_REF_WRAP(T)); -+ std::ostream &os(); -+ template<class T> -+ DOCTEST_REF_WRAP(T) val(); -+ -+ template<class, class = void> -+ struct check { -+ static DOCTEST_CONSTEXPR bool value = false; - }; - -- yes& testStreamable(std::ostream&); -- no testStreamable(no); -- -- no operator<<(const std::ostream&, const any_t&); -- -- template <typename T> -- struct has_insertion_operator -- { -- static std::ostream& s; -- static const DOCTEST_REF_WRAP(T) t; -- static const bool value = sizeof(decltype(testStreamable(s << t))) == sizeof(yes); -+ template<class T> -+ struct check<T, decltype(os() << val<T>(), void())> { -+ static DOCTEST_CONSTEXPR bool value = true; - }; - } // namespace has_insertion_operator_impl - -- template <typename T> -- struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator<T> -- {}; -+ template<class T> -+ using has_insertion_operator = has_insertion_operator_impl::check<const T>; - -- DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned num); -+ DOCTEST_INTERFACE std::ostream* tlssPush(); -+ DOCTEST_INTERFACE String tlssPop(); - -- DOCTEST_INTERFACE std::ostream* getTlsOss(); // returns a thread-local ostringstream -- DOCTEST_INTERFACE String getTlsOssResult(); - - template <bool C> - struct StringMakerBase -@@ -824,13 +903,61 @@ - } - }; - -+ // Vector<int> and various type other than pointer or array. -+ template<typename T> -+ struct filldata -+ { -+ static void fill(std::ostream* stream, const T &in) { -+ *stream << in; -+ } -+ }; -+ -+ template<typename T,unsigned long N> -+ struct filldata<T[N]> -+ { -+ static void fill(std::ostream* stream, const T (&in)[N]) { -+ for (unsigned long i = 0; i < N; i++) { -+ *stream << in[i]; -+ } -+ } -+ }; -+ -+ // Specialized since we don't want the terminating null byte! -+ template<unsigned long N> -+ struct filldata<const char[N]> -+ { -+ static void fill(std::ostream* stream, const char(&in)[N]) { -+ *stream << in; -+ } -+ }; -+ -+ template<typename T> -+ void filloss(std::ostream* stream, const T& in) { -+ filldata<T>::fill(stream, in); -+ } -+ -+ template<typename T,unsigned long N> -+ void filloss(std::ostream* stream, const T (&in)[N]) { -+ // T[N], T(&)[N], T(&&)[N] have same behaviour. -+ // Hence remove reference. -+ filldata<typename remove_reference<decltype(in)>::type>::fill(stream, in); -+ } -+ - template <> - struct StringMakerBase<true> - { - template <typename T> - static String convert(const DOCTEST_REF_WRAP(T) in) { -- *getTlsOss() << in; -- return getTlsOssResult(); -+ /* When parameter "in" is a null terminated const char* it works. -+ * When parameter "in" is a T arr[N] without '\0' we can fill the -+ * stringstream with N objects (T=char).If in is char pointer * -+ * without '\0' , it would cause segfault -+ * stepping over unaccessible memory. -+ */ -+ -+ std::ostream* stream = tlssPush(); -+ filloss(stream, in); -+ return tlssPop(); - } - }; - -@@ -872,7 +999,7 @@ - } - }; - --template <typename T> -+template <typename T, typename detail::enable_if<!detail::is_enum<T>::value, bool>::type = true> - String toString(const DOCTEST_REF_WRAP(T) value) { - return StringMaker<T>::convert(value); - } -@@ -899,8 +1026,14 @@ - DOCTEST_INTERFACE String toString(int long long unsigned in); - DOCTEST_INTERFACE String toString(std::nullptr_t in); - -+template <typename T, typename detail::enable_if<detail::is_enum<T>::value, bool>::type = true> -+String toString(const DOCTEST_REF_WRAP(T) value) { -+ typedef typename detail::underlying_type<T>::type UT; -+ return toString(static_cast<UT>(value)); -+} -+ - #if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) --// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 -+// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 - DOCTEST_INTERFACE String toString(const std::string& in); - #endif // VS 2019 - -@@ -909,8 +1042,6 @@ - public: - explicit Approx(double value); - -- DOCTEST_DECLARE_COPIES(Approx); -- - Approx operator()(double value) const; - - #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -@@ -1010,14 +1141,12 @@ - - struct DOCTEST_INTERFACE TestFailureException - { -- DOCTEST_DECLARE_DEFAULTS(TestFailureException); -- DOCTEST_DECLARE_COPIES(TestFailureException); - }; - - DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); - - #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -- [[noreturn]] -+ DOCTEST_NORETURN - #endif // DOCTEST_CONFIG_NO_EXCEPTIONS - DOCTEST_INTERFACE void throwException(); - -@@ -1026,24 +1155,42 @@ - SubcaseSignature m_signature; - bool m_entered = false; - -- Subcase(const char* name, const char* file, int line); -+ Subcase(const String& name, const char* file, int line); - ~Subcase(); - -- DOCTEST_DELETE_COPIES(Subcase); -- - operator bool() const; - }; - - template <typename L, typename R> - String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, - const DOCTEST_REF_WRAP(R) rhs) { -+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - return toString(lhs) + op + toString(rhs); - } - -+#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) -+DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison") -+#endif -+ -+// This will check if there is any way it could find a operator like member or friend and uses it. -+// If not it doesn't find the operator or if the operator at global scope is defined after -+// this template, the template won't be instantiated due to SFINAE. Once the template is not -+// instantiated it can look for global operator using normal conversions. -+#define SFINAE_OP(ret,op) decltype((void)(doctest::detail::declval<L>() op doctest::detail::declval<R>()),ret{}) -+ - #define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ - template <typename R> \ -- DOCTEST_NOINLINE Result operator op(const DOCTEST_REF_WRAP(R) rhs) { \ -- bool res = op_macro(lhs, rhs); \ -+ DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(const R&& rhs) { \ -+ bool res = op_macro(doctest::detail::forward<const L>(lhs), doctest::detail::forward<const R>(rhs)); \ -+ if(m_at & assertType::is_false) \ -+ res = !res; \ -+ if(!res || doctest::getContextOptions()->success) \ -+ return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ -+ return Result(res); \ -+ } \ -+ template <typename R ,typename enable_if<!doctest::detail::is_rvalue_reference<R>::value, void >::type* = nullptr> \ -+ DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(const R& rhs) { \ -+ bool res = op_macro(doctest::detail::forward<const L>(lhs), rhs); \ - if(m_at & assertType::is_false) \ - res = !res; \ - if(!res || doctest::getContextOptions()->success) \ -@@ -1067,12 +1214,10 @@ - bool m_passed; - String m_decomp; - -+ Result() = default; - Result(bool passed, const String& decomposition = String()); - -- DOCTEST_DECLARE_DEFAULTS(Result); -- DOCTEST_DECLARE_COPIES(Result); -- -- // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence -+ // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence - DOCTEST_FORBIT_EXPRESSION(Result, &) - DOCTEST_FORBIT_EXPRESSION(Result, ^) - DOCTEST_FORBIT_EXPRESSION(Result, |) -@@ -1114,7 +1259,7 @@ - //DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal") - - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -- // http://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389 -+ // https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389 - DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch - DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch - DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch -@@ -1127,6 +1272,7 @@ - #define DOCTEST_COMPARISON_RETURN_TYPE bool - #else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - #define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type -+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } - inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } - inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } -@@ -1173,12 +1319,15 @@ - L lhs; - assertType::Enum m_at; - -- explicit Expression_lhs(L in, assertType::Enum at) -- : lhs(in) -+ explicit Expression_lhs(L&& in, assertType::Enum at) -+ : lhs(doctest::detail::forward<L>(in)) - , m_at(at) {} - - DOCTEST_NOINLINE operator Result() { -- bool res = !!lhs; -+// this is needed only for MSVC 2015 -+DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool -+ bool res = static_cast<bool>(lhs); -+DOCTEST_MSVC_SUPPRESS_WARNING_POP - if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional - res = !res; - -@@ -1187,6 +1336,9 @@ - return Result(res); - } - -+ /* This is required for user-defined conversions from Expression_lhs to L */ -+ operator L() const { return lhs; } -+ - // clang-format off - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional -@@ -1196,7 +1348,7 @@ - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional - // clang-format on - -- // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence -+ // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |) -@@ -1227,37 +1379,42 @@ - - #endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - -+#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) -+DOCTEST_CLANG_SUPPRESS_WARNING_POP -+#endif -+ - struct DOCTEST_INTERFACE ExpressionDecomposer - { - assertType::Enum m_at; - - ExpressionDecomposer(assertType::Enum at); - -- DOCTEST_DECLARE_DEFAULTS(ExpressionDecomposer); -- DOCTEST_DELETE_COPIES(ExpressionDecomposer); -- - // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator precedence table) - // but then there will be warnings from GCC about "-Wparentheses" and since "_Pragma()" is problematic this will stay for now... - // https://github.com/catchorg/Catch2/issues/870 - // https://github.com/catchorg/Catch2/issues/565 - template <typename L> -- Expression_lhs<const DOCTEST_REF_WRAP(L)> operator<<(const DOCTEST_REF_WRAP(L) operand) { -- return Expression_lhs<const DOCTEST_REF_WRAP(L)>(operand, m_at); -+ Expression_lhs<const L> operator<<(const L &&operand) { -+ return Expression_lhs<const L>(doctest::detail::forward<const L>(operand), m_at); -+ } -+ -+ template <typename L,typename enable_if<!doctest::detail::is_rvalue_reference<L>::value,void >::type* = nullptr> -+ Expression_lhs<const L&> operator<<(const L &operand) { -+ return Expression_lhs<const L&>(operand, m_at); - } - }; - - struct DOCTEST_INTERFACE TestSuite - { -- const char* m_test_suite; -- const char* m_description; -- bool m_skip; -- bool m_may_fail; -- bool m_should_fail; -- int m_expected_failures; -- double m_timeout; -- -- DOCTEST_DECLARE_DEFAULTS(TestSuite); -- DOCTEST_DECLARE_COPIES(TestSuite); -+ const char* m_test_suite = nullptr; -+ const char* m_description = nullptr; -+ bool m_skip = false; -+ bool m_no_breaks = false; -+ bool m_no_output = false; -+ bool m_may_fail = false; -+ bool m_should_fail = false; -+ int m_expected_failures = 0; -+ double m_timeout = 0; - - TestSuite& operator*(const char* in); - -@@ -1281,8 +1438,6 @@ - TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, - const char* type = "", int template_id = -1); - -- DOCTEST_DECLARE_DEFAULTS(TestCase); -- - TestCase(const TestCase& other); - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function -@@ -1327,33 +1482,31 @@ - template <class L, class R> struct RelationalComparator<n, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } }; - // clang-format on - -- DOCTEST_BINARY_RELATIONAL_OP(0, eq) -- DOCTEST_BINARY_RELATIONAL_OP(1, ne) -- DOCTEST_BINARY_RELATIONAL_OP(2, gt) -- DOCTEST_BINARY_RELATIONAL_OP(3, lt) -- DOCTEST_BINARY_RELATIONAL_OP(4, ge) -- DOCTEST_BINARY_RELATIONAL_OP(5, le) -+ DOCTEST_BINARY_RELATIONAL_OP(0, doctest::detail::eq) -+ DOCTEST_BINARY_RELATIONAL_OP(1, doctest::detail::ne) -+ DOCTEST_BINARY_RELATIONAL_OP(2, doctest::detail::gt) -+ DOCTEST_BINARY_RELATIONAL_OP(3, doctest::detail::lt) -+ DOCTEST_BINARY_RELATIONAL_OP(4, doctest::detail::ge) -+ DOCTEST_BINARY_RELATIONAL_OP(5, doctest::detail::le) - - struct DOCTEST_INTERFACE ResultBuilder : public AssertData - { - ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, -- const char* exception_type = ""); -- -- DOCTEST_DECLARE_DEFAULTS(ResultBuilder); -- DOCTEST_DELETE_COPIES(ResultBuilder); -+ const char* exception_type = "", const char* exception_string = ""); - - void setResult(const Result& res); - - template <int comparison, typename L, typename R> -- DOCTEST_NOINLINE void binary_assert(const DOCTEST_REF_WRAP(L) lhs, -+ DOCTEST_NOINLINE bool binary_assert(const DOCTEST_REF_WRAP(L) lhs, - const DOCTEST_REF_WRAP(R) rhs) { - m_failed = !RelationalComparator<comparison, L, R>()(lhs, rhs); - if(m_failed || getContextOptions()->success) - m_decomp = stringifyBinaryExpr(lhs, ", ", rhs); -+ return !m_failed; - } - - template <typename L> -- DOCTEST_NOINLINE void unary_assert(const DOCTEST_REF_WRAP(L) val) { -+ DOCTEST_NOINLINE bool unary_assert(const DOCTEST_REF_WRAP(L) val) { - m_failed = !val; - - if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional -@@ -1361,6 +1514,8 @@ - - if(m_failed || getContextOptions()->success) - m_decomp = toString(val); -+ -+ return !m_failed; - } - - void translateException(); -@@ -1380,7 +1535,7 @@ - - DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData& ad); - -- DOCTEST_INTERFACE void decomp_assert(assertType::Enum at, const char* file, int line, -+ DOCTEST_INTERFACE bool decomp_assert(assertType::Enum at, const char* file, int line, - const char* expr, Result result); - - #define DOCTEST_ASSERT_OUT_OF_TESTS(decomp) \ -@@ -1396,7 +1551,7 @@ - if(checkIfShouldThrow(at)) \ - throwException(); \ - } \ -- return; \ -+ return !failed; \ - } \ - } while(false) - -@@ -1411,7 +1566,7 @@ - throwException() - - template <int comparison, typename L, typename R> -- DOCTEST_NOINLINE void binary_assert(assertType::Enum at, const char* file, int line, -+ DOCTEST_NOINLINE bool binary_assert(assertType::Enum at, const char* file, int line, - const char* expr, const DOCTEST_REF_WRAP(L) lhs, - const DOCTEST_REF_WRAP(R) rhs) { - bool failed = !RelationalComparator<comparison, L, R>()(lhs, rhs); -@@ -1422,10 +1577,11 @@ - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); - DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); -+ return !failed; - } - - template <typename L> -- DOCTEST_NOINLINE void unary_assert(assertType::Enum at, const char* file, int line, -+ DOCTEST_NOINLINE bool unary_assert(assertType::Enum at, const char* file, int line, - const char* expr, const DOCTEST_REF_WRAP(L) val) { - bool failed = !val; - -@@ -1438,12 +1594,11 @@ - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(toString(val)); - DOCTEST_ASSERT_IN_TESTS(toString(val)); -+ return !failed; - } - - struct DOCTEST_INTERFACE IExceptionTranslator - { -- DOCTEST_DELETE_COPIES(IExceptionTranslator); -- - IExceptionTranslator(); - virtual ~IExceptionTranslator(); - virtual bool translate(String&) const = 0; -@@ -1464,9 +1619,9 @@ - } catch(T ex) { // NOLINT - res = m_translateFunction(ex); //!OCLINT parameter reassignment - return true; -- } catch(...) {} //!OCLINT - empty catch statement --#endif // DOCTEST_CONFIG_NO_EXCEPTIONS -- ((void)res); // to silence -Wunused-parameter -+ } catch(...) {} //!OCLINT - empty catch statement -+#endif // DOCTEST_CONFIG_NO_EXCEPTIONS -+ static_cast<void>(res); // to silence -Wunused-parameter - return false; - } - -@@ -1533,40 +1688,57 @@ - class DOCTEST_INTERFACE ContextScopeBase : public IContextScope { - protected: - ContextScopeBase(); -+ ContextScopeBase(ContextScopeBase&& other); - - void destroy(); -+ bool need_to_destroy{true}; - }; - -- template <typename L> class DOCTEST_INTERFACE ContextScope : public ContextScopeBase -+ template <typename L> class ContextScope : public ContextScopeBase - { -- const L &lambda_; -+ const L lambda_; - - public: - explicit ContextScope(const L &lambda) : lambda_(lambda) {} - -- ContextScope(ContextScope &&other) : lambda_(other.lambda_) {} -+ ContextScope(ContextScope &&other) : ContextScopeBase(static_cast<ContextScopeBase&&>(other)), lambda_(other.lambda_) {} - - void stringify(std::ostream* s) const override { lambda_(s); } - -- ~ContextScope() override { destroy(); } -+ ~ContextScope() override { -+ if (need_to_destroy) { -+ destroy(); -+ } -+ } - }; - - struct DOCTEST_INTERFACE MessageBuilder : public MessageData - { - std::ostream* m_stream; -+ bool logged = false; - - MessageBuilder(const char* file, int line, assertType::Enum severity); - MessageBuilder() = delete; - ~MessageBuilder(); - -- DOCTEST_DELETE_COPIES(MessageBuilder); -- -+ // the preferred way of chaining parameters for stringification - template <typename T> -- MessageBuilder& operator<<(const T& in) { -+ MessageBuilder& operator,(const T& in) { - toStream(m_stream, in); - return *this; - } - -+ // kept here just for backwards-compatibility - the comma operator should be preferred now -+ template <typename T> -+ MessageBuilder& operator<<(const T& in) { return this->operator,(in); } -+ -+ // the `,` operator has the lowest operator precedence - if `<<` is used by the user then -+ // the `,` operator will be called last which is not what we want and thus the `*` operator -+ // is used first (has higher operator precedence compared to `<<`) so that we guarantee that -+ // an operator of the MessageBuilder class is called first before the rest of the parameters -+ template <typename T> -+ MessageBuilder& operator*(const T& in) { return this->operator,(in); } -+ - bool log(); - void react(); - }; -@@ -1590,6 +1762,8 @@ - DOCTEST_DEFINE_DECORATOR(test_suite, const char*, ""); - DOCTEST_DEFINE_DECORATOR(description, const char*, ""); - DOCTEST_DEFINE_DECORATOR(skip, bool, true); -+DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true); -+DOCTEST_DEFINE_DECORATOR(no_output, bool, true); - DOCTEST_DEFINE_DECORATOR(timeout, double, 0); - DOCTEST_DEFINE_DECORATOR(may_fail, bool, true); - DOCTEST_DEFINE_DECORATOR(should_fail, bool, true); -@@ -1634,14 +1808,13 @@ - public: - explicit Context(int argc = 0, const char* const* argv = nullptr); - -- DOCTEST_DELETE_COPIES(Context); -- - ~Context(); - - void applyCommandLine(int argc, const char* const* argv); - - void addFilter(const char* filter, const char* value); - void clearFilters(); -+ void setOption(const char* option, bool value); - void setOption(const char* option, int value); - void setOption(const char* option, const char* value); - -@@ -1651,6 +1824,8 @@ - - void setAssertHandler(detail::assert_handler ah); - -+ void setCout(std::ostream* out); -+ - int run(); - }; - -@@ -1677,9 +1852,7 @@ - int numAssertsFailedCurrentTest; - double seconds; - int failure_flags; // use TestCaseFailureReason::Enum -- -- DOCTEST_DECLARE_DEFAULTS(CurrentTestCaseStats); -- DOCTEST_DELETE_COPIES(CurrentTestCaseStats); -+ bool testCaseSuccess; - }; - - struct DOCTEST_INTERFACE TestCaseException -@@ -1696,16 +1869,13 @@ - unsigned numTestCasesFailed; - int numAsserts; - int numAssertsFailed; -- -- DOCTEST_DECLARE_DEFAULTS(TestRunStats); -- DOCTEST_DELETE_COPIES(TestRunStats); - }; - - struct QueryData - { -- const TestRunStats* run_stats = nullptr; -- String* data = nullptr; -- unsigned num_data = 0; -+ const TestRunStats* run_stats = nullptr; -+ const TestCaseData** data = nullptr; -+ unsigned num_data = 0; - }; - - struct DOCTEST_INTERFACE IReporter -@@ -1724,6 +1894,8 @@ - - // called when a test case is started (safe to cache a pointer to the input) - virtual void test_case_start(const TestCaseData&) = 0; -+ // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input) -+ virtual void test_case_reenter(const TestCaseData&) = 0; - // called when a test case has ended - virtual void test_case_end(const CurrentTestCaseStats&) = 0; - -@@ -1778,10 +1950,11 @@ - #if !defined(DOCTEST_CONFIG_DISABLE) - - // common code in asserts - for convenience --#define DOCTEST_ASSERT_LOG_AND_REACT(b) \ -+#define DOCTEST_ASSERT_LOG_REACT_RETURN(b) \ - if(b.log()) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ -- b.react() -+ b.react(); \ -+ return !b.m_failed - - #ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS - #define DOCTEST_WRAP_IN_TRY(x) x; -@@ -1789,27 +1962,26 @@ - #define DOCTEST_WRAP_IN_TRY(x) \ - try { \ - x; \ -- } catch(...) { _DOCTEST_RB.translateException(); } -+ } catch(...) { DOCTEST_RB.translateException(); } - #endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS - - #ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS --#define DOCTEST_CAST_TO_VOID(x) \ -+#define DOCTEST_CAST_TO_VOID(...) \ - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \ -- static_cast<void>(x); \ -+ static_cast<void>(__VA_ARGS__); \ - DOCTEST_GCC_SUPPRESS_WARNING_POP - #else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS --#define DOCTEST_CAST_TO_VOID(x) x; -+#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__; - #endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS - - // registers the test by initializing a dummy var with a function - #define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators) \ -- global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ -+ global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), \ - doctest::detail::regTest( \ - doctest::detail::TestCase( \ - f, __FILE__, __LINE__, \ - doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ -- decorators); \ -- DOCTEST_GLOBAL_NO_WARNINGS_END() -+ decorators)) - - #define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators) \ - namespace { \ -@@ -1832,18 +2004,18 @@ - - #define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators) \ - static doctest::detail::funcType proxy() { return f; } \ -- DOCTEST_REGISTER_FUNCTION(inline const, proxy(), decorators) \ -+ DOCTEST_REGISTER_FUNCTION(inline, proxy(), decorators) \ - static void f() - - // for registering tests - #define DOCTEST_TEST_CASE(decorators) \ -- DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) -+ DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators) - - // for registering tests in classes - requires C++17 for inline variables! - #if __cplusplus >= 201703L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 12, 0) && _MSVC_LANG >= 201703L) - #define DOCTEST_TEST_CASE_CLASS(decorators) \ -- DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), \ -- DOCTEST_ANONYMOUS(_DOCTEST_ANON_PROXY_), \ -+ DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), \ -+ DOCTEST_ANONYMOUS(DOCTEST_ANON_PROXY_), \ - decorators) - #else // DOCTEST_TEST_CASE_CLASS - #define DOCTEST_TEST_CASE_CLASS(...) \ -@@ -1852,8 +2024,8 @@ - - // for registering tests with a fixture - #define DOCTEST_TEST_CASE_FIXTURE(c, decorators) \ -- DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c, \ -- DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) -+ DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), c, \ -+ DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators) - - // for converting types to strings without the <typeinfo> header and demangling - #define DOCTEST_TYPE_TO_STRING_IMPL(...) \ -@@ -1866,7 +2038,7 @@ - DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__) \ - } \ - } \ -- typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+ static_assert(true, "") - - #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \ - template <typename T> \ -@@ -1897,20 +2069,20 @@ - - #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id) \ - DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR), \ -- DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) -+ DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)) - - #define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...) \ -- DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = \ -- doctest::detail::instantiationHelper(DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0));\ -- DOCTEST_GLOBAL_NO_WARNINGS_END() -+ DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY), \ -+ doctest::detail::instantiationHelper( \ -+ DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0))) - - #define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ -- DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ -- typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+ DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ -+ static_assert(true, "") - - #define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ -- DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \ -- typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+ DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) \ -+ static_assert(true, "") - - #define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon); \ -@@ -1919,11 +2091,11 @@ - static void anon() - - #define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...) \ -- DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) -+ DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) - - // for subcases - #define DOCTEST_SUBCASE(name) \ -- if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ -+ if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ - doctest::detail::Subcase(name, __FILE__, __LINE__)) - - // for grouping tests in test suites by using code blocks -@@ -1932,10 +2104,12 @@ - static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \ - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \ -- static doctest::detail::TestSuite data; \ -+ DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers") \ -+ static doctest::detail::TestSuite data{}; \ - static bool inited = false; \ - DOCTEST_MSVC_SUPPRESS_WARNING_POP \ - DOCTEST_CLANG_SUPPRESS_WARNING_POP \ -+ DOCTEST_GCC_SUPPRESS_WARNING_POP \ - if(!inited) { \ - data* decorators; \ - inited = true; \ -@@ -1947,79 +2121,79 @@ - namespace ns_name - - #define DOCTEST_TEST_SUITE(decorators) \ -- DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_)) -+ DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(DOCTEST_ANON_SUITE_)) - - // for starting a testsuite block - #define DOCTEST_TEST_SUITE_BEGIN(decorators) \ -- DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ -- doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators); \ -- DOCTEST_GLOBAL_NO_WARNINGS_END() \ -- typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+ DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), \ -+ doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators)) \ -+ static_assert(true, "") - - // for ending a testsuite block - #define DOCTEST_TEST_SUITE_END \ -- DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ -- doctest::detail::setTestSuite(doctest::detail::TestSuite() * ""); \ -- DOCTEST_GLOBAL_NO_WARNINGS_END() \ -- typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+ DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), \ -+ doctest::detail::setTestSuite(doctest::detail::TestSuite() * "")) \ -+ typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_) - - // for registering exception translators - #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature) \ - inline doctest::String translatorName(signature); \ -- DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)) = \ -- doctest::registerExceptionTranslator(translatorName); \ -- DOCTEST_GLOBAL_NO_WARNINGS_END() \ -+ DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_), \ -+ doctest::registerExceptionTranslator(translatorName)) \ - doctest::String translatorName(signature) - - #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ -- DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_), \ -+ DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_), \ - signature) - - // for registering reporters - #define DOCTEST_REGISTER_REPORTER(name, priority, reporter) \ -- DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ -- doctest::registerReporter<reporter>(name, priority, true); \ -- DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+ DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_), \ -+ doctest::registerReporter<reporter>(name, priority, true)) \ -+ static_assert(true, "") - - // for registering listeners - #define DOCTEST_REGISTER_LISTENER(name, priority, reporter) \ -- DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ -- doctest::registerReporter<reporter>(name, priority, false); \ -- DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -- --// for logging --#define DOCTEST_INFO(expression) \ -- DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \ -- DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), expression) -- --#define DOCTEST_INFO_IMPL(lambda_name, mb_name, s_name, expression) \ -- DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \ -- auto lambda_name = [&](std::ostream* s_name) { \ -+ DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_), \ -+ doctest::registerReporter<reporter>(name, priority, false)) \ -+ static_assert(true, "") -+ -+// clang-format off -+// for logging - disabling formatting because it's important to have these on 2 separate lines - see PR #557 -+#define DOCTEST_INFO(...) \ -+ DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_), \ -+ DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_OTHER_), \ -+ __VA_ARGS__) -+// clang-format on -+ -+#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \ -+ auto DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \ -+ [&](std::ostream* s_name) { \ - doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ - mb_name.m_stream = s_name; \ -- mb_name << expression; \ -- }; \ -- DOCTEST_MSVC_SUPPRESS_WARNING_POP \ -- auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope(lambda_name) -+ mb_name * __VA_ARGS__; \ -+ }) - --#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := " << x) -+#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x) - --#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, x) \ -- do { \ -+#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, ...) \ -+ [&] { \ - doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type); \ -- mb << x; \ -- DOCTEST_ASSERT_LOG_AND_REACT(mb); \ -- } while((void)0, 0) -+ mb * __VA_ARGS__; \ -+ if(mb.log()) \ -+ DOCTEST_BREAK_INTO_DEBUGGER(); \ -+ mb.react(); \ -+ }() - - // clang-format off --#define DOCTEST_ADD_MESSAGE_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) --#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) --#define DOCTEST_ADD_FAIL_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) -+#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) -+#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) -+#define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) - // clang-format on - --#define DOCTEST_MESSAGE(x) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, x) --#define DOCTEST_FAIL_CHECK(x) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, x) --#define DOCTEST_FAIL(x) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, x) -+#define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, __VA_ARGS__) -+#define DOCTEST_FAIL_CHECK(...) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, __VA_ARGS__) -+#define DOCTEST_FAIL(...) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, __VA_ARGS__) - - #define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility. - -@@ -2027,21 +2201,24 @@ - - #define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ -- doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -+ doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, #__VA_ARGS__); \ -- DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.setResult( \ -+ DOCTEST_WRAP_IN_TRY(DOCTEST_RB.setResult( \ - doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ - << __VA_ARGS__)) \ -- DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB) \ -+ DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB) \ - DOCTEST_CLANG_SUPPRESS_WARNING_POP - - #define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ -- do { \ -+ [&] { \ - DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__); \ -- } while((void)0, 0) -+ }() - - #else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -+// necessary for <ASSERT>_MESSAGE -+#define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1 -+ - #define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ - doctest::detail::decomp_assert( \ -@@ -2059,102 +2236,113 @@ - #define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__) - - // clang-format off --#define DOCTEST_WARN_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } while((void)0, 0) --#define DOCTEST_CHECK_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } while((void)0, 0) --#define DOCTEST_REQUIRE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } while((void)0, 0) --#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } while((void)0, 0) --#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } while((void)0, 0) --#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } while((void)0, 0) -+#define DOCTEST_WARN_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); }() -+#define DOCTEST_CHECK_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); }() -+#define DOCTEST_REQUIRE_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); }() -+#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); }() -+#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); }() -+#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); }() - // clang-format on - --#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, ...) \ -- do { \ -+#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...) \ -+ [&] { \ - if(!doctest::getContextOptions()->no_throw) { \ -- doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -- __LINE__, #expr, #__VA_ARGS__); \ -+ doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -+ __LINE__, #expr, #__VA_ARGS__, message); \ - try { \ - DOCTEST_CAST_TO_VOID(expr) \ -- } catch(const doctest::detail::remove_const< \ -- doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) { \ -- _DOCTEST_RB.translateException(); \ -- _DOCTEST_RB.m_threw_as = true; \ -- } catch(...) { _DOCTEST_RB.translateException(); } \ -- DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ -+ } catch(const typename doctest::detail::remove_const< \ -+ typename doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) { \ -+ DOCTEST_RB.translateException(); \ -+ DOCTEST_RB.m_threw_as = true; \ -+ } catch(...) { DOCTEST_RB.translateException(); } \ -+ DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ -+ } else { \ -+ return false; \ - } \ -- } while((void)0, 0) -+ }() - --#define DOCTEST_ASSERT_THROWS_WITH(expr, assert_type, ...) \ -- do { \ -+#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...) \ -+ [&] { \ - if(!doctest::getContextOptions()->no_throw) { \ -- doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -- __LINE__, #expr, __VA_ARGS__); \ -+ doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -+ __LINE__, expr_str, "", __VA_ARGS__); \ - try { \ - DOCTEST_CAST_TO_VOID(expr) \ -- } catch(...) { _DOCTEST_RB.translateException(); } \ -- DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ -+ } catch(...) { DOCTEST_RB.translateException(); } \ -+ DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ -+ } else { \ -+ return false; \ - } \ -- } while((void)0, 0) -+ }() - --#define DOCTEST_ASSERT_NOTHROW(expr, assert_type) \ -- do { \ -- doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -- __LINE__, #expr); \ -+#define DOCTEST_ASSERT_NOTHROW(assert_type, ...) \ -+ [&] { \ -+ doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -+ __LINE__, #__VA_ARGS__); \ - try { \ -- DOCTEST_CAST_TO_VOID(expr) \ -- } catch(...) { _DOCTEST_RB.translateException(); } \ -- DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ -- } while((void)0, 0) -+ DOCTEST_CAST_TO_VOID(__VA_ARGS__) \ -+ } catch(...) { DOCTEST_RB.translateException(); } \ -+ DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ -+ }() - - // clang-format off --#define DOCTEST_WARN_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_WARN_THROWS, "") --#define DOCTEST_CHECK_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_CHECK_THROWS, "") --#define DOCTEST_REQUIRE_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_REQUIRE_THROWS, "") -- --#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, __VA_ARGS__) --#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, __VA_ARGS__) --#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, __VA_ARGS__) -- --#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, DT_WARN_THROWS_WITH, __VA_ARGS__) --#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, DT_CHECK_THROWS_WITH, __VA_ARGS__) --#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__) -- --#define DOCTEST_WARN_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_WARN_NOTHROW) --#define DOCTEST_CHECK_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_CHECK_NOTHROW) --#define DOCTEST_REQUIRE_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_REQUIRE_NOTHROW) -- --#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS(expr); } while((void)0, 0) --#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS(expr); } while((void)0, 0) --#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS(expr); } while((void)0, 0) --#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_AS(expr, ex); } while((void)0, 0) --#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_AS(expr, ex); } while((void)0, 0) --#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while((void)0, 0) --#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_WITH(expr, ex); } while((void)0, 0) --#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_WITH(expr, ex); } while((void)0, 0) --#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_WITH(expr, ex); } while((void)0, 0) --#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_NOTHROW(expr); } while((void)0, 0) --#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_NOTHROW(expr); } while((void)0, 0) --#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_NOTHROW(expr); } while((void)0, 0) -+#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "") -+#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "") -+#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "") -+ -+#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__) -+#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__) -+#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__) -+ -+#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__) -+#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__) -+#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__) -+ -+#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__) -+#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__) -+#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__) -+ -+#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__) -+#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__) -+#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__) -+ -+#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS(expr); }() -+#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS(expr); }() -+#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS(expr); }() -+#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_AS(expr, ex); }() -+#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_AS(expr, ex); }() -+#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_AS(expr, ex); }() -+#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH(expr, with); }() -+#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH(expr, with); }() -+#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH(expr, with); }() -+#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); }() -+#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); }() -+#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); }() -+#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_NOTHROW(expr); }() -+#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_NOTHROW(expr); }() -+#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_NOTHROW(expr); }() - // clang-format on - - #ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS - - #define DOCTEST_BINARY_ASSERT(assert_type, comp, ...) \ -- do { \ -- doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -+ [&] { \ -+ doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, #__VA_ARGS__); \ - DOCTEST_WRAP_IN_TRY( \ -- _DOCTEST_RB.binary_assert<doctest::detail::binaryAssertComparison::comp>( \ -+ DOCTEST_RB.binary_assert<doctest::detail::binaryAssertComparison::comp>( \ - __VA_ARGS__)) \ -- DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ -- } while((void)0, 0) -+ DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ -+ }() - - #define DOCTEST_UNARY_ASSERT(assert_type, ...) \ -- do { \ -- doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ -+ [&] { \ -+ doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, #__VA_ARGS__); \ -- DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(__VA_ARGS__)) \ -- DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ -- } while((void)0, 0) -+ DOCTEST_WRAP_IN_TRY(DOCTEST_RB.unary_assert(__VA_ARGS__)) \ -+ DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ -+ }() - - #else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -@@ -2205,6 +2393,9 @@ - #undef DOCTEST_WARN_THROWS_WITH - #undef DOCTEST_CHECK_THROWS_WITH - #undef DOCTEST_REQUIRE_THROWS_WITH -+#undef DOCTEST_WARN_THROWS_WITH_AS -+#undef DOCTEST_CHECK_THROWS_WITH_AS -+#undef DOCTEST_REQUIRE_THROWS_WITH_AS - #undef DOCTEST_WARN_NOTHROW - #undef DOCTEST_CHECK_NOTHROW - #undef DOCTEST_REQUIRE_NOTHROW -@@ -2218,37 +2409,46 @@ - #undef DOCTEST_WARN_THROWS_WITH_MESSAGE - #undef DOCTEST_CHECK_THROWS_WITH_MESSAGE - #undef DOCTEST_REQUIRE_THROWS_WITH_MESSAGE -+#undef DOCTEST_WARN_THROWS_WITH_AS_MESSAGE -+#undef DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE -+#undef DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE - #undef DOCTEST_WARN_NOTHROW_MESSAGE - #undef DOCTEST_CHECK_NOTHROW_MESSAGE - #undef DOCTEST_REQUIRE_NOTHROW_MESSAGE - - #ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - --#define DOCTEST_WARN_THROWS(expr) ((void)0) --#define DOCTEST_CHECK_THROWS(expr) ((void)0) --#define DOCTEST_REQUIRE_THROWS(expr) ((void)0) --#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) --#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) --#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) --#define DOCTEST_WARN_THROWS_WITH(expr, ...) ((void)0) --#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ((void)0) --#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ((void)0) --#define DOCTEST_WARN_NOTHROW(expr) ((void)0) --#define DOCTEST_CHECK_NOTHROW(expr) ((void)0) --#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) -- --#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) -+#define DOCTEST_WARN_THROWS(...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS(...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_AS(expr, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_AS(expr, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_WITH(expr, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ([] { return false; }) -+#define DOCTEST_WARN_NOTHROW(...) ([] { return false; }) -+#define DOCTEST_CHECK_NOTHROW(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_NOTHROW(...) ([] { return false; }) -+ -+#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; }) -+#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) ([] { return false; }) - - #else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -@@ -2290,35 +2490,32 @@ - - // for registering tests - #define DOCTEST_TEST_CASE(name) \ -- DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) -+ DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) - - // for registering tests in classes - #define DOCTEST_TEST_CASE_CLASS(name) \ -- DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) -+ DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) - - // for registering tests with a fixture - #define DOCTEST_TEST_CASE_FIXTURE(x, name) \ -- DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x, \ -- DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) -+ DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), x, \ -+ DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) - - // for converting types to strings without the <typeinfo> header and demangling --#define DOCTEST_TYPE_TO_STRING(...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+#define DOCTEST_TYPE_TO_STRING(...) static_assert(true, "") - #define DOCTEST_TYPE_TO_STRING_IMPL(...) - - // for typed tests - #define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \ - template <typename type> \ -- inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() -+ inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)() - - #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id) \ - template <typename type> \ -- inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() -+ inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)() - --#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ -- typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -- --#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ -- typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) static_assert(true, "") -+#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) static_assert(true, "") - - // for subcases - #define DOCTEST_SUBCASE(name) -@@ -2327,92 +2524,159 @@ - #define DOCTEST_TEST_SUITE(name) namespace - - // for starting a testsuite block --#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+#define DOCTEST_TEST_SUITE_BEGIN(name) static_assert(true, "") - - // for ending a testsuite block --#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -+#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_) - - #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ - template <typename DOCTEST_UNUSED_TEMPLATE_TYPE> \ -- static inline doctest::String DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature) -+ static inline doctest::String DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_)(signature) - - #define DOCTEST_REGISTER_REPORTER(name, priority, reporter) - #define DOCTEST_REGISTER_LISTENER(name, priority, reporter) - --#define DOCTEST_INFO(x) ((void)0) --#define DOCTEST_CAPTURE(x) ((void)0) --#define DOCTEST_ADD_MESSAGE_AT(file, line, x) ((void)0) --#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) ((void)0) --#define DOCTEST_ADD_FAIL_AT(file, line, x) ((void)0) --#define DOCTEST_MESSAGE(x) ((void)0) --#define DOCTEST_FAIL_CHECK(x) ((void)0) --#define DOCTEST_FAIL(x) ((void)0) -- --#define DOCTEST_WARN(...) ((void)0) --#define DOCTEST_CHECK(...) ((void)0) --#define DOCTEST_REQUIRE(...) ((void)0) --#define DOCTEST_WARN_FALSE(...) ((void)0) --#define DOCTEST_CHECK_FALSE(...) ((void)0) --#define DOCTEST_REQUIRE_FALSE(...) ((void)0) -- --#define DOCTEST_WARN_MESSAGE(cond, msg) ((void)0) --#define DOCTEST_CHECK_MESSAGE(cond, msg) ((void)0) --#define DOCTEST_REQUIRE_MESSAGE(cond, msg) ((void)0) --#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) ((void)0) --#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) ((void)0) --#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) ((void)0) -- --#define DOCTEST_WARN_THROWS(expr) ((void)0) --#define DOCTEST_CHECK_THROWS(expr) ((void)0) --#define DOCTEST_REQUIRE_THROWS(expr) ((void)0) --#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) --#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) --#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) --#define DOCTEST_WARN_THROWS_WITH(expr, ...) ((void)0) --#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ((void)0) --#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ((void)0) --#define DOCTEST_WARN_NOTHROW(expr) ((void)0) --#define DOCTEST_CHECK_NOTHROW(expr) ((void)0) --#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) -- --#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, ex, msg) ((void)0) --#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) --#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) -- --#define DOCTEST_WARN_EQ(...) ((void)0) --#define DOCTEST_CHECK_EQ(...) ((void)0) --#define DOCTEST_REQUIRE_EQ(...) ((void)0) --#define DOCTEST_WARN_NE(...) ((void)0) --#define DOCTEST_CHECK_NE(...) ((void)0) --#define DOCTEST_REQUIRE_NE(...) ((void)0) --#define DOCTEST_WARN_GT(...) ((void)0) --#define DOCTEST_CHECK_GT(...) ((void)0) --#define DOCTEST_REQUIRE_GT(...) ((void)0) --#define DOCTEST_WARN_LT(...) ((void)0) --#define DOCTEST_CHECK_LT(...) ((void)0) --#define DOCTEST_REQUIRE_LT(...) ((void)0) --#define DOCTEST_WARN_GE(...) ((void)0) --#define DOCTEST_CHECK_GE(...) ((void)0) --#define DOCTEST_REQUIRE_GE(...) ((void)0) --#define DOCTEST_WARN_LE(...) ((void)0) --#define DOCTEST_CHECK_LE(...) ((void)0) --#define DOCTEST_REQUIRE_LE(...) ((void)0) -- --#define DOCTEST_WARN_UNARY(...) ((void)0) --#define DOCTEST_CHECK_UNARY(...) ((void)0) --#define DOCTEST_REQUIRE_UNARY(...) ((void)0) --#define DOCTEST_WARN_UNARY_FALSE(...) ((void)0) --#define DOCTEST_CHECK_UNARY_FALSE(...) ((void)0) --#define DOCTEST_REQUIRE_UNARY_FALSE(...) ((void)0) -+#define DOCTEST_INFO(...) (static_cast<void>(0)) -+#define DOCTEST_CAPTURE(x) (static_cast<void>(0)) -+#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) (static_cast<void>(0)) -+#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) (static_cast<void>(0)) -+#define DOCTEST_ADD_FAIL_AT(file, line, ...) (static_cast<void>(0)) -+#define DOCTEST_MESSAGE(...) (static_cast<void>(0)) -+#define DOCTEST_FAIL_CHECK(...) (static_cast<void>(0)) -+#define DOCTEST_FAIL(...) (static_cast<void>(0)) -+ -+#ifdef DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED -+ -+#define DOCTEST_WARN(...) [&] { return __VA_ARGS__; }() -+#define DOCTEST_CHECK(...) [&] { return __VA_ARGS__; }() -+#define DOCTEST_REQUIRE(...) [&] { return __VA_ARGS__; }() -+#define DOCTEST_WARN_FALSE(...) [&] { return !(__VA_ARGS__); }() -+#define DOCTEST_CHECK_FALSE(...) [&] { return !(__VA_ARGS__); }() -+#define DOCTEST_REQUIRE_FALSE(...) [&] { return !(__VA_ARGS__); }() -+ -+#define DOCTEST_WARN_MESSAGE(cond, ...) [&] { return cond; }() -+#define DOCTEST_CHECK_MESSAGE(cond, ...) [&] { return cond; }() -+#define DOCTEST_REQUIRE_MESSAGE(cond, ...) [&] { return cond; }() -+#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() -+#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() -+#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() -+ -+namespace doctest { -+namespace detail { -+#define DOCTEST_RELATIONAL_OP(name, op) \ -+ template <typename L, typename R> \ -+ bool name(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs op rhs; } -+ -+ DOCTEST_RELATIONAL_OP(eq, ==) -+ DOCTEST_RELATIONAL_OP(ne, !=) -+ DOCTEST_RELATIONAL_OP(lt, <) -+ DOCTEST_RELATIONAL_OP(gt, >) -+ DOCTEST_RELATIONAL_OP(le, <=) -+ DOCTEST_RELATIONAL_OP(ge, >=) -+} // namespace detail -+} // namespace doctest -+ -+#define DOCTEST_WARN_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() -+#define DOCTEST_CHECK_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() -+#define DOCTEST_REQUIRE_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() -+#define DOCTEST_WARN_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() -+#define DOCTEST_CHECK_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() -+#define DOCTEST_REQUIRE_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() -+#define DOCTEST_WARN_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() -+#define DOCTEST_CHECK_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() -+#define DOCTEST_REQUIRE_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() -+#define DOCTEST_WARN_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() -+#define DOCTEST_CHECK_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() -+#define DOCTEST_REQUIRE_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() -+#define DOCTEST_WARN_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() -+#define DOCTEST_CHECK_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() -+#define DOCTEST_REQUIRE_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() -+#define DOCTEST_WARN_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() -+#define DOCTEST_CHECK_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() -+#define DOCTEST_REQUIRE_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() -+#define DOCTEST_WARN_UNARY(...) [&] { return __VA_ARGS__; }() -+#define DOCTEST_CHECK_UNARY(...) [&] { return __VA_ARGS__; }() -+#define DOCTEST_REQUIRE_UNARY(...) [&] { return __VA_ARGS__; }() -+#define DOCTEST_WARN_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() -+#define DOCTEST_CHECK_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() -+#define DOCTEST_REQUIRE_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() -+ -+#else // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED -+ -+#define DOCTEST_WARN(...) ([] { return false; }) -+#define DOCTEST_CHECK(...) ([] { return false; }) -+#define DOCTEST_REQUIRE(...) ([] { return false; }) -+#define DOCTEST_WARN_FALSE(...) ([] { return false; }) -+#define DOCTEST_CHECK_FALSE(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_FALSE(...) ([] { return false; }) -+ -+#define DOCTEST_WARN_MESSAGE(cond, ...) ([] { return false; }) -+#define DOCTEST_CHECK_MESSAGE(cond, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_MESSAGE(cond, ...) ([] { return false; }) -+#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) ([] { return false; }) -+#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) ([] { return false; }) -+ -+#define DOCTEST_WARN_EQ(...) ([] { return false; }) -+#define DOCTEST_CHECK_EQ(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_EQ(...) ([] { return false; }) -+#define DOCTEST_WARN_NE(...) ([] { return false; }) -+#define DOCTEST_CHECK_NE(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_NE(...) ([] { return false; }) -+#define DOCTEST_WARN_GT(...) ([] { return false; }) -+#define DOCTEST_CHECK_GT(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_GT(...) ([] { return false; }) -+#define DOCTEST_WARN_LT(...) ([] { return false; }) -+#define DOCTEST_CHECK_LT(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_LT(...) ([] { return false; }) -+#define DOCTEST_WARN_GE(...) ([] { return false; }) -+#define DOCTEST_CHECK_GE(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_GE(...) ([] { return false; }) -+#define DOCTEST_WARN_LE(...) ([] { return false; }) -+#define DOCTEST_CHECK_LE(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_LE(...) ([] { return false; }) -+ -+#define DOCTEST_WARN_UNARY(...) ([] { return false; }) -+#define DOCTEST_CHECK_UNARY(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_UNARY(...) ([] { return false; }) -+#define DOCTEST_WARN_UNARY_FALSE(...) ([] { return false; }) -+#define DOCTEST_CHECK_UNARY_FALSE(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_UNARY_FALSE(...) ([] { return false; }) -+ -+#endif // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED -+ -+// TODO: think about if these also need to work properly even when doctest is disabled -+#define DOCTEST_WARN_THROWS(...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS(...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_AS(expr, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_AS(expr, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_WITH(expr, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ([] { return false; }) -+#define DOCTEST_WARN_NOTHROW(...) ([] { return false; }) -+#define DOCTEST_CHECK_NOTHROW(...) ([] { return false; }) -+#define DOCTEST_REQUIRE_NOTHROW(...) ([] { return false; }) -+ -+#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; }) -+#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; }) -+#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; }) -+#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) ([] { return false; }) -+#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) ([] { return false; }) - - #endif // DOCTEST_CONFIG_DISABLE - -@@ -2444,7 +2708,7 @@ - #define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE - #define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE - --#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INVOKE -+#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__) - // clang-format on - - // BDD style macros -@@ -2464,132 +2728,138 @@ - // == SHORT VERSIONS OF THE MACROS - #if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) - --#define TEST_CASE DOCTEST_TEST_CASE --#define TEST_CASE_CLASS DOCTEST_TEST_CASE_CLASS --#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE --#define TYPE_TO_STRING DOCTEST_TYPE_TO_STRING --#define TEST_CASE_TEMPLATE DOCTEST_TEST_CASE_TEMPLATE --#define TEST_CASE_TEMPLATE_DEFINE DOCTEST_TEST_CASE_TEMPLATE_DEFINE --#define TEST_CASE_TEMPLATE_INVOKE DOCTEST_TEST_CASE_TEMPLATE_INVOKE --#define TEST_CASE_TEMPLATE_APPLY DOCTEST_TEST_CASE_TEMPLATE_APPLY --#define SUBCASE DOCTEST_SUBCASE --#define TEST_SUITE DOCTEST_TEST_SUITE --#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN -+#define TEST_CASE(name) DOCTEST_TEST_CASE(name) -+#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name) -+#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name) -+#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__) -+#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__) -+#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id) -+#define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__) -+#define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__) -+#define SUBCASE(name) DOCTEST_SUBCASE(name) -+#define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators) -+#define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name) - #define TEST_SUITE_END DOCTEST_TEST_SUITE_END --#define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR --#define REGISTER_REPORTER DOCTEST_REGISTER_REPORTER --#define REGISTER_LISTENER DOCTEST_REGISTER_LISTENER --#define INFO DOCTEST_INFO --#define CAPTURE DOCTEST_CAPTURE --#define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT --#define ADD_FAIL_CHECK_AT DOCTEST_ADD_FAIL_CHECK_AT --#define ADD_FAIL_AT DOCTEST_ADD_FAIL_AT --#define MESSAGE DOCTEST_MESSAGE --#define FAIL_CHECK DOCTEST_FAIL_CHECK --#define FAIL DOCTEST_FAIL --#define TO_LVALUE DOCTEST_TO_LVALUE -- --#define WARN DOCTEST_WARN --#define WARN_FALSE DOCTEST_WARN_FALSE --#define WARN_THROWS DOCTEST_WARN_THROWS --#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS --#define WARN_THROWS_WITH DOCTEST_WARN_THROWS_WITH --#define WARN_NOTHROW DOCTEST_WARN_NOTHROW --#define CHECK DOCTEST_CHECK --#define CHECK_FALSE DOCTEST_CHECK_FALSE --#define CHECK_THROWS DOCTEST_CHECK_THROWS --#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS --#define CHECK_THROWS_WITH DOCTEST_CHECK_THROWS_WITH --#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW --#define REQUIRE DOCTEST_REQUIRE --#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE --#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS --#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS --#define REQUIRE_THROWS_WITH DOCTEST_REQUIRE_THROWS_WITH --#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW -- --#define WARN_MESSAGE DOCTEST_WARN_MESSAGE --#define WARN_FALSE_MESSAGE DOCTEST_WARN_FALSE_MESSAGE --#define WARN_THROWS_MESSAGE DOCTEST_WARN_THROWS_MESSAGE --#define WARN_THROWS_AS_MESSAGE DOCTEST_WARN_THROWS_AS_MESSAGE --#define WARN_THROWS_WITH_MESSAGE DOCTEST_WARN_THROWS_WITH_MESSAGE --#define WARN_NOTHROW_MESSAGE DOCTEST_WARN_NOTHROW_MESSAGE --#define CHECK_MESSAGE DOCTEST_CHECK_MESSAGE --#define CHECK_FALSE_MESSAGE DOCTEST_CHECK_FALSE_MESSAGE --#define CHECK_THROWS_MESSAGE DOCTEST_CHECK_THROWS_MESSAGE --#define CHECK_THROWS_AS_MESSAGE DOCTEST_CHECK_THROWS_AS_MESSAGE --#define CHECK_THROWS_WITH_MESSAGE DOCTEST_CHECK_THROWS_WITH_MESSAGE --#define CHECK_NOTHROW_MESSAGE DOCTEST_CHECK_NOTHROW_MESSAGE --#define REQUIRE_MESSAGE DOCTEST_REQUIRE_MESSAGE --#define REQUIRE_FALSE_MESSAGE DOCTEST_REQUIRE_FALSE_MESSAGE --#define REQUIRE_THROWS_MESSAGE DOCTEST_REQUIRE_THROWS_MESSAGE --#define REQUIRE_THROWS_AS_MESSAGE DOCTEST_REQUIRE_THROWS_AS_MESSAGE --#define REQUIRE_THROWS_WITH_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_MESSAGE --#define REQUIRE_NOTHROW_MESSAGE DOCTEST_REQUIRE_NOTHROW_MESSAGE -- --#define SCENARIO DOCTEST_SCENARIO --#define SCENARIO_CLASS DOCTEST_SCENARIO_CLASS --#define SCENARIO_TEMPLATE DOCTEST_SCENARIO_TEMPLATE --#define SCENARIO_TEMPLATE_DEFINE DOCTEST_SCENARIO_TEMPLATE_DEFINE --#define GIVEN DOCTEST_GIVEN --#define WHEN DOCTEST_WHEN --#define AND_WHEN DOCTEST_AND_WHEN --#define THEN DOCTEST_THEN --#define AND_THEN DOCTEST_AND_THEN -- --#define WARN_EQ DOCTEST_WARN_EQ --#define CHECK_EQ DOCTEST_CHECK_EQ --#define REQUIRE_EQ DOCTEST_REQUIRE_EQ --#define WARN_NE DOCTEST_WARN_NE --#define CHECK_NE DOCTEST_CHECK_NE --#define REQUIRE_NE DOCTEST_REQUIRE_NE --#define WARN_GT DOCTEST_WARN_GT --#define CHECK_GT DOCTEST_CHECK_GT --#define REQUIRE_GT DOCTEST_REQUIRE_GT --#define WARN_LT DOCTEST_WARN_LT --#define CHECK_LT DOCTEST_CHECK_LT --#define REQUIRE_LT DOCTEST_REQUIRE_LT --#define WARN_GE DOCTEST_WARN_GE --#define CHECK_GE DOCTEST_CHECK_GE --#define REQUIRE_GE DOCTEST_REQUIRE_GE --#define WARN_LE DOCTEST_WARN_LE --#define CHECK_LE DOCTEST_CHECK_LE --#define REQUIRE_LE DOCTEST_REQUIRE_LE --#define WARN_UNARY DOCTEST_WARN_UNARY --#define CHECK_UNARY DOCTEST_CHECK_UNARY --#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY --#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE --#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE --#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE -+#define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) -+#define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter) -+#define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter) -+#define INFO(...) DOCTEST_INFO(__VA_ARGS__) -+#define CAPTURE(x) DOCTEST_CAPTURE(x) -+#define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__) -+#define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__) -+#define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__) -+#define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__) -+#define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__) -+#define FAIL(...) DOCTEST_FAIL(__VA_ARGS__) -+#define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__) -+ -+#define WARN(...) DOCTEST_WARN(__VA_ARGS__) -+#define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__) -+#define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__) -+#define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__) -+#define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__) -+#define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__) -+#define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__) -+#define CHECK(...) DOCTEST_CHECK(__VA_ARGS__) -+#define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__) -+#define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__) -+#define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__) -+#define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__) -+#define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__) -+#define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__) -+#define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__) -+#define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__) -+#define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__) -+#define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__) -+#define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__) -+#define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__) -+#define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__) -+ -+#define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__) -+#define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__) -+#define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__) -+#define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) -+#define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) -+#define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) -+#define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__) -+#define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__) -+#define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__) -+#define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__) -+#define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) -+#define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) -+#define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) -+#define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__) -+#define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__) -+#define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__) -+#define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__) -+#define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) -+#define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) -+#define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) -+#define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__) -+ -+#define SCENARIO(name) DOCTEST_SCENARIO(name) -+#define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name) -+#define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__) -+#define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) -+#define GIVEN(name) DOCTEST_GIVEN(name) -+#define WHEN(name) DOCTEST_WHEN(name) -+#define AND_WHEN(name) DOCTEST_AND_WHEN(name) -+#define THEN(name) DOCTEST_THEN(name) -+#define AND_THEN(name) DOCTEST_AND_THEN(name) -+ -+#define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__) -+#define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__) -+#define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__) -+#define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__) -+#define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__) -+#define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__) -+#define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__) -+#define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__) -+#define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__) -+#define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__) -+#define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__) -+#define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__) -+#define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__) -+#define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__) -+#define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__) -+#define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__) -+#define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__) -+#define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__) -+#define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__) -+#define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__) -+#define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__) -+#define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__) -+#define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__) -+#define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__) - - // KEPT FOR BACKWARDS COMPATIBILITY --#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ --#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ --#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ --#define FAST_WARN_NE DOCTEST_FAST_WARN_NE --#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE --#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE --#define FAST_WARN_GT DOCTEST_FAST_WARN_GT --#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT --#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT --#define FAST_WARN_LT DOCTEST_FAST_WARN_LT --#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT --#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT --#define FAST_WARN_GE DOCTEST_FAST_WARN_GE --#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE --#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE --#define FAST_WARN_LE DOCTEST_FAST_WARN_LE --#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE --#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE -- --#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY --#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY --#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY --#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE --#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE --#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE -+#define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__) -+#define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__) -+#define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__) -+#define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__) -+#define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__) -+#define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__) -+#define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__) -+#define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__) -+#define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__) -+#define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__) -+#define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__) -+#define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__) -+#define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__) -+#define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__) -+#define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__) -+#define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__) -+#define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__) -+#define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__) -+ -+#define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__) -+#define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__) -+#define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__) -+#define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__) -+#define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__) -+#define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__) - --#define TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE -+#define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__) - - #endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES - -@@ -2626,6 +2896,8 @@ - DOCTEST_MSVC_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - -+DOCTEST_SUPPRESS_COMMON_WARNINGS_POP -+ - #endif // DOCTEST_LIBRARY_INCLUDED - - #ifndef DOCTEST_SINGLE_HEADER -@@ -2645,13 +2917,11 @@ - - DOCTEST_CLANG_SUPPRESS_WARNING_POP - -+DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH -+ - DOCTEST_CLANG_SUPPRESS_WARNING_PUSH --DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations") -@@ -2659,64 +2929,35 @@ - DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") --DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function") -+DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path") - - DOCTEST_GCC_SUPPRESS_WARNING_PUSH --DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") --DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") - DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") --DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") - DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") --DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") --DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") - DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers") - DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces") --DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") --DOCTEST_GCC_SUPPRESS_WARNING("-Winline") - DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch") - DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") - DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default") - DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations") - DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") --DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") --DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") - DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function") - DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance") --DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") - DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute") - - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH --DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning --DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning --DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration - DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data --DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression --DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated --DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant - DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled - DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified - DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal - DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch --DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding in structs --DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe - DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C --DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation stuff --DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted --DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted --DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted --DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted - DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning) --// static analysis --DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept' --DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable --DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ... --DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtor... -+DOCTEST_MSVC_SUPPRESS_WARNING(5245) // unreferenced function with internal linkage has been removed - - DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN - -@@ -2724,7 +2965,7 @@ - #include <ctime> - #include <cmath> - #include <climits> --// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37 -+// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/doctest/doctest/pull/37 - #ifdef __BORLANDC__ - #include <math.h> - #endif // __BORLANDC__ -@@ -2746,9 +2987,7 @@ - #include <map> - #include <exception> - #include <stdexcept> --#ifdef DOCTEST_CONFIG_POSIX_SIGNALS - #include <csignal> --#endif // DOCTEST_CONFIG_POSIX_SIGNALS - #include <cfloat> - #include <cctype> - #include <cstdint> -@@ -2773,7 +3012,7 @@ - #ifdef __AFXDLL - #include <AfxWin.h> - #else --#include <Windows.h> -+#include <windows.h> - #endif - #include <io.h> - -@@ -2784,6 +3023,12 @@ - - #endif // DOCTEST_PLATFORM_WINDOWS - -+// this is a fix for https://github.com/doctest/doctest/issues/348 -+// https://mail.gnome.org/archives/xml/2012-January/msg00000.html -+#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO) -+#define STDOUT_FILENO fileno(stdout) -+#endif // HAVE_UNISTD_H -+ - DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END - - // counts the number of elements in a C array -@@ -2800,7 +3045,19 @@ - #endif - - #ifndef DOCTEST_THREAD_LOCAL -+#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) -+#define DOCTEST_THREAD_LOCAL -+#else // DOCTEST_MSVC - #define DOCTEST_THREAD_LOCAL thread_local -+#endif // DOCTEST_MSVC -+#endif // DOCTEST_THREAD_LOCAL -+ -+#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES -+#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32 -+#endif -+ -+#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE -+#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64 - #endif - - #ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS -@@ -2809,12 +3066,38 @@ - #define DOCTEST_OPTIONS_PREFIX_DISPLAY "" - #endif - -+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -+#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS -+#endif -+ -+#ifndef DOCTEST_CDECL -+#define DOCTEST_CDECL __cdecl -+#endif -+ - namespace doctest { - - bool is_running_in_test = false; - - namespace { - using namespace detail; -+ -+ template <typename Ex> -+ DOCTEST_NORETURN void throw_exception(Ex const& e) { -+#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -+ throw e; -+#else // DOCTEST_CONFIG_NO_EXCEPTIONS -+ std::cerr << "doctest will terminate because it needed to throw an exception.\n" -+ << "The message was: " << e.what() << '\n'; -+ std::terminate(); -+#endif // DOCTEST_CONFIG_NO_EXCEPTIONS -+ } -+ -+#ifndef DOCTEST_INTERNAL_ERROR -+#define DOCTEST_INTERNAL_ERROR(msg) \ -+ throw_exception(std::logic_error( \ -+ __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) -+#endif // DOCTEST_INTERNAL_ERROR -+ - // case insensitive strcmp - int stricmp(const char* a, const char* b) { - for(;; a++, b++) { -@@ -2858,8 +3141,6 @@ - } // namespace - - namespace detail { -- void my_memcpy(void* dest, const void* src, unsigned num) { memcpy(dest, src, num); } -- - String rawMemoryToString(const void* object, unsigned size) { - // Reverse order for little endian architectures - int i = 0, end = static_cast<int>(size), inc = 1; -@@ -2869,49 +3150,76 @@ - } - - unsigned const char* bytes = static_cast<unsigned const char*>(object); -- std::ostringstream oss; -- oss << "0x" << std::setfill('0') << std::hex; -+ std::ostream* oss = tlssPush(); -+ *oss << "0x" << std::setfill('0') << std::hex; - for(; i != end; i += inc) -- oss << std::setw(2) << static_cast<unsigned>(bytes[i]); -- return oss.str().c_str(); -+ *oss << std::setw(2) << static_cast<unsigned>(bytes[i]); -+ return tlssPop(); - } - -- DOCTEST_THREAD_LOCAL std::ostringstream g_oss; // NOLINT(cert-err58-cpp) -+ DOCTEST_THREAD_LOCAL class -+ { -+ std::vector<std::streampos> stack; -+ std::stringstream ss; -+ -+ public: -+ std::ostream* push() { -+ stack.push_back(ss.tellp()); -+ return &ss; -+ } -+ -+ String pop() { -+ if (stack.empty()) -+ DOCTEST_INTERNAL_ERROR("TLSS was empty when trying to pop!"); -+ -+ std::streampos pos = stack.back(); -+ stack.pop_back(); -+ unsigned sz = static_cast<unsigned>(ss.tellp() - pos); -+ ss.rdbuf()->pubseekpos(pos, std::ios::in | std::ios::out); -+ return String(ss, sz); -+ } -+ } g_oss; - -- std::ostream* getTlsOss() { -- g_oss.clear(); // there shouldn't be anything worth clearing in the flags -- g_oss.str(""); // the slow way of resetting a string stream -- //g_oss.seekp(0); // optimal reset - as seen here: https://stackoverflow.com/a/624291/3162383 -- return &g_oss; -+ std::ostream* tlssPush() { -+ return g_oss.push(); - } - -- String getTlsOssResult() { -- //g_oss << std::ends; // needed - as shown here: https://stackoverflow.com/a/624291/3162383 -- return g_oss.str().c_str(); -+ String tlssPop() { -+ return g_oss.pop(); - } - - #ifndef DOCTEST_CONFIG_DISABLE - -- typedef uint64_t UInt64; -+namespace timer_large_integer -+{ -+ -+#if defined(DOCTEST_PLATFORM_WINDOWS) -+ typedef ULONGLONG type; -+#else // DOCTEST_PLATFORM_WINDOWS -+ typedef std::uint64_t type; -+#endif // DOCTEST_PLATFORM_WINDOWS -+} -+ -+typedef timer_large_integer::type ticks_t; - - #ifdef DOCTEST_CONFIG_GETCURRENTTICKS -- UInt64 getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); } -+ ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); } - #elif defined(DOCTEST_PLATFORM_WINDOWS) -- UInt64 getCurrentTicks() { -- static UInt64 hz = 0, hzo = 0; -- if(!hz) { -- QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&hz)); -- QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&hzo)); -- } -- UInt64 t; -- QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&t)); -- return ((t - hzo) * 1000000) / hz; -+ ticks_t getCurrentTicks() { -+ static LARGE_INTEGER hz = {0}, hzo = {0}; -+ if(!hz.QuadPart) { -+ QueryPerformanceFrequency(&hz); -+ QueryPerformanceCounter(&hzo); -+ } -+ LARGE_INTEGER t; -+ QueryPerformanceCounter(&t); -+ return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart; - } - #else // DOCTEST_PLATFORM_WINDOWS -- UInt64 getCurrentTicks() { -+ ticks_t getCurrentTicks() { - timeval t; - gettimeofday(&t, nullptr); -- return static_cast<UInt64>(t.tv_sec) * 1000000 + static_cast<UInt64>(t.tv_usec); -+ return static_cast<ticks_t>(t.tv_sec) * 1000000 + static_cast<ticks_t>(t.tv_usec); - } - #endif // DOCTEST_PLATFORM_WINDOWS - -@@ -2924,24 +3232,111 @@ - //unsigned int getElapsedMilliseconds() const { - // return static_cast<unsigned int>(getElapsedMicroseconds() / 1000); - //} -- double getElapsedSeconds() const { return getElapsedMicroseconds() / 1000000.0; } -+ double getElapsedSeconds() const { return static_cast<double>(getCurrentTicks() - m_ticks) / 1000000.0; } -+ -+ private: -+ ticks_t m_ticks = 0; -+ }; -+ -+#ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS -+ template <typename T> -+ using AtomicOrMultiLaneAtomic = std::atomic<T>; -+#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS -+ // Provides a multilane implementation of an atomic variable that supports add, sub, load, -+ // store. Instead of using a single atomic variable, this splits up into multiple ones, -+ // each sitting on a separate cache line. The goal is to provide a speedup when most -+ // operations are modifying. It achieves this with two properties: -+ // -+ // * Multiple atomics are used, so chance of congestion from the same atomic is reduced. -+ // * Each atomic sits on a separate cache line, so false sharing is reduced. -+ // -+ // The disadvantage is that there is a small overhead due to the use of TLS, and load/store -+ // is slower because all atomics have to be accessed. -+ template <typename T> -+ class MultiLaneAtomic -+ { -+ struct CacheLineAlignedAtomic -+ { -+ std::atomic<T> atomic{}; -+ char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)]; -+ }; -+ CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES]; -+ -+ static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE, -+ "guarantee one atomic takes exactly one cache line"); -+ -+ public: -+ T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; } -+ -+ T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); } -+ -+ T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { -+ return myAtomic().fetch_add(arg, order); -+ } -+ -+ T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { -+ return myAtomic().fetch_sub(arg, order); -+ } -+ -+ operator T() const DOCTEST_NOEXCEPT { return load(); } -+ -+ T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT { -+ auto result = T(); -+ for(auto const& c : m_atomics) { -+ result += c.atomic.load(order); -+ } -+ return result; -+ } -+ -+ T operator=(T desired) DOCTEST_NOEXCEPT { // lgtm [cpp/assignment-does-not-return-this] -+ store(desired); -+ return desired; -+ } -+ -+ void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { -+ // first value becomes desired", all others become 0. -+ for(auto& c : m_atomics) { -+ c.atomic.store(desired, order); -+ desired = {}; -+ } -+ } - - private: -- UInt64 m_ticks = 0; -+ // Each thread has a different atomic that it operates on. If more than NumLanes threads -+ // use this, some will use the same atomic. So performance will degrade a bit, but still -+ // everything will work. -+ // -+ // The logic here is a bit tricky. The call should be as fast as possible, so that there -+ // is minimal to no overhead in determining the correct atomic for the current thread. -+ // -+ // 1. A global static counter laneCounter counts continuously up. -+ // 2. Each successive thread will use modulo operation of that counter so it gets an atomic -+ // assigned in a round-robin fashion. -+ // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with -+ // little overhead. -+ std::atomic<T>& myAtomic() DOCTEST_NOEXCEPT { -+ static std::atomic<size_t> laneCounter; -+ DOCTEST_THREAD_LOCAL size_t tlsLaneIdx = -+ laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES; -+ -+ return m_atomics[tlsLaneIdx].atomic; -+ } - }; - -+ template <typename T> -+ using AtomicOrMultiLaneAtomic = MultiLaneAtomic<T>; -+#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS -+ - // this holds both parameters from the command line and runtime data for tests - struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats - { -- std::atomic<int> numAssertsCurrentTest_atomic; -- std::atomic<int> numAssertsFailedCurrentTest_atomic; -+ AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic; -+ AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic; - - std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters - - std::vector<IReporter*> reporters_currently_used; - -- const TestCase* currentTest = nullptr; -- - assert_handler ah = nullptr; - - Timer timer; -@@ -2949,10 +3344,11 @@ - std::vector<String> stringifiedContexts; // logging from INFO() due to an exception - - // stuff for subcases -- std::set<SubcaseSignature> subcasesPassed; -- std::set<int> subcasesEnteredLevels; -- int subcasesCurrentLevel; -- bool should_reenter; -+ std::vector<SubcaseSignature> subcasesStack; -+ std::set<decltype(subcasesStack)> subcasesPassed; -+ int subcasesCurrentMaxLevel; -+ bool should_reenter; -+ std::atomic<bool> shouldLogCurrentException; - - void resetRunData() { - numTestCases = 0; -@@ -3002,7 +3398,8 @@ - (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags); - - // if any subcase has failed - the whole test case has failed -- if(failure_flags && !ok_to_fail) -+ testCaseSuccess = !(failure_flags && !ok_to_fail); -+ if(!testCaseSuccess) - numTestCasesFailed++; - } - }; -@@ -3017,6 +3414,21 @@ - #endif // DOCTEST_CONFIG_DISABLE - } // namespace detail - -+char* String::allocate(unsigned sz) { -+ if (sz <= last) { -+ buf[sz] = '\0'; -+ setLast(last - sz); -+ return buf; -+ } else { -+ setOnHeap(); -+ data.size = sz; -+ data.capacity = data.size + 1; -+ data.ptr = new char[data.capacity]; -+ data.ptr[sz] = '\0'; -+ return data.ptr; -+ } -+} -+ - void String::setOnHeap() { *reinterpret_cast<unsigned char*>(&buf[last]) = 128; } - void String::setLast(unsigned in) { buf[last] = char(in); } - -@@ -3024,11 +3436,7 @@ - if(other.isOnStack()) { - memcpy(buf, other.buf, len); - } else { -- setOnHeap(); -- data.size = other.data.size; -- data.capacity = data.size + 1; -- data.ptr = new char[data.capacity]; -- memcpy(data.ptr, other.data.ptr, data.size + 1); -+ memcpy(allocate(other.data.size), other.data.ptr, other.data.size); - } - } - -@@ -3040,22 +3448,18 @@ - String::~String() { - if(!isOnStack()) - delete[] data.ptr; -+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - } - - String::String(const char* in) - : String(in, strlen(in)) {} - - String::String(const char* in, unsigned in_size) { -- if(in_size <= last) { -- memcpy(buf, in, in_size + 1); -- setLast(last - in_size); -- } else { -- setOnHeap(); -- data.size = in_size; -- data.capacity = data.size + 1; -- data.ptr = new char[data.capacity]; -- memcpy(data.ptr, in, in_size + 1); -- } -+ memcpy(allocate(in_size), in, in_size); -+} -+ -+String::String(std::istream& in, unsigned in_size) { -+ in.read(allocate(in_size), in_size); - } - - String::String(const String& other) { copy(other); } -@@ -3079,6 +3483,7 @@ - if(total_size < len) { - // append to the current stack space - memcpy(buf + my_old_size, other.c_str(), other_size + 1); -+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - setLast(last - total_size); - } else { - // alloc new chunk -@@ -3120,8 +3525,6 @@ - return *this; - } - --String String::operator+(const String& other) const { return String(*this) += other; } -- - String::String(String&& other) { - memcpy(buf, other.buf, len); - other.buf[0] = '\0'; -@@ -3165,7 +3568,7 @@ - - int String::compare(const char* other, bool no_case) const { - if(no_case) -- return stricmp(c_str(), other); -+ return doctest::stricmp(c_str(), other); - return std::strcmp(c_str(), other); - } - -@@ -3173,6 +3576,9 @@ - return compare(other.c_str(), no_case); - } - -+// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) -+String operator+(const String& lhs, const String& rhs) { return String(lhs) += rhs; } -+ - // clang-format off - bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } - bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } -@@ -3219,6 +3625,10 @@ - case assertType::DT_CHECK_THROWS_WITH : return "CHECK_THROWS_WITH"; - case assertType::DT_REQUIRE_THROWS_WITH : return "REQUIRE_THROWS_WITH"; - -+ case assertType::DT_WARN_THROWS_WITH_AS : return "WARN_THROWS_WITH_AS"; -+ case assertType::DT_CHECK_THROWS_WITH_AS : return "CHECK_THROWS_WITH_AS"; -+ case assertType::DT_REQUIRE_THROWS_WITH_AS : return "REQUIRE_THROWS_WITH_AS"; -+ - case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW"; - case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW"; - case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW"; -@@ -3268,6 +3678,7 @@ - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") - // depending on the current options this will remove the path of filenames - const char* skipPathFromFilename(const char* file) { -+#ifndef DOCTEST_CONFIG_DISABLE - if(getContextOptions()->no_path_in_filenames) { - auto back = std::strrchr(file, '\\'); - auto forward = std::strrchr(file, '/'); -@@ -3277,41 +3688,26 @@ - return forward + 1; - } - } -+#endif // DOCTEST_CONFIG_DISABLE - return file; - } - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - --DOCTEST_DEFINE_DEFAULTS(TestCaseData); --DOCTEST_DEFINE_COPIES(TestCaseData); -- --DOCTEST_DEFINE_DEFAULTS(AssertData); -- --DOCTEST_DEFINE_DEFAULTS(MessageData); -- --SubcaseSignature::SubcaseSignature(const char* name, const char* file, int line) -- : m_name(name) -- , m_file(file) -- , m_line(line) {} -- --DOCTEST_DEFINE_DEFAULTS(SubcaseSignature); --DOCTEST_DEFINE_COPIES(SubcaseSignature); -- - bool SubcaseSignature::operator<(const SubcaseSignature& other) const { - if(m_line != other.m_line) - return m_line < other.m_line; - if(std::strcmp(m_file, other.m_file) != 0) - return std::strcmp(m_file, other.m_file) < 0; -- return std::strcmp(m_name, other.m_name) < 0; -+ return m_name.compare(other.m_name) < 0; - } - - IContextScope::IContextScope() = default; - IContextScope::~IContextScope() = default; - --DOCTEST_DEFINE_DEFAULTS(ContextOptions); -- - #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - String toString(char* in) { return toString(static_cast<const char*>(in)); } -+// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } - #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - String toString(bool in) { return in ? "true" : "false"; } -@@ -3341,7 +3737,7 @@ - String toString(std::nullptr_t) { return "NULL"; } - - #if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) --// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 -+// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 - String toString(const std::string& in) { return in.c_str(); } - #endif // VS 2019 - -@@ -3350,8 +3746,6 @@ - , m_scale(1.0) - , m_value(value) {} - --DOCTEST_DEFINE_COPIES(Approx); -- - Approx Approx::operator()(double value) const { - Approx approx(value); - approx.epsilon(m_epsilon); -@@ -3386,7 +3780,8 @@ - bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; } - - String toString(const Approx& in) { -- return String("Approx( ") + doctest::toString(in.m_value) + " )"; -+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) -+ return "Approx( " + doctest::toString(in.m_value) + " )"; - } - const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); } - -@@ -3399,17 +3794,15 @@ - void Context::applyCommandLine(int, const char* const*) {} - void Context::addFilter(const char*, const char*) {} - void Context::clearFilters() {} -+void Context::setOption(const char*, bool) {} - void Context::setOption(const char*, int) {} - void Context::setOption(const char*, const char*) {} - bool Context::shouldExit() { return false; } - void Context::setAsDefaultForAssertsOutOfTestCases() {} - void Context::setAssertHandler(detail::assert_handler) {} -+void Context::setCout(std::ostream* out) {} - int Context::run() { return 0; } - --DOCTEST_DEFINE_DEFAULTS(CurrentTestCaseStats); -- --DOCTEST_DEFINE_DEFAULTS(TestRunStats); -- - IReporter::~IReporter() = default; - - int IReporter::get_num_active_contexts() { return 0; } -@@ -3435,7 +3828,7 @@ - namespace doctest_detail_test_suite_ns { - // holds the current test suite - doctest::detail::TestSuite& getCurrentTestSuite() { -- static doctest::detail::TestSuite data; -+ static doctest::detail::TestSuite data{}; - return data; - } - } // namespace doctest_detail_test_suite_ns -@@ -3460,8 +3853,6 @@ - for(auto& curr_rep : g_cs->reporters_currently_used) \ - curr_rep->function(__VA_ARGS__) - -- DOCTEST_DEFINE_DEFAULTS(TestFailureException); -- DOCTEST_DEFINE_COPIES(TestFailureException); - bool checkIfShouldThrow(assertType::Enum at) { - if(at & assertType::is_require) //!OCLINT bitwise operator in conditional - return true; -@@ -3476,7 +3867,10 @@ - } - - #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -- [[noreturn]] void throwException() { throw TestFailureException(); } // NOLINT(cert-err60-cpp) -+ DOCTEST_NORETURN void throwException() { -+ g_cs->shouldLogCurrentException = false; -+ throw TestFailureException(); -+ } // NOLINT(cert-err60-cpp) - #else // DOCTEST_CONFIG_NO_EXCEPTIONS - void throwException() {} - #endif // DOCTEST_CONFIG_NO_EXCEPTIONS -@@ -3487,8 +3881,8 @@ - // matching of a string against a wildcard mask (case sensitivity configurable) taken from - // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing - int wildcmp(const char* str, const char* wild, bool caseSensitive) { -- const char* cp = nullptr; -- const char* mp = nullptr; -+ const char* cp = str; -+ const char* mp = wild; - - while((*str) && (*wild != '*')) { - if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && -@@ -3544,73 +3938,82 @@ - } // namespace - namespace detail { - -- Subcase::Subcase(const char* name, const char* file, int line) -- : m_signature(name, file, line) { -- ContextState* s = g_cs; -- -- // if we have already completed it -- if(s->subcasesPassed.count(m_signature) != 0) -- return; -+ Subcase::Subcase(const String& name, const char* file, int line) -+ : m_signature({name, file, line}) { -+ auto* s = g_cs; - - // check subcase filters -- if(s->subcasesCurrentLevel < s->subcase_filter_levels) { -- if(!matchesAny(m_signature.m_name, s->filters[6], true, s->case_sensitive)) -+ if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) { -+ if(!matchesAny(m_signature.m_name.c_str(), s->filters[6], true, s->case_sensitive)) - return; -- if(matchesAny(m_signature.m_name, s->filters[7], false, s->case_sensitive)) -+ if(matchesAny(m_signature.m_name.c_str(), s->filters[7], false, s->case_sensitive)) - return; - } -- -+ - // if a Subcase on the same level has already been entered -- if(s->subcasesEnteredLevels.count(s->subcasesCurrentLevel) != 0) { -+ if(s->subcasesStack.size() < size_t(s->subcasesCurrentMaxLevel)) { - s->should_reenter = true; - return; - } - -- s->subcasesEnteredLevels.insert(s->subcasesCurrentLevel++); -+ // push the current signature to the stack so we can check if the -+ // current stack + the current new subcase have been traversed -+ s->subcasesStack.push_back(m_signature); -+ if(s->subcasesPassed.count(s->subcasesStack) != 0) { -+ // pop - revert to previous stack since we've already passed this -+ s->subcasesStack.pop_back(); -+ return; -+ } -+ -+ s->subcasesCurrentMaxLevel = s->subcasesStack.size(); - m_entered = true; - - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); - } - -+ DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 -+ DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") -+ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") -+ - Subcase::~Subcase() { - if(m_entered) { -- ContextState* s = g_cs; -- -- s->subcasesCurrentLevel--; -- // only mark the subcase as passed if no subcases have been skipped -- if(s->should_reenter == false) -- s->subcasesPassed.insert(m_signature); -+ // only mark the subcase stack as passed if no subcases have been skipped -+ if(g_cs->should_reenter == false) -+ g_cs->subcasesPassed.insert(g_cs->subcasesStack); -+ g_cs->subcasesStack.pop_back(); - -+#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) -+ if(std::uncaught_exceptions() > 0 -+#else -+ if(std::uncaught_exception() -+#endif -+ && g_cs->shouldLogCurrentException) { -+ DOCTEST_ITERATE_THROUGH_REPORTERS( -+ test_case_exception, {"exception thrown in subcase - will translate later " -+ "when the whole test case has been exited (cannot " -+ "translate while there is an active exception)", -+ false}); -+ g_cs->shouldLogCurrentException = false; -+ } - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); - } - } - -+ DOCTEST_CLANG_SUPPRESS_WARNING_POP -+ DOCTEST_GCC_SUPPRESS_WARNING_POP -+ DOCTEST_MSVC_SUPPRESS_WARNING_POP -+ - Subcase::operator bool() const { return m_entered; } - - Result::Result(bool passed, const String& decomposition) - : m_passed(passed) - , m_decomp(decomposition) {} - -- DOCTEST_DEFINE_DEFAULTS(Result); -- DOCTEST_DEFINE_COPIES(Result); -- - ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at) - : m_at(at) {} - -- DOCTEST_DEFINE_DEFAULTS(ExpressionDecomposer); -- -- DOCTEST_DEFINE_DEFAULTS(TestSuite); -- DOCTEST_DEFINE_COPIES(TestSuite); -- - TestSuite& TestSuite::operator*(const char* in) { - m_test_suite = in; -- // clear state -- m_description = nullptr; -- m_skip = false; -- m_may_fail = false; -- m_should_fail = false; -- m_expected_failures = 0; -- m_timeout = 0; - return *this; - } - -@@ -3622,6 +4025,8 @@ - m_test_suite = test_suite.m_test_suite; - m_description = test_suite.m_description; - m_skip = test_suite.m_skip; -+ m_no_breaks = test_suite.m_no_breaks; -+ m_no_output = test_suite.m_no_output; - m_may_fail = test_suite.m_may_fail; - m_should_fail = test_suite.m_should_fail; - m_expected_failures = test_suite.m_expected_failures; -@@ -3632,8 +4037,6 @@ - m_template_id = template_id; - } - -- DOCTEST_DEFINE_DEFAULTS(TestCase); -- - TestCase::TestCase(const TestCase& other) - : TestCaseData() { - *this = other; -@@ -3667,25 +4070,31 @@ - } - - bool TestCase::operator<(const TestCase& other) const { -+ // this will be used only to differentiate between test cases - not relevant for sorting - if(m_line != other.m_line) - return m_line < other.m_line; -- const int file_cmp = std::strcmp(m_file, other.m_file); -+ const int name_cmp = strcmp(m_name, other.m_name); -+ if(name_cmp != 0) -+ return name_cmp < 0; -+ const int file_cmp = m_file.compare(other.m_file); - if(file_cmp != 0) - return file_cmp < 0; - return m_template_id < other.m_template_id; - } -+ -+ // all the registered tests -+ std::set<TestCase>& getRegisteredTests() { -+ static std::set<TestCase> data; -+ return data; -+ } - } // namespace detail - namespace { - using namespace detail; - // for sorting tests by file/line - bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) { --#if DOCTEST_MSVC - // this is needed because MSVC gives different case for drive letters - // for __FILE__ when evaluated in a header and a source file -- const int res = stricmp(lhs->m_file, rhs->m_file); --#else // MSVC -- const int res = std::strcmp(lhs->m_file, rhs->m_file); --#endif // MSVC -+ const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC)); - if(res != 0) - return res < 0; - if(lhs->m_line != rhs->m_line) -@@ -3709,39 +4118,10 @@ - return suiteOrderComparator(lhs, rhs); - } - -- // all the registered tests -- std::set<TestCase>& getRegisteredTests() { -- static std::set<TestCase> data; -- return data; -- } -- --#ifdef DOCTEST_CONFIG_COLORS_WINDOWS -- HANDLE g_stdoutHandle; -- WORD g_origFgAttrs; -- WORD g_origBgAttrs; -- bool g_attrsInitted = false; -- -- int colors_init() { -- if(!g_attrsInitted) { -- g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); -- g_attrsInitted = true; -- CONSOLE_SCREEN_BUFFER_INFO csbiInfo; -- GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo); -- g_origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | -- BACKGROUND_BLUE | BACKGROUND_INTENSITY); -- g_origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | -- FOREGROUND_BLUE | FOREGROUND_INTENSITY); -- } -- return 0; -- } -- -- int dumy_init_console_colors = colors_init(); --#endif // DOCTEST_CONFIG_COLORS_WINDOWS -- - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - void color_to_stream(std::ostream& s, Color::Enum code) { -- ((void)s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS -- ((void)code); // for DOCTEST_CONFIG_COLORS_NONE -+ static_cast<void>(s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS -+ static_cast<void>(code); // for DOCTEST_CONFIG_COLORS_NONE - #ifdef DOCTEST_CONFIG_COLORS_ANSI - if(g_no_colors || - (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false)) -@@ -3771,10 +4151,26 @@ - - #ifdef DOCTEST_CONFIG_COLORS_WINDOWS - if(g_no_colors || -- (isatty(fileno(stdout)) == false && getContextOptions()->force_colors == false)) -+ (_isatty(_fileno(stdout)) == false && getContextOptions()->force_colors == false)) - return; - --#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(g_stdoutHandle, x | g_origBgAttrs) -+ static struct ConsoleHelper { -+ HANDLE stdoutHandle; -+ WORD origFgAttrs; -+ WORD origBgAttrs; -+ -+ ConsoleHelper() { -+ stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); -+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo; -+ GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo); -+ origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | -+ BACKGROUND_BLUE | BACKGROUND_INTENSITY); -+ origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | -+ FOREGROUND_BLUE | FOREGROUND_INTENSITY); -+ } -+ } ch; -+ -+#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(ch.stdoutHandle, x | ch.origBgAttrs) - - // clang-format off - switch (code) { -@@ -3791,7 +4187,7 @@ - case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; - case Color::None: - case Color::Bright: // invalid -- default: DOCTEST_SET_ATTR(g_origFgAttrs); -+ default: DOCTEST_SET_ATTR(ch.origFgAttrs); - } - // clang-format on - #endif // DOCTEST_CONFIG_COLORS_WINDOWS -@@ -3844,9 +4240,33 @@ - return 0; - } - --#ifdef DOCTEST_PLATFORM_MAC -+#ifdef DOCTEST_IS_DEBUGGER_ACTIVE -+ bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); } -+#else // DOCTEST_IS_DEBUGGER_ACTIVE -+#ifdef DOCTEST_PLATFORM_LINUX -+ class ErrnoGuard { -+ public: -+ ErrnoGuard() : m_oldErrno(errno) {} -+ ~ErrnoGuard() { errno = m_oldErrno; } -+ private: -+ int m_oldErrno; -+ }; -+ // See the comments in Catch2 for the reasoning behind this implementation: -+ // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102 -+ bool isDebuggerActive() { -+ ErrnoGuard guard; -+ std::ifstream in("/proc/self/status"); -+ for(std::string line; std::getline(in, line);) { -+ static const int PREFIX_LEN = 11; -+ if(line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) { -+ return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; -+ } -+ } -+ return false; -+ } -+#elif defined(DOCTEST_PLATFORM_MAC) - // The following function is taken directly from the following technical note: -- // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html -+ // https://developer.apple.com/library/archive/qa/qa1361/_index.html - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive() { -@@ -3871,11 +4291,12 @@ - // We're being debugged if the P_TRACED flag is set. - return ((info.kp_proc.p_flag & P_TRACED) != 0); - } --#elif DOCTEST_MSVC || defined(__MINGW32__) -+#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__) - bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } - #else - bool isDebuggerActive() { return false; } - #endif // Platform -+#endif // DOCTEST_IS_DEBUGGER_ACTIVE - - void registerExceptionTranslatorImpl(const IExceptionTranslator* et) { - if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) == -@@ -3910,41 +4331,47 @@ - g_infoContexts.push_back(this); - } - -+ ContextScopeBase::ContextScopeBase(ContextScopeBase&& other) { -+ if (other.need_to_destroy) { -+ other.destroy(); -+ } -+ other.need_to_destroy = false; -+ g_infoContexts.push_back(this); -+ } -+ - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") -+ - // destroy cannot be inlined into the destructor because that would mean calling stringify after - // ContextScope has been destroyed (base class destructors run after derived class destructors). - // Instead, ContextScope calls this method directly from its destructor. - void ContextScopeBase::destroy() { -+#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) -+ if(std::uncaught_exceptions() > 0) { -+#else - if(std::uncaught_exception()) { -+#endif - std::ostringstream s; - this->stringify(&s); - g_cs->stringifiedContexts.push_back(s.str().c_str()); - } - g_infoContexts.pop_back(); - } -+ - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - DOCTEST_MSVC_SUPPRESS_WARNING_POP -- - } // namespace detail - namespace { - using namespace detail; - -- std::ostream& file_line_to_stream(std::ostream& s, const char* file, int line, -- const char* tail = "") { -- const auto opt = getContextOptions(); -- s << Color::LightGrey << skipPathFromFilename(file) << (opt->gnu_file_line ? ":" : "(") -- << (opt->no_line_numbers ? 0 : line) // 0 or the real num depending on the option -- << (opt->gnu_file_line ? ":" : "):") << tail; -- return s; -- } -- - #if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) - struct FatalConditionHandler - { -- void reset() {} -+ static void reset() {} -+ static void allocateAltStackMem() {} -+ static void freeAltStackMem() {} - }; - #else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH - -@@ -3961,43 +4388,113 @@ - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - SignalDefs signalDefs[] = { -- {EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal"}, -- {EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow"}, -- {EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal"}, -- {EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error"}, -+ {static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), -+ "SIGILL - Illegal instruction signal"}, -+ {static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"}, -+ {static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), -+ "SIGSEGV - Segmentation violation signal"}, -+ {static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"}, - }; - - struct FatalConditionHandler - { -- static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { -- for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { -- if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { -- reportFatal(signalDefs[i].name); -+ static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) { -+ // Multiple threads may enter this filter/handler at once. We want the error message to be printed on the -+ // console just once no matter how many threads have crashed. -+ static std::mutex mutex; -+ static bool execute = true; -+ { -+ std::lock_guard<std::mutex> lock(mutex); -+ if(execute) { -+ bool reported = false; -+ for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { -+ if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { -+ reportFatal(signalDefs[i].name); -+ reported = true; -+ break; -+ } -+ } -+ if(reported == false) -+ reportFatal("Unhandled SEH exception caught"); -+ if(isDebuggerActive() && !g_cs->no_breaks) -+ DOCTEST_BREAK_INTO_DEBUGGER(); - } -+ execute = false; - } -- // If its not an exception we care about, pass it along. -- // This stops us from eating debugger breaks etc. -- return EXCEPTION_CONTINUE_SEARCH; -+ std::exit(EXIT_FAILURE); - } - -+ static void allocateAltStackMem() {} -+ static void freeAltStackMem() {} -+ - FatalConditionHandler() { - isSet = true; - // 32k seems enough for doctest to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; -- exceptionHandlerHandle = nullptr; -- // Register as first handler in current chain -- exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); -+ // Register an unhandled exception filter -+ previousTop = SetUnhandledExceptionFilter(handleException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); -+ -+ // On Windows uncaught exceptions from another thread, exceptions from -+ // destructors, or calls to std::terminate are not a SEH exception -+ -+ // The terminal handler gets called when: -+ // - std::terminate is called FROM THE TEST RUNNER THREAD -+ // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD -+ original_terminate_handler = std::get_terminate(); -+ std::set_terminate([]() DOCTEST_NOEXCEPT { -+ reportFatal("Terminate handler called"); -+ if(isDebuggerActive() && !g_cs->no_breaks) -+ DOCTEST_BREAK_INTO_DEBUGGER(); -+ std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well -+ }); -+ -+ // SIGABRT is raised when: -+ // - std::terminate is called FROM A DIFFERENT THREAD -+ // - an exception is thrown from a destructor FROM A DIFFERENT THREAD -+ // - an uncaught exception is thrown FROM A DIFFERENT THREAD -+ prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT { -+ if(signal == SIGABRT) { -+ reportFatal("SIGABRT - Abort (abnormal termination) signal"); -+ if(isDebuggerActive() && !g_cs->no_breaks) -+ DOCTEST_BREAK_INTO_DEBUGGER(); -+ std::exit(EXIT_FAILURE); -+ } -+ }); -+ -+ // The following settings are taken from google test, and more -+ // specifically from UnitTest::Run() inside of gtest.cc -+ -+ // the user does not want to see pop-up dialogs about crashes -+ prev_error_mode_1 = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | -+ SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); -+ // This forces the abort message to go to stderr in all circumstances. -+ prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR); -+ // In the debug version, Visual Studio pops up a separate dialog -+ // offering a choice to debug the aborted program - we want to disable that. -+ prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); -+ // In debug mode, the Windows CRT can crash with an assertion over invalid -+ // input (e.g. passing an invalid file descriptor). The default handling -+ // for these assertions is to pop up a dialog and wait for user input. -+ // Instead ask the CRT to dump such assertions to stderr non-interactively. -+ prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); -+ prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); - } - - static void reset() { - if(isSet) { - // Unregister handler and restore the old guarantee -- RemoveVectoredExceptionHandler(exceptionHandlerHandle); -+ SetUnhandledExceptionFilter(previousTop); - SetThreadStackGuarantee(&guaranteeSize); -- exceptionHandlerHandle = nullptr; -+ std::set_terminate(original_terminate_handler); -+ std::signal(SIGABRT, prev_sigabrt_handler); -+ SetErrorMode(prev_error_mode_1); -+ _set_error_mode(prev_error_mode_2); -+ _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); -+ static_cast<void>(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode)); -+ static_cast<void>(_CrtSetReportFile(_CRT_ASSERT, prev_report_file)); - isSet = false; - } - } -@@ -4005,14 +4502,28 @@ - ~FatalConditionHandler() { reset(); } - - private: -+ static UINT prev_error_mode_1; -+ static int prev_error_mode_2; -+ static unsigned int prev_abort_behavior; -+ static int prev_report_mode; -+ static _HFILE prev_report_file; -+ static void (DOCTEST_CDECL *prev_sigabrt_handler)(int); -+ static std::terminate_handler original_terminate_handler; - static bool isSet; - static ULONG guaranteeSize; -- static PVOID exceptionHandlerHandle; -+ static LPTOP_LEVEL_EXCEPTION_FILTER previousTop; - }; - -+ UINT FatalConditionHandler::prev_error_mode_1; -+ int FatalConditionHandler::prev_error_mode_2; -+ unsigned int FatalConditionHandler::prev_abort_behavior; -+ int FatalConditionHandler::prev_report_mode; -+ _HFILE FatalConditionHandler::prev_report_file; -+ void (DOCTEST_CDECL *FatalConditionHandler::prev_sigabrt_handler)(int); -+ std::terminate_handler FatalConditionHandler::original_terminate_handler; - bool FatalConditionHandler::isSet = false; - ULONG FatalConditionHandler::guaranteeSize = 0; -- PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; -+ LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr; - - #else // DOCTEST_PLATFORM_WINDOWS - -@@ -4033,7 +4544,8 @@ - static bool isSet; - static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; - static stack_t oldSigStack; -- static char altStackMem[4 * SIGSTKSZ]; -+ static size_t altStackSize; -+ static char* altStackMem; - - static void handleSignal(int sig) { - const char* name = "<unknown signal>"; -@@ -4049,11 +4561,19 @@ - raise(sig); - } - -+ static void allocateAltStackMem() { -+ altStackMem = new char[altStackSize]; -+ } -+ -+ static void freeAltStackMem() { -+ delete[] altStackMem; -+ } -+ - FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; -- sigStack.ss_size = sizeof(altStackMem); -+ sigStack.ss_size = altStackSize; - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = {}; -@@ -4078,10 +4598,11 @@ - } - }; - -- bool FatalConditionHandler::isSet = false; -+ bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; -- stack_t FatalConditionHandler::oldSigStack = {}; -- char FatalConditionHandler::altStackMem[] = {}; -+ stack_t FatalConditionHandler::oldSigStack = {}; -+ size_t FatalConditionHandler::altStackSize = 4 * SIGSTKSZ; -+ char* FatalConditionHandler::altStackMem = nullptr; - - #endif // DOCTEST_PLATFORM_WINDOWS - #endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH -@@ -4114,8 +4635,10 @@ - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true}); - -- while(g_cs->subcasesCurrentLevel--) -+ while(g_cs->subcasesStack.size()) { -+ g_cs->subcasesStack.pop_back(); - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); -+ } - - g_cs->finalizeTestCaseData(); - -@@ -4128,24 +4651,23 @@ - namespace detail { - - ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, -- const char* exception_type) { -- m_test_case = g_cs->currentTest; -- m_at = at; -- m_file = file; -- m_line = line; -- m_expr = expr; -- m_failed = true; -- m_threw = false; -- m_threw_as = false; -- m_exception_type = exception_type; -+ const char* exception_type, const char* exception_string) { -+ m_test_case = g_cs->currentTest; -+ m_at = at; -+ m_file = file; -+ m_line = line; -+ m_expr = expr; -+ m_failed = true; -+ m_threw = false; -+ m_threw_as = false; -+ m_exception_type = exception_type; -+ m_exception_string = exception_string; - #if DOCTEST_MSVC - if(m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC - ++m_expr; - #endif // MSVC - } - -- DOCTEST_DEFINE_DEFAULTS(ResultBuilder); -- - void ResultBuilder::setResult(const Result& res) { - m_decomp = res.m_decomp; - m_failed = !res.m_passed; -@@ -4159,16 +4681,18 @@ - bool ResultBuilder::log() { - if(m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional - m_failed = !m_threw; -+ } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT -+ m_failed = !m_threw_as || (m_exception != m_exception_string); - } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional - m_failed = !m_threw_as; - } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional -- m_failed = m_exception != m_exception_type; -+ m_failed = m_exception != m_exception_string; - } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional - m_failed = m_threw; - } - - if(m_exception.size()) -- m_exception = String("\"") + m_exception + "\""; -+ m_exception = "\"" + m_exception + "\""; - - if(is_running_in_test) { - addAssert(m_at); -@@ -4180,8 +4704,8 @@ - failed_out_of_a_testing_context(*this); - } - -- return m_failed && isDebuggerActive() && -- !getContextOptions()->no_breaks; // break into debugger -+ return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks && -+ (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger - } - - void ResultBuilder::react() const { -@@ -4196,7 +4720,7 @@ - std::abort(); - } - -- void decomp_assert(assertType::Enum at, const char* file, int line, const char* expr, -+ bool decomp_assert(assertType::Enum at, const char* file, int line, const char* expr, - Result result) { - bool failed = !result.m_passed; - -@@ -4206,58 +4730,53 @@ - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp); - DOCTEST_ASSERT_IN_TESTS(result.m_decomp); -+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) -+ return !failed; - } - - MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) { -- m_stream = getTlsOss(); -+ m_stream = tlssPush(); - m_file = file; - m_line = line; - m_severity = severity; - } - -+ MessageBuilder::~MessageBuilder() { -+ if (!logged) -+ tlssPop(); -+ } -+ - IExceptionTranslator::IExceptionTranslator() = default; - IExceptionTranslator::~IExceptionTranslator() = default; - - bool MessageBuilder::log() { -- m_string = getTlsOssResult(); -+ if (!logged) { -+ m_string = tlssPop(); -+ logged = true; -+ } -+ - DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this); - - const bool isWarn = m_severity & assertType::is_warn; - -- // warn is just a message in this context so we dont treat it as an assert -+ // warn is just a message in this context so we don't treat it as an assert - if(!isWarn) { - addAssert(m_severity); - addFailedAssert(m_severity); - } - -- return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn; // break -+ return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn && -+ (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger - } - - void MessageBuilder::react() { - if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional - throwException(); - } -- -- MessageBuilder::~MessageBuilder() = default; - } // namespace detail - namespace { - using namespace detail; - -- template <typename Ex> -- [[noreturn]] void throw_exception(Ex const& e) { --#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -- throw e; --#else // DOCTEST_CONFIG_NO_EXCEPTIONS -- std::cerr << "doctest will terminate because it needed to throw an exception.\n" -- << "The message was: " << e.what() << '\n'; -- std::terminate(); --#endif // DOCTEST_CONFIG_NO_EXCEPTIONS -- } -- --#define DOCTEST_INTERNAL_ERROR(msg) \ -- throw_exception(std::logic_error( \ -- __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) -- - // clang-format off - - // ================================================================================================= -@@ -4287,8 +4806,8 @@ - public: - ScopedElement( XmlWriter* writer ); - -- ScopedElement( ScopedElement&& other ) noexcept; -- ScopedElement& operator=( ScopedElement&& other ) noexcept; -+ ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT; -+ ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT; - - ~ScopedElement(); - -@@ -4404,7 +4923,7 @@ - - void XmlEncode::encodeTo( std::ostream& os ) const { - // Apostrophe escaping not necessary if we always use " to write attributes -- // (see: http://www.w3.org/TR/xml/#syntax) -+ // (see: https://www.w3.org/TR/xml/#syntax) - - for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { - uchar c = m_str[idx]; -@@ -4413,7 +4932,7 @@ - case '&': os << "&"; break; - - case '>': -- // See: http://www.w3.org/TR/xml/#syntax -+ // See: https://www.w3.org/TR/xml/#syntax - if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') - os << ">"; - else -@@ -4431,7 +4950,7 @@ - // Check for control characters and invalid utf-8 - - // Escape control characters in standard ascii -- // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 -+ // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { - hexEscapeChar(os, c); - break; -@@ -4505,11 +5024,11 @@ - : m_writer( writer ) - {} - -- XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept -+ XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT - : m_writer( other.m_writer ){ - other.m_writer = nullptr; - } -- XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { -+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT { - if ( m_writer ) { - m_writer->endElement(); - } -@@ -4671,7 +5190,7 @@ - void test_case_start_impl(const TestCaseData& in) { - bool open_ts_tag = false; - if(tc != nullptr) { // we have already opened a test suite -- if(strcmp(tc->m_test_suite, in.m_test_suite) != 0) { -+ if(std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) { - xml.endElement(); - open_ts_tag = true; - } -@@ -4688,7 +5207,7 @@ - tc = ∈ - xml.startElement("TestCase") - .writeAttribute("name", in.m_name) -- .writeAttribute("filename", skipPathFromFilename(in.m_file)) -+ .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str())) - .writeAttribute("line", line(in.m_line)) - .writeAttribute("description", in.m_description); - -@@ -4716,13 +5235,18 @@ - .writeAttribute("priority", curr.first.first) - .writeAttribute("name", curr.first.second); - } else if(opt.count || opt.list_test_cases) { -- for(unsigned i = 0; i < in.num_data; ++i) -- xml.scopedElement("TestCase").writeAttribute("name", in.data[i]); -+ for(unsigned i = 0; i < in.num_data; ++i) { -+ xml.scopedElement("TestCase").writeAttribute("name", in.data[i]->m_name) -+ .writeAttribute("testsuite", in.data[i]->m_test_suite) -+ .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str())) -+ .writeAttribute("line", line(in.data[i]->m_line)) -+ .writeAttribute("skipped", in.data[i]->m_skip); -+ } - xml.scopedElement("OverallResultsTestCases") - .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); - } else if(opt.list_test_suites) { - for(unsigned i = 0; i < in.num_data; ++i) -- xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]); -+ xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite); - xml.scopedElement("OverallResultsTestCases") - .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); - xml.scopedElement("OverallResultsTestSuites") -@@ -4779,12 +5303,15 @@ - test_case_start_impl(in); - xml.ensureTagClosed(); - } -+ -+ void test_case_reenter(const TestCaseData&) override {} - - void test_case_end(const CurrentTestCaseStats& st) override { - xml.startElement("OverallResultsAsserts") - .writeAttribute("successes", - st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest) -- .writeAttribute("failures", st.numAssertsFailedCurrentTest); -+ .writeAttribute("failures", st.numAssertsFailedCurrentTest) -+ .writeAttribute("test_case_success", st.testCaseSuccess); - if(opt.duration) - xml.writeAttribute("duration", st.seconds); - if(tc->m_expected_failures) -@@ -4803,8 +5330,6 @@ - } - - void subcase_start(const SubcaseSignature& in) override { -- std::lock_guard<std::mutex> lock(mutex); -- - xml.startElement("SubCase") - .writeAttribute("name", in.m_name) - .writeAttribute("filename", skipPathFromFilename(in.m_file)) -@@ -4831,11 +5356,12 @@ - if(rb.m_threw) - xml.scopedElement("Exception").writeText(rb.m_exception.c_str()); - -- if(rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) { -+ if(rb.m_at & assertType::is_throws_as) - xml.scopedElement("ExpectedException").writeText(rb.m_exception_type); -- } else if((rb.m_at & assertType::is_normal) && !rb.m_threw) { -+ if(rb.m_at & assertType::is_throws_with) -+ xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string); -+ if((rb.m_at & assertType::is_normal) && !rb.m_threw) - xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str()); -- } - - log_contexts(); - -@@ -4868,6 +5394,278 @@ - - DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter); - -+ void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) { -+ if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == -+ 0) //!OCLINT bitwise operator in conditional -+ s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " -+ << Color::None; -+ -+ if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional -+ s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; -+ } else if((rb.m_at & assertType::is_throws_as) && -+ (rb.m_at & assertType::is_throws_with)) { //!OCLINT -+ s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" -+ << rb.m_exception_string << "\", " << rb.m_exception_type << " ) " << Color::None; -+ if(rb.m_threw) { -+ if(!rb.m_failed) { -+ s << "threw as expected!\n"; -+ } else { -+ s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n"; -+ } -+ } else { -+ s << "did NOT throw at all!\n"; -+ } -+ } else if(rb.m_at & -+ assertType::is_throws_as) { //!OCLINT bitwise operator in conditional -+ s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", " -+ << rb.m_exception_type << " ) " << Color::None -+ << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" : -+ "threw a DIFFERENT exception: ") : -+ "did NOT throw at all!") -+ << Color::Cyan << rb.m_exception << "\n"; -+ } else if(rb.m_at & -+ assertType::is_throws_with) { //!OCLINT bitwise operator in conditional -+ s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" -+ << rb.m_exception_string << "\" ) " << Color::None -+ << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" : -+ "threw a DIFFERENT exception: ") : -+ "did NOT throw at all!") -+ << Color::Cyan << rb.m_exception << "\n"; -+ } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional -+ s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan -+ << rb.m_exception << "\n"; -+ } else { -+ s << (rb.m_threw ? "THREW exception: " : -+ (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")); -+ if(rb.m_threw) -+ s << rb.m_exception << "\n"; -+ else -+ s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n"; -+ } -+ } -+ -+ // TODO: -+ // - log_message() -+ // - respond to queries -+ // - honor remaining options -+ // - more attributes in tags -+ struct JUnitReporter : public IReporter -+ { -+ XmlWriter xml; -+ std::mutex mutex; -+ Timer timer; -+ std::vector<String> deepestSubcaseStackNames; -+ -+ struct JUnitTestCaseData -+ { -+ static std::string getCurrentTimestamp() { -+ // Beware, this is not reentrant because of backward compatibility issues -+ // Also, UTC only, again because of backward compatibility (%z is C++11) -+ time_t rawtime; -+ std::time(&rawtime); -+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); -+ -+ std::tm timeInfo; -+#ifdef DOCTEST_PLATFORM_WINDOWS -+ gmtime_s(&timeInfo, &rawtime); -+#else // DOCTEST_PLATFORM_WINDOWS -+ gmtime_r(&rawtime, &timeInfo); -+#endif // DOCTEST_PLATFORM_WINDOWS -+ -+ char timeStamp[timeStampSize]; -+ const char* const fmt = "%Y-%m-%dT%H:%M:%SZ"; -+ -+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -+ return std::string(timeStamp); -+ } -+ -+ struct JUnitTestMessage -+ { -+ JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details) -+ : message(_message), type(_type), details(_details) {} -+ -+ JUnitTestMessage(const std::string& _message, const std::string& _details) -+ : message(_message), type(), details(_details) {} -+ -+ std::string message, type, details; -+ }; -+ -+ struct JUnitTestCase -+ { -+ JUnitTestCase(const std::string& _classname, const std::string& _name) -+ : classname(_classname), name(_name), time(0), failures() {} -+ -+ std::string classname, name; -+ double time; -+ std::vector<JUnitTestMessage> failures, errors; -+ }; -+ -+ void add(const std::string& classname, const std::string& name) { -+ testcases.emplace_back(classname, name); -+ } -+ -+ void appendSubcaseNamesToLastTestcase(std::vector<String> nameStack) { -+ for(auto& curr: nameStack) -+ if(curr.size()) -+ testcases.back().name += std::string("/") + curr.c_str(); -+ } -+ -+ void addTime(double time) { -+ if(time < 1e-4) -+ time = 0; -+ testcases.back().time = time; -+ totalSeconds += time; -+ } -+ -+ void addFailure(const std::string& message, const std::string& type, const std::string& details) { -+ testcases.back().failures.emplace_back(message, type, details); -+ ++totalFailures; -+ } -+ -+ void addError(const std::string& message, const std::string& details) { -+ testcases.back().errors.emplace_back(message, details); -+ ++totalErrors; -+ } -+ -+ std::vector<JUnitTestCase> testcases; -+ double totalSeconds = 0; -+ int totalErrors = 0, totalFailures = 0; -+ }; -+ -+ JUnitTestCaseData testCaseData; -+ -+ // caching pointers/references to objects of these types - safe to do -+ const ContextOptions& opt; -+ const TestCaseData* tc = nullptr; -+ -+ JUnitReporter(const ContextOptions& co) -+ : xml(*co.cout) -+ , opt(co) {} -+ -+ unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } -+ -+ // ========================================================================================= -+ // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE -+ // ========================================================================================= -+ -+ void report_query(const QueryData&) override {} -+ -+ void test_run_start() override {} -+ -+ void test_run_end(const TestRunStats& p) override { -+ // remove .exe extension - mainly to have the same output on UNIX and Windows -+ std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); -+#ifdef DOCTEST_PLATFORM_WINDOWS -+ if(binary_name.rfind(".exe") != std::string::npos) -+ binary_name = binary_name.substr(0, binary_name.length() - 4); -+#endif // DOCTEST_PLATFORM_WINDOWS -+ xml.startElement("testsuites"); -+ xml.startElement("testsuite").writeAttribute("name", binary_name) -+ .writeAttribute("errors", testCaseData.totalErrors) -+ .writeAttribute("failures", testCaseData.totalFailures) -+ .writeAttribute("tests", p.numAsserts); -+ if(opt.no_time_in_output == false) { -+ xml.writeAttribute("time", testCaseData.totalSeconds); -+ xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp()); -+ } -+ if(opt.no_version == false) -+ xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR); -+ -+ for(const auto& testCase : testCaseData.testcases) { -+ xml.startElement("testcase") -+ .writeAttribute("classname", testCase.classname) -+ .writeAttribute("name", testCase.name); -+ if(opt.no_time_in_output == false) -+ xml.writeAttribute("time", testCase.time); -+ // This is not ideal, but it should be enough to mimic gtest's junit output. -+ xml.writeAttribute("status", "run"); -+ -+ for(const auto& failure : testCase.failures) { -+ xml.scopedElement("failure") -+ .writeAttribute("message", failure.message) -+ .writeAttribute("type", failure.type) -+ .writeText(failure.details, false); -+ } -+ -+ for(const auto& error : testCase.errors) { -+ xml.scopedElement("error") -+ .writeAttribute("message", error.message) -+ .writeText(error.details); -+ } -+ -+ xml.endElement(); -+ } -+ xml.endElement(); -+ xml.endElement(); -+ } -+ -+ void test_case_start(const TestCaseData& in) override { -+ testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); -+ timer.start(); -+ } -+ -+ void test_case_reenter(const TestCaseData& in) override { -+ testCaseData.addTime(timer.getElapsedSeconds()); -+ testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); -+ deepestSubcaseStackNames.clear(); -+ -+ timer.start(); -+ testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); -+ } -+ -+ void test_case_end(const CurrentTestCaseStats&) override { -+ testCaseData.addTime(timer.getElapsedSeconds()); -+ testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); -+ deepestSubcaseStackNames.clear(); -+ } -+ -+ void test_case_exception(const TestCaseException& e) override { -+ std::lock_guard<std::mutex> lock(mutex); -+ testCaseData.addError("exception", e.error_string.c_str()); -+ } -+ -+ void subcase_start(const SubcaseSignature& in) override { -+ deepestSubcaseStackNames.push_back(in.m_name); -+ } -+ -+ void subcase_end() override {} -+ -+ void log_assert(const AssertData& rb) override { -+ if(!rb.m_failed) // report only failures & ignore the `success` option -+ return; -+ -+ std::lock_guard<std::mutex> lock(mutex); -+ -+ std::ostringstream os; -+ os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(") -+ << line(rb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl; -+ -+ fulltext_log_assert_to_stream(os, rb); -+ log_contexts(os); -+ testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str()); -+ } -+ -+ void log_message(const MessageData&) override {} -+ -+ void test_case_skipped(const TestCaseData&) override {} -+ -+ void log_contexts(std::ostringstream& s) { -+ int num_contexts = get_num_active_contexts(); -+ if(num_contexts) { -+ auto contexts = get_active_contexts(); -+ -+ s << " logged: "; -+ for(int i = 0; i < num_contexts; ++i) { -+ s << (i == 0 ? "" : " "); -+ contexts[i]->stringify(&s); -+ s << std::endl; -+ } -+ } -+ } -+ }; -+ -+ DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter); -+ - struct Whitespace - { - int nrSpaces; -@@ -4886,6 +5684,7 @@ - std::ostream& s; - bool hasLoggedCurrentTestStart; - std::vector<SubcaseSignature> subcasesStack; -+ size_t currentSubcaseLevel; - std::mutex mutex; - - // caching pointers/references to objects of these types - safe to do -@@ -4944,23 +5743,40 @@ - s << "\n"; - } - -+ // this was requested to be made virtual so users could override it -+ virtual void file_line_to_stream(const char* file, int line, -+ const char* tail = "") { -+ s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(") -+ << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option -+ << (opt.gnu_file_line ? ":" : "):") << tail; -+ } -+ - void logTestStart() { - if(hasLoggedCurrentTestStart) - return; - - separator_to_stream(); -- file_line_to_stream(s, tc->m_file, tc->m_line, "\n"); -+ file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n"); - if(tc->m_description) - s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n"; - if(tc->m_test_suite && tc->m_test_suite[0] != '\0') - s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n"; - if(strncmp(tc->m_name, " Scenario:", 11) != 0) -- s << Color::None << "TEST CASE: "; -+ s << Color::Yellow << "TEST CASE: "; - s << Color::None << tc->m_name << "\n"; - -- for(auto& curr : subcasesStack) -- if(curr.m_name[0] != '\0') -- s << " " << curr.m_name << "\n"; -+ for(size_t i = 0; i < currentSubcaseLevel; ++i) { -+ if(subcasesStack[i].m_name[0] != '\0') -+ s << " " << subcasesStack[i].m_name << "\n"; -+ } -+ -+ if(currentSubcaseLevel != subcasesStack.size()) { -+ s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None; -+ for(size_t i = 0; i < subcasesStack.size(); ++i) { -+ if(subcasesStack[i].m_name[0] != '\0') -+ s << " " << subcasesStack[i].m_name << "\n"; -+ } -+ } - - s << "\n"; - -@@ -4974,9 +5790,11 @@ - } - - void printIntro() { -- printVersion(); -- s << Color::Cyan << "[doctest] " << Color::None -- << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; -+ if(opt.no_intro == false) { -+ printVersion(); -+ s << Color::Cyan << "[doctest] " << Color::None -+ << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; -+ } - } - - void printHelp() { -@@ -5038,7 +5856,7 @@ - << Whitespace(sizePrefixDisplay*1) << "output filename\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by=<string> " - << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n"; -- s << Whitespace(sizePrefixDisplay*3) << " <string> - by [file/suite/name/rand]\n"; -+ s << Whitespace(sizePrefixDisplay*3) << " <string> - [file/suite/name/rand/none]\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed=<int> " - << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first=<int> " -@@ -5061,12 +5879,18 @@ - << Whitespace(sizePrefixDisplay*1) << "exits after the tests finish\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration=<bool> " - << Whitespace(sizePrefixDisplay*1) << "prints the time duration of each test\n"; -+ s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "m, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "minimal=<bool> " -+ << Whitespace(sizePrefixDisplay*1) << "minimal console output (only failures)\n"; -+ s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "q, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "quiet=<bool> " -+ << Whitespace(sizePrefixDisplay*1) << "no console output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw=<bool> " - << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related assert checks\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode=<bool> " - << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always with success\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run=<bool> " - << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest operations\n"; -+ s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ni, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-intro=<bool> " -+ << Whitespace(sizePrefixDisplay*1) << "omit the framework intro in the output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version=<bool> " - << Whitespace(sizePrefixDisplay*1) << "omit the framework version in the output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors=<bool> " -@@ -5104,22 +5928,6 @@ - printReporters(getReporters(), "reporters"); - } - -- void list_query_results() { -- separator_to_stream(); -- if(opt.count || opt.list_test_cases) { -- s << Color::Cyan << "[doctest] " << Color::None -- << "unskipped test cases passing the current filters: " -- << g_cs->numTestCasesPassingFilters << "\n"; -- } else if(opt.list_test_suites) { -- s << Color::Cyan << "[doctest] " << Color::None -- << "unskipped test cases passing the current filters: " -- << g_cs->numTestCasesPassingFilters << "\n"; -- s << Color::Cyan << "[doctest] " << Color::None -- << "test suites with unskipped test cases passing the current filters: " -- << g_cs->numTestSuitesPassingFilters << "\n"; -- } -- } -- - // ========================================================================================= - // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE - // ========================================================================================= -@@ -5139,7 +5947,7 @@ - } - - for(unsigned i = 0; i < in.num_data; ++i) -- s << Color::None << in.data[i] << "\n"; -+ s << Color::None << in.data[i]->m_name << "\n"; - - separator_to_stream(); - -@@ -5152,7 +5960,7 @@ - separator_to_stream(); - - for(unsigned i = 0; i < in.num_data; ++i) -- s << Color::None << in.data[i] << "\n"; -+ s << Color::None << in.data[i]->m_test_suite << "\n"; - - separator_to_stream(); - -@@ -5165,30 +5973,40 @@ - } - } - -- void test_run_start() override { printIntro(); } -+ void test_run_start() override { -+ if(!opt.minimal) -+ printIntro(); -+ } - - void test_run_end(const TestRunStats& p) override { -+ if(opt.minimal && p.numTestCasesFailed == 0) -+ return; -+ - separator_to_stream(); -+ s << std::dec; - -+ auto totwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters, static_cast<unsigned>(p.numAsserts))) + 1))); -+ auto passwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast<unsigned>(p.numAsserts - p.numAssertsFailed))) + 1))); -+ auto failwidth = int(std::ceil(log10((std::max(p.numTestCasesFailed, static_cast<unsigned>(p.numAssertsFailed))) + 1))); - const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0; -- s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(6) -+ s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth) - << p.numTestCasesPassingFilters << " | " - << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None : - Color::Green) -- << std::setw(6) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed" -+ << std::setw(passwidth) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed" - << Color::None << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None) -- << std::setw(6) << p.numTestCasesFailed << " failed" << Color::None << " | "; -+ << std::setw(failwidth) << p.numTestCasesFailed << " failed" << Color::None << " |"; - if(opt.no_skipped_summary == false) { - const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters; -- s << (numSkipped == 0 ? Color::None : Color::Yellow) << std::setw(6) << numSkipped -+ s << " " << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped - << " skipped" << Color::None; - } - s << "\n"; -- s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(6) -+ s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(totwidth) - << p.numAsserts << " | " - << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green) -- << std::setw(6) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None -- << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(6) -+ << std::setw(passwidth) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None -+ << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth) - << p.numAssertsFailed << " failed" << Color::None << " |\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green) -@@ -5198,9 +6016,18 @@ - void test_case_start(const TestCaseData& in) override { - hasLoggedCurrentTestStart = false; - tc = ∈ -+ subcasesStack.clear(); -+ currentSubcaseLevel = 0; -+ } -+ -+ void test_case_reenter(const TestCaseData&) override { -+ subcasesStack.clear(); - } - - void test_case_end(const CurrentTestCaseStats& st) override { -+ if(tc->m_no_output) -+ return; -+ - // log the preamble of the test case only if there is something - // else to print - something other than that an assert has failed - if(opt.duration || -@@ -5235,9 +6062,13 @@ - } - - void test_case_exception(const TestCaseException& e) override { -+ std::lock_guard<std::mutex> lock(mutex); -+ if(tc->m_no_output) -+ return; -+ - logTestStart(); - -- file_line_to_stream(s, tc->m_file, tc->m_line, " "); -+ file_line_to_stream(tc->m_file.c_str(), tc->m_line, " "); - successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require : - assertType::is_check); - s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ") -@@ -5256,71 +6087,41 @@ - } - - void subcase_start(const SubcaseSignature& subc) override { -- std::lock_guard<std::mutex> lock(mutex); - subcasesStack.push_back(subc); -+ ++currentSubcaseLevel; - hasLoggedCurrentTestStart = false; - } - - void subcase_end() override { -- std::lock_guard<std::mutex> lock(mutex); -- subcasesStack.pop_back(); -+ --currentSubcaseLevel; - hasLoggedCurrentTestStart = false; - } - - void log_assert(const AssertData& rb) override { -- if(!rb.m_failed && !opt.success) -+ if((!rb.m_failed && !opt.success) || tc->m_no_output) - return; - - std::lock_guard<std::mutex> lock(mutex); - - logTestStart(); - -- file_line_to_stream(s, rb.m_file, rb.m_line, " "); -+ file_line_to_stream(rb.m_file, rb.m_line, " "); - successOrFailColoredStringToStream(!rb.m_failed, rb.m_at); -- if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == -- 0) //!OCLINT bitwise operator in conditional -- s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " -- << Color::None; -- -- if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional -- s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; -- } else if(rb.m_at & -- assertType::is_throws_as) { //!OCLINT bitwise operator in conditional -- s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", " -- << rb.m_exception_type << " ) " << Color::None -- << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" : -- "threw a DIFFERENT exception: ") : -- "did NOT throw at all!") -- << Color::Cyan << rb.m_exception << "\n"; -- } else if(rb.m_at & -- assertType::is_throws_with) { //!OCLINT bitwise operator in conditional -- s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" -- << rb.m_exception_type << "\" ) " << Color::None -- << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" : -- "threw a DIFFERENT exception: ") : -- "did NOT throw at all!") -- << Color::Cyan << rb.m_exception << "\n"; -- } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional -- s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan -- << rb.m_exception << "\n"; -- } else { -- s << (rb.m_threw ? "THREW exception: " : -- (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")); -- if(rb.m_threw) -- s << rb.m_exception << "\n"; -- else -- s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n"; -- } -+ -+ fulltext_log_assert_to_stream(s, rb); - - log_contexts(); - } - - void log_message(const MessageData& mb) override { -+ if(tc->m_no_output) -+ return; -+ - std::lock_guard<std::mutex> lock(mutex); - - logTestStart(); - -- file_line_to_stream(s, mb.m_file, mb.m_line, " "); -+ file_line_to_stream(mb.m_file, mb.m_line, " "); - s << getSuccessOrFailColor(false, mb.m_severity) - << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity, - "MESSAGE") << ": "; -@@ -5346,14 +6147,17 @@ - bool with_col = g_no_colors; \ - g_no_colors = false; \ - ConsoleReporter::func(arg); \ -- DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ -- oss.str(""); \ -+ if(oss.tellp() != std::streampos{}) { \ -+ DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ -+ oss.str(""); \ -+ } \ - g_no_colors = with_col; \ - } - - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in) -+ DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in) -@@ -5368,7 +6172,7 @@ - - // the implementation of parseOption() - bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) { -- // going from the end to the begining and stopping on the first occurance from the end -+ // going from the end to the beginning and stopping on the first occurrence from the end - for(int i = argc; i > 0; --i) { - auto index = i - 1; - auto temp = std::strstr(argv[index], pattern); -@@ -5424,18 +6228,42 @@ - std::vector<String>& res) { - String filtersString; - if(parseOption(argc, argv, pattern, &filtersString)) { -- // tokenize with "," as a separator -- // cppcheck-suppress strtokCalled -- DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") -- auto pch = std::strtok(filtersString.c_str(), ","); // modifies the string -- while(pch != nullptr) { -- if(strlen(pch)) -- res.push_back(pch); -- // uses the strtok() internal state to go to the next token -- // cppcheck-suppress strtokCalled -- pch = std::strtok(nullptr, ","); -+ // tokenize with "," as a separator, unless escaped with backslash -+ std::ostringstream s; -+ auto flush = [&s, &res]() { -+ auto string = s.str(); -+ if(string.size() > 0) { -+ res.push_back(string.c_str()); -+ } -+ s.str(""); -+ }; -+ -+ bool seenBackslash = false; -+ const char* current = filtersString.c_str(); -+ const char* end = current + strlen(current); -+ while(current != end) { -+ char character = *current++; -+ if(seenBackslash) { -+ seenBackslash = false; -+ if(character == ',') { -+ s.put(','); -+ continue; -+ } -+ s.put('\\'); -+ } -+ if(character == '\\') { -+ seenBackslash = true; -+ } else if(character == ',') { -+ flush(); -+ } else { -+ s.put(character); -+ } -+ } -+ -+ if(seenBackslash) { -+ s.put('\\'); - } -- DOCTEST_CLANG_SUPPRESS_WARNING_POP -+ flush(); - return true; - } - return false; -@@ -5533,7 +6361,7 @@ - #define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ - if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \ - parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \ -- p->var = !!intRes; \ -+ p->var = static_cast<bool>(intRes); \ - else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \ - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \ - p->var = true; \ -@@ -5568,9 +6396,12 @@ - DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false); -+ DOCTEST_PARSE_AS_BOOL_OR_FLAG("minimal", "m", minimal, false); -+ DOCTEST_PARSE_AS_BOOL_OR_FLAG("quiet", "q", quiet, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false); -+ DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-intro", "ni", no_intro, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false); -@@ -5579,7 +6410,9 @@ - DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC)); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false); -+ DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-debug-output", "ndo", no_debug_output, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false); -+ DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false); - // clang-format on - - if(withDefaults) { -@@ -5632,9 +6465,15 @@ - curr.clear(); - } - --// allows the user to override procedurally the int/bool options from the command line -+// allows the user to override procedurally the bool options from the command line -+void Context::setOption(const char* option, bool value) { -+ setOption(option, value ? "true" : "false"); -+} -+ -+// allows the user to override procedurally the int options from the command line - void Context::setOption(const char* option, int value) { - setOption(option, toString(value).c_str()); -+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - } - - // allows the user to override procedurally the string options from the command line -@@ -5651,6 +6490,31 @@ - - void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; } - -+void Context::setCout(std::ostream* out) { p->cout = out; } -+ -+static class DiscardOStream : public std::ostream -+{ -+private: -+ class : public std::streambuf -+ { -+ private: -+ // allowing some buffering decreases the amount of calls to overflow -+ char buf[1024]; -+ -+ protected: -+ std::streamsize xsputn(const char_type*, std::streamsize count) override { return count; } -+ -+ int_type overflow(int_type ch) override { -+ setp(std::begin(buf), std::end(buf)); -+ return traits_type::not_eof(ch); -+ } -+ } discardBuf; -+ -+public: -+ DiscardOStream() -+ : std::ostream(&discardBuf) {} -+} discardOut; -+ - // the main function that does all the filtering and test running - int Context::run() { - using namespace detail; -@@ -5664,18 +6528,25 @@ - g_no_colors = p->no_colors; - p->resetRunData(); - -- // stdout by default -- p->cout = &std::cout; -- p->cerr = &std::cerr; -- -- // or to a file if specified - std::fstream fstr; -- if(p->out.size()) { -- fstr.open(p->out.c_str(), std::fstream::out); -- p->cout = &fstr; -+ if(p->cout == nullptr) { -+ if(p->quiet) { -+ p->cout = &discardOut; -+ } else if(p->out.size()) { -+ // to a file if specified -+ fstr.open(p->out.c_str(), std::fstream::out); -+ p->cout = &fstr; -+ } else { -+ // stdout by default -+ p->cout = &std::cout; -+ } - } - -+ FatalConditionHandler::allocateAltStackMem(); -+ - auto cleanup_and_return = [&]() { -+ FatalConditionHandler::freeAltStackMem(); -+ - if(fstr.is_open()) - fstr.close(); - -@@ -5710,7 +6581,7 @@ - p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs)); - - #ifdef DOCTEST_PLATFORM_WINDOWS -- if(isDebuggerActive()) -+ if(isDebuggerActive() && p->no_debug_output == false) - p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs)); - #endif // DOCTEST_PLATFORM_WINDOWS - -@@ -5747,13 +6618,16 @@ - first[i] = first[idxToSwap]; - first[idxToSwap] = temp; - } -+ } else if(p->order_by.compare("none", true) == 0) { -+ // means no sorting - beneficial for death tests which call into the executable -+ // with a specific test case in mind - we don't want to slow down the startup times - } - } - - std::set<String> testSuitesPassingFilt; - -- bool query_mode = p->count || p->list_test_cases || p->list_test_suites; -- std::vector<String> queryResults; -+ bool query_mode = p->count || p->list_test_cases || p->list_test_suites; -+ std::vector<const TestCaseData*> queryResults; - - if(!query_mode) - DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY); -@@ -5766,9 +6640,9 @@ - if(tc.m_skip && !p->no_skip) - skip_me = true; - -- if(!matchesAny(tc.m_file, p->filters[0], true, p->case_sensitive)) -+ if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive)) - skip_me = true; -- if(matchesAny(tc.m_file, p->filters[1], false, p->case_sensitive)) -+ if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive)) - skip_me = true; - if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive)) - skip_me = true; -@@ -5799,14 +6673,14 @@ - - // print the name of the test and don't execute it - if(p->list_test_cases) { -- queryResults.push_back(tc.m_name); -+ queryResults.push_back(&tc); - continue; - } - - // print the name of the test suite if not done already and don't execute it - if(p->list_test_suites) { - if((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') { -- queryResults.push_back(tc.m_test_suite); -+ queryResults.push_back(&tc); - testSuitesPassingFilt.insert(tc.m_test_suite); - p->numTestSuitesPassingFilters++; - } -@@ -5829,12 +6703,16 @@ - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); - - p->timer.start(); -+ -+ bool run_test = true; - - do { - // reset some of the fields for subcases (except for the set of fully passed ones) -- p->should_reenter = false; -- p->subcasesCurrentLevel = 0; -- p->subcasesEnteredLevels.clear(); -+ p->should_reenter = false; -+ p->subcasesCurrentMaxLevel = 0; -+ p->subcasesStack.clear(); -+ -+ p->shouldLogCurrentException = true; - - // reset stuff for logging with INFO() - p->stringifiedContexts.clear(); -@@ -5842,10 +6720,13 @@ - #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - try { - #endif // DOCTEST_CONFIG_NO_EXCEPTIONS -+// MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method) -+DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable - FatalConditionHandler fatalConditionHandler; // Handle signals - // execute the test - tc.m_test(); - fatalConditionHandler.reset(); -+DOCTEST_MSVC_SUPPRESS_WARNING_POP - #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - } catch(const TestFailureException&) { - p->failure_flags |= TestCaseFailureReason::AssertFailure; -@@ -5859,10 +6740,15 @@ - // exit this loop if enough assertions have failed - even if there are more subcases - if(p->abort_after > 0 && - p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) { -- p->should_reenter = false; -+ run_test = false; - p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts; - } -- } while(p->should_reenter == true); -+ -+ if(p->should_reenter && run_test) -+ DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); -+ if(!p->should_reenter) -+ run_test = false; -+ } while(run_test); - - p->finalizeTestCaseData(); - -@@ -5886,20 +6772,9 @@ - DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); - } - -- // see these issues on the reasoning for this: -- // - https://github.com/onqtam/doctest/issues/143#issuecomment-414418903 -- // - https://github.com/onqtam/doctest/issues/126 -- auto DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS = []() DOCTEST_NOINLINE -- { std::cout << std::string(); }; -- DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS(); -- - return cleanup_and_return(); - } - --DOCTEST_DEFINE_DEFAULTS(CurrentTestCaseStats); -- --DOCTEST_DEFINE_DEFAULTS(TestRunStats); -- - IReporter::~IReporter() = default; - - int IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); } -@@ -5935,5 +6810,7 @@ - DOCTEST_MSVC_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - -+DOCTEST_SUPPRESS_COMMON_WARNINGS_POP -+ - #endif // DOCTEST_LIBRARY_IMPLEMENTATION - #endif // DOCTEST_CONFIG_IMPLEMENT |