xref: /oneTBB/test/common/doctest.h (revision 68e075cb)
1 /*
2     Modifications Copyright (c) 2020-2021 Intel Corporation
3     Modifications Licensed under the Apache License, Version 2.0;
4     You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
5 */
6 
7 // ====================================================================== lgtm [cpp/missing-header-guard]
8 // == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! ==
9 // ======================================================================
10 //
11 // doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD
12 //
13 // Copyright (c) 2016-2021 Viktor Kirilov
14 //
15 // Distributed under the MIT Software License
16 // See accompanying file LICENSE.txt or copy at
17 // https://opensource.org/licenses/MIT
18 //
19 // The documentation can be found at the library's page:
20 // https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md
21 //
22 // =================================================================================================
23 // =================================================================================================
24 // =================================================================================================
25 //
26 // The library is heavily influenced by Catch - https://github.com/catchorg/Catch2
27 // which uses the Boost Software License - Version 1.0
28 // see here - https://github.com/catchorg/Catch2/blob/master/LICENSE.txt
29 //
30 // The concept of subcases (sections in Catch) and expression decomposition are from there.
31 // Some parts of the code are taken directly:
32 // - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<>
33 // - the Approx() helper class for floating point comparison
34 // - colors in the console
35 // - breaking into a debugger
36 // - signal / SEH handling
37 // - timer
38 // - XmlWriter class - thanks to Phil Nash for allowing the direct reuse (AKA copy/paste)
39 //
40 // The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest
41 // which uses the Boost Software License - Version 1.0
42 // see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt
43 //
44 // =================================================================================================
45 // =================================================================================================
46 // =================================================================================================
47 
48 #ifndef DOCTEST_LIBRARY_INCLUDED
49 #define DOCTEST_LIBRARY_INCLUDED
50 
51 // =================================================================================================
52 // == VERSION ======================================================================================
53 // =================================================================================================
54 
55 #define DOCTEST_VERSION_MAJOR 2
56 #define DOCTEST_VERSION_MINOR 4
57 #define DOCTEST_VERSION_PATCH 6
58 #define DOCTEST_VERSION_STR "2.4.6"
59 
60 #define DOCTEST_VERSION                                                                            \
61     (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH)
62 
63 // =================================================================================================
64 // == COMPILER VERSION =============================================================================
65 // =================================================================================================
66 
67 // ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect
68 
69 #define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH))
70 
71 // GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl...
72 #if defined(_MSC_VER) && defined(_MSC_FULL_VER)
73 #if _MSC_VER == _MSC_FULL_VER / 10000
74 #define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000)
75 #else // MSVC
76 #define DOCTEST_MSVC                                                                               \
77     DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000)
78 #endif // MSVC
79 #endif // MSVC
80 #if defined(__clang__) && defined(__clang_minor__)
81 #define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__)
82 #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) &&              \
83         !defined(__INTEL_COMPILER)
84 #define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
85 #endif // GCC
86 // TODO: upstream the change to doctest : Intel Compiler support
87 #if defined(__INTEL_COMPILER)
88 #define DOCTEST_ICC DOCTEST_COMPILER(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER % 10000)
89 #endif // ICC
90 
91 #ifndef DOCTEST_MSVC
92 #define DOCTEST_MSVC 0
93 #endif // DOCTEST_MSVC
94 #ifndef DOCTEST_CLANG
95 #define DOCTEST_CLANG 0
96 #endif // DOCTEST_CLANG
97 #ifndef DOCTEST_GCC
98 #define DOCTEST_GCC 0
99 #endif // DOCTEST_GCC
100 #ifndef DOCTEST_ICC
101 #define DOCTEST_ICC 0
102 #endif // DOCTEST_ICC
103 
104 // =================================================================================================
105 // == COMPILER WARNINGS HELPERS ====================================================================
106 // =================================================================================================
107 
108 #if DOCTEST_CLANG && !DOCTEST_ICC
109 #define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x)
110 #define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push")
111 #define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w)
112 #define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop")
113 #define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w)                                                \
114     DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w)
115 #else // DOCTEST_CLANG
116 #define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
117 #define DOCTEST_CLANG_SUPPRESS_WARNING(w)
118 #define DOCTEST_CLANG_SUPPRESS_WARNING_POP
119 #define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w)
120 #endif // DOCTEST_CLANG
121 
122 #if DOCTEST_GCC
123 #define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x)
124 #define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push")
125 #define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w)
126 #define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop")
127 #define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w)                                                  \
128     DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w)
129 #else // DOCTEST_GCC
130 #define DOCTEST_GCC_SUPPRESS_WARNING_PUSH
131 #define DOCTEST_GCC_SUPPRESS_WARNING(w)
132 #define DOCTEST_GCC_SUPPRESS_WARNING_POP
133 #define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w)
134 #endif // DOCTEST_GCC
135 
136 #if DOCTEST_MSVC
137 #define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push))
138 #define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w))
139 #define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop))
140 #define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w)                                                 \
141     DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w)
142 #else // DOCTEST_MSVC
143 #define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
144 #define DOCTEST_MSVC_SUPPRESS_WARNING(w)
145 #define DOCTEST_MSVC_SUPPRESS_WARNING_POP
146 #define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w)
147 #endif // DOCTEST_MSVC
148 
149 // =================================================================================================
150 // == COMPILER WARNINGS ============================================================================
151 // =================================================================================================
152 
153 DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
154 DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas")
155 DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor")
156 DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables")
157 DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded")
158 DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated")
159 DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes")
160 DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef")
161 DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
162 DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
163 
164 DOCTEST_GCC_SUPPRESS_WARNING_PUSH
165 DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas")
166 DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas")
167 DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++")
168 DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow")
169 DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing")
170 DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy")
171 DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations")
172 DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor")
173 DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs")
174 DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast")
175 DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept")
176 DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo")
177 
178 DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
179 DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning
180 DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning
181 DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration
182 DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression
183 DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated
184 DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant
185 DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding
186 DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted
187 DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted
188 DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted
189 DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted
190 DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted
191 DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe
192 // static analysis
193 DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept'
194 DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable
195 DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ...
196 DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtr...
197 DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum'
198 
199 // 4548 - expression before comma has no effect; expected expression with side - effect
200 // 4265 - class has virtual functions, but destructor is not virtual
201 // 4986 - exception specification does not match previous declaration
202 // 4350 - behavior change: 'member1' called instead of 'member2'
203 // 4668 - 'x' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
204 // 4365 - conversion from 'int' to 'unsigned long', signed/unsigned mismatch
205 // 4774 - format string expected in argument 'x' is not a string literal
206 // 4820 - padding in structs
207 
208 // only 4 should be disabled globally:
209 // - 4514 # unreferenced inline function has been removed
210 // - 4571 # SEH related
211 // - 4710 # function not inlined
212 // - 4711 # function 'x' selected for automatic inline expansion
213 
214 #define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN                                 \
215     DOCTEST_MSVC_SUPPRESS_WARNING_PUSH                                                             \
216     DOCTEST_MSVC_SUPPRESS_WARNING(4548)                                                            \
217     DOCTEST_MSVC_SUPPRESS_WARNING(4265)                                                            \
218     DOCTEST_MSVC_SUPPRESS_WARNING(4986)                                                            \
219     DOCTEST_MSVC_SUPPRESS_WARNING(4350)                                                            \
220     DOCTEST_MSVC_SUPPRESS_WARNING(4668)                                                            \
221     DOCTEST_MSVC_SUPPRESS_WARNING(4365)                                                            \
222     DOCTEST_MSVC_SUPPRESS_WARNING(4774)                                                            \
223     DOCTEST_MSVC_SUPPRESS_WARNING(4820)                                                            \
224     DOCTEST_MSVC_SUPPRESS_WARNING(4625)                                                            \
225     DOCTEST_MSVC_SUPPRESS_WARNING(4626)                                                            \
226     DOCTEST_MSVC_SUPPRESS_WARNING(5027)                                                            \
227     DOCTEST_MSVC_SUPPRESS_WARNING(5026)                                                            \
228     DOCTEST_MSVC_SUPPRESS_WARNING(4623)                                                            \
229     DOCTEST_MSVC_SUPPRESS_WARNING(5039)                                                            \
230     DOCTEST_MSVC_SUPPRESS_WARNING(5045)                                                            \
231     DOCTEST_MSVC_SUPPRESS_WARNING(5105)
232 
233 #define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP
234 
235 // =================================================================================================
236 // == FEATURE DETECTION ============================================================================
237 // =================================================================================================
238 
239 // general compiler feature support table: https://en.cppreference.com/w/cpp/compiler_support
240 // MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx
241 // GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html
242 // MSVC version table:
243 // https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering
244 // MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019)
245 // MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017)
246 // MSVC++ 14.0      _MSC_VER == 1900 (Visual Studio 2015)
247 // MSVC++ 12.0      _MSC_VER == 1800 (Visual Studio 2013)
248 // MSVC++ 11.0      _MSC_VER == 1700 (Visual Studio 2012)
249 // MSVC++ 10.0      _MSC_VER == 1600 (Visual Studio 2010)
250 // MSVC++ 9.0       _MSC_VER == 1500 (Visual Studio 2008)
251 // MSVC++ 8.0       _MSC_VER == 1400 (Visual Studio 2005)
252 
253 #if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH)
254 #define DOCTEST_CONFIG_WINDOWS_SEH
255 #endif // MSVC
256 #if defined(DOCTEST_CONFIG_NO_WINDOWS_SEH) && defined(DOCTEST_CONFIG_WINDOWS_SEH)
257 #undef DOCTEST_CONFIG_WINDOWS_SEH
258 #endif // DOCTEST_CONFIG_NO_WINDOWS_SEH
259 
260 #if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) &&             \
261         !defined(__EMSCRIPTEN__)
262 #define DOCTEST_CONFIG_POSIX_SIGNALS
263 #endif // _WIN32
264 #if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS)
265 #undef DOCTEST_CONFIG_POSIX_SIGNALS
266 #endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS
267 
268 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
269 #if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)
270 #define DOCTEST_CONFIG_NO_EXCEPTIONS
271 #endif // no exceptions
272 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
273 
274 #ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS
275 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
276 #define DOCTEST_CONFIG_NO_EXCEPTIONS
277 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
278 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS
279 
280 #if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS)
281 #define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
282 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
283 
284 #if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT)
285 #define DOCTEST_CONFIG_IMPLEMENT
286 #endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
287 
288 #if defined(_WIN32) || defined(__CYGWIN__)
289 #if DOCTEST_MSVC
290 #define DOCTEST_SYMBOL_EXPORT __declspec(dllexport)
291 #define DOCTEST_SYMBOL_IMPORT __declspec(dllimport)
292 #else // MSVC
293 #define DOCTEST_SYMBOL_EXPORT __attribute__((dllexport))
294 #define DOCTEST_SYMBOL_IMPORT __attribute__((dllimport))
295 #endif // MSVC
296 #else  // _WIN32
297 #define DOCTEST_SYMBOL_EXPORT __attribute__((visibility("default")))
298 #define DOCTEST_SYMBOL_IMPORT
299 #endif // _WIN32
300 
301 #ifdef DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL
302 #ifdef DOCTEST_CONFIG_IMPLEMENT
303 #define DOCTEST_INTERFACE DOCTEST_SYMBOL_EXPORT
304 #else // DOCTEST_CONFIG_IMPLEMENT
305 #define DOCTEST_INTERFACE DOCTEST_SYMBOL_IMPORT
306 #endif // DOCTEST_CONFIG_IMPLEMENT
307 #else  // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL
308 #define DOCTEST_INTERFACE
309 #endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL
310 
311 #define DOCTEST_EMPTY
312 
313 #if DOCTEST_MSVC
314 #define DOCTEST_NOINLINE __declspec(noinline)
315 #define DOCTEST_UNUSED
316 #define DOCTEST_ALIGNMENT(x)
317 #elif DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 5, 0)
318 #define DOCTEST_NOINLINE
319 #define DOCTEST_UNUSED
320 #define DOCTEST_ALIGNMENT(x)
321 #else
322 #define DOCTEST_NOINLINE __attribute__((noinline))
323 #define DOCTEST_UNUSED __attribute__((unused))
324 #define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x)))
325 #endif
326 // TODO: upstream the change to doctest : Work-around for the warning: 'routine is both "inline" and "noinline"'
327 #if DOCTEST_ICC
328 #undef DOCTEST_NOINLINE
329 #define DOCTEST_NOINLINE
330 #endif // ICC
331 
332 #ifndef DOCTEST_NORETURN
333 #define DOCTEST_NORETURN [[noreturn]]
334 #endif // DOCTEST_NORETURN
335 
336 #ifndef DOCTEST_NOEXCEPT
337 #define DOCTEST_NOEXCEPT noexcept
338 #endif // DOCTEST_NOEXCEPT
339 
340 // =================================================================================================
341 // == FEATURE DETECTION END ========================================================================
342 // =================================================================================================
343 
344 // internal macros for string concatenation and anonymous variable name generation
345 #define DOCTEST_CAT_IMPL(s1, s2) s1##s2
346 #define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2)
347 #ifdef __COUNTER__ // not standard and may be missing for some compilers
348 #define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__)
349 #else // __COUNTER__
350 #define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__)
351 #endif // __COUNTER__
352 
353 #define DOCTEST_TOSTR(x) #x
354 
355 #ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE
356 #define DOCTEST_REF_WRAP(x) x&
357 #else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE
358 #define DOCTEST_REF_WRAP(x) x
359 #endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE
360 
361 // not using __APPLE__ because... this is how Catch does it
362 #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
363 #define DOCTEST_PLATFORM_MAC
364 #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
365 #define DOCTEST_PLATFORM_IPHONE
366 #elif defined(_WIN32)
367 #define DOCTEST_PLATFORM_WINDOWS
368 #else // DOCTEST_PLATFORM
369 #define DOCTEST_PLATFORM_LINUX
370 #endif // DOCTEST_PLATFORM
371 
372 // TODO: upstream the change to doctest : make variable volatile to suppress unused warning
373 #define DOCTEST_GLOBAL_NO_WARNINGS(var)                                                            \
374     DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors")                              \
375     DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable")                                            \
376     static volatile int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp)
377 #define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP
378 
379 #ifndef DOCTEST_BREAK_INTO_DEBUGGER
380 // should probably take a look at https://github.com/scottt/debugbreak
381 #ifdef DOCTEST_PLATFORM_LINUX
382 #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
383 // Break at the location of the failing check if possible
384 #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler)
385 #else
386 #include <signal.h>
387 #define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP)
388 #endif
389 #elif defined(DOCTEST_PLATFORM_MAC)
390 #if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386)
391 #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler)
392 #else
393 #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT (hicpp-no-assembler)
394 #endif
395 #elif DOCTEST_MSVC
396 #define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak()
397 #elif defined(__MINGW32__)
398 DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wredundant-decls")
399 extern "C" __declspec(dllimport) void __stdcall DebugBreak();
400 DOCTEST_GCC_SUPPRESS_WARNING_POP
401 #define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak()
402 #else // linux
403 #define DOCTEST_BREAK_INTO_DEBUGGER() (static_cast<void>(0))
404 #endif // linux
405 #endif // DOCTEST_BREAK_INTO_DEBUGGER
406 
407 // this is kept here for backwards compatibility since the config option was changed
408 #ifdef DOCTEST_CONFIG_USE_IOSFWD
409 #define DOCTEST_CONFIG_USE_STD_HEADERS
410 #endif // DOCTEST_CONFIG_USE_IOSFWD
411 
412 #ifdef DOCTEST_CONFIG_USE_STD_HEADERS
413 #ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
414 #define DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
415 #endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
416 #include <iosfwd>
417 #include <cstddef>
418 #include <ostream>
419 #else // DOCTEST_CONFIG_USE_STD_HEADERS
420 
421 #if DOCTEST_CLANG
422 // to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier)
423 #include <ciso646>
424 #endif // clang
425 
426 #ifdef _LIBCPP_VERSION
427 #define DOCTEST_STD_NAMESPACE_BEGIN _LIBCPP_BEGIN_NAMESPACE_STD
428 #define DOCTEST_STD_NAMESPACE_END _LIBCPP_END_NAMESPACE_STD
429 #else // _LIBCPP_VERSION
430 #define DOCTEST_STD_NAMESPACE_BEGIN namespace std {
431 #define DOCTEST_STD_NAMESPACE_END }
432 #endif // _LIBCPP_VERSION
433 
434 // Forward declaring 'X' in namespace std is not permitted by the C++ Standard.
435 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643)
436 
437 DOCTEST_STD_NAMESPACE_BEGIN // NOLINT (cert-dcl58-cpp)
438 typedef decltype(nullptr) nullptr_t;
439 template <class charT>
440 struct char_traits;
441 template <>
442 struct char_traits<char>;
443 template <class charT, class traits>
444 class basic_ostream;
445 typedef basic_ostream<char, char_traits<char>> ostream;
446 template <class... Types>
447 class tuple;
448 #if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
449 // see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183
450 template <class _Ty>
451 class allocator;
452 template <class _Elem, class _Traits, class _Alloc>
453 class basic_string;
454 using string = basic_string<char, char_traits<char>, allocator<char>>;
455 #endif // VS 2019
456 DOCTEST_STD_NAMESPACE_END
457 
458 DOCTEST_MSVC_SUPPRESS_WARNING_POP
459 
460 #endif // DOCTEST_CONFIG_USE_STD_HEADERS
461 
462 #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
463 #include <type_traits>
464 #endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
465 
466 namespace doctest {
467 
468 DOCTEST_INTERFACE extern bool is_running_in_test;
469 
470 #if _MSC_VER
471 // TODO: upstream the change to doctest :
472 // Due to race between exiting the process and starting of a new detached thread in Windows, thread
473 // local variables, which constructors or destructors have calls to runtime functions (e.g. free()
474 // function) can cause access violation since TBB along with runtime library may have been unloaded
475 // by the time these variables are constructed or destroyed. The workaround is do not call constructors
476 // and/or destructors for such variables if they are not used.
477 template <typename T>
478 struct doctest_thread_local_wrapper {
479     doctest_thread_local_wrapper() {
480         // Default definition is ill-formed in case of non-trivial type T.
481     }
482     T& get() {
483         if( !initialized ) {
484             new(&value) T;
485             initialized = true;
486         }
487         return value;
488     }
489     ~doctest_thread_local_wrapper() {
490         if( initialized )
491             value.~T();
492     }
493 private:
494     union { T value; };
495     bool initialized = false;
496 };
497 #else  // _MSC_VER
498 template <typename T>
499 struct doctest_thread_local_wrapper {
500     T& get() { return value; }
501 private:
502     T value{};
503 };
504 #endif // _MSC_VER
505 
506 // A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length
507 // of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for:
508 // - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128)
509 // - if small - capacity left before going on the heap - using the lowest 5 bits
510 // - if small - 2 bits are left unused - the second and third highest ones
511 // - if small - acts as a null terminator if strlen() is 23 (24 including the null terminator)
512 //              and the "is small" bit remains "0" ("as well as the capacity left") so its OK
513 // Idea taken from this lecture about the string implementation of facebook/folly - fbstring
514 // https://www.youtube.com/watch?v=kPR8h4-qZdk
515 // TODO:
516 // - optimizations - like not deleting memory unnecessarily in operator= and etc.
517 // - resize/reserve/clear
518 // - substr
519 // - replace
520 // - back/front
521 // - iterator stuff
522 // - find & friends
523 // - push_back/pop_back
524 // - assign/insert/erase
525 // - relational operators as free functions - taking const char* as one of the params
526 class DOCTEST_INTERFACE String
527 {
528     static const unsigned len  = 24;      //!OCLINT avoid private static members
529     static const unsigned last = len - 1; //!OCLINT avoid private static members
530 
531     struct view // len should be more than sizeof(view) - because of the final byte for flags
532     {
533         char*    ptr;
534         unsigned size;
535         unsigned capacity;
536     };
537 
538     union
539     {
540         char buf[len];
541         view data;
542     };
543 
544     bool isOnStack() const { return (buf[last] & 128) == 0; }
545     void setOnHeap();
546     void setLast(unsigned in = last);
547 
548     void copy(const String& other);
549 
550 public:
551     String();
552     ~String();
553 
554     // cppcheck-suppress noExplicitConstructor
555     String(const char* in);
556     String(const char* in, unsigned in_size);
557 
558     String(const String& other);
559     String& operator=(const String& other);
560 
561     String& operator+=(const String& other);
562     String  operator+(const String& other) const;
563 
564     String(String&& other);
565     String& operator=(String&& other);
566 
567     char  operator[](unsigned i) const;
568     char& operator[](unsigned i);
569 
570     // the only functions I'm willing to leave in the interface - available for inlining
571     const char* c_str() const { return const_cast<String*>(this)->c_str(); } // NOLINT
572     char*       c_str() {
573         if(isOnStack())
574             return reinterpret_cast<char*>(buf);
575         return data.ptr;
576     }
577 
578     unsigned size() const;
579     unsigned capacity() const;
580 
581     int compare(const char* other, bool no_case = false) const;
582     int compare(const String& other, bool no_case = false) const;
583 };
584 
585 DOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs);
586 DOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs);
587 DOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs);
588 DOCTEST_INTERFACE bool operator>(const String& lhs, const String& rhs);
589 DOCTEST_INTERFACE bool operator<=(const String& lhs, const String& rhs);
590 DOCTEST_INTERFACE bool operator>=(const String& lhs, const String& rhs);
591 
592 DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in);
593 
594 namespace Color {
595     enum Enum
596     {
597         None = 0,
598         White,
599         Red,
600         Green,
601         Blue,
602         Cyan,
603         Yellow,
604         Grey,
605 
606         Bright = 0x10,
607 
608         BrightRed   = Bright | Red,
609         BrightGreen = Bright | Green,
610         LightGrey   = Bright | Grey,
611         BrightWhite = Bright | White
612     };
613 
614     DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, Color::Enum code);
615 } // namespace Color
616 
617 namespace assertType {
618     enum Enum
619     {
620         // macro traits
621 
622         is_warn    = 1,
623         is_check   = 2 * is_warn,
624         is_require = 2 * is_check,
625 
626         is_normal      = 2 * is_require,
627         is_throws      = 2 * is_normal,
628         is_throws_as   = 2 * is_throws,
629         is_throws_with = 2 * is_throws_as,
630         is_nothrow     = 2 * is_throws_with,
631 
632         is_false = 2 * is_nothrow,
633         is_unary = 2 * is_false, // not checked anywhere - used just to distinguish the types
634 
635         is_eq = 2 * is_unary,
636         is_ne = 2 * is_eq,
637 
638         is_lt = 2 * is_ne,
639         is_gt = 2 * is_lt,
640 
641         is_ge = 2 * is_gt,
642         is_le = 2 * is_ge,
643 
644         // macro types
645 
646         DT_WARN    = is_normal | is_warn,
647         DT_CHECK   = is_normal | is_check,
648         DT_REQUIRE = is_normal | is_require,
649 
650         DT_WARN_FALSE    = is_normal | is_false | is_warn,
651         DT_CHECK_FALSE   = is_normal | is_false | is_check,
652         DT_REQUIRE_FALSE = is_normal | is_false | is_require,
653 
654         DT_WARN_THROWS    = is_throws | is_warn,
655         DT_CHECK_THROWS   = is_throws | is_check,
656         DT_REQUIRE_THROWS = is_throws | is_require,
657 
658         DT_WARN_THROWS_AS    = is_throws_as | is_warn,
659         DT_CHECK_THROWS_AS   = is_throws_as | is_check,
660         DT_REQUIRE_THROWS_AS = is_throws_as | is_require,
661 
662         DT_WARN_THROWS_WITH    = is_throws_with | is_warn,
663         DT_CHECK_THROWS_WITH   = is_throws_with | is_check,
664         DT_REQUIRE_THROWS_WITH = is_throws_with | is_require,
665 
666         DT_WARN_THROWS_WITH_AS    = is_throws_with | is_throws_as | is_warn,
667         DT_CHECK_THROWS_WITH_AS   = is_throws_with | is_throws_as | is_check,
668         DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require,
669 
670         DT_WARN_NOTHROW    = is_nothrow | is_warn,
671         DT_CHECK_NOTHROW   = is_nothrow | is_check,
672         DT_REQUIRE_NOTHROW = is_nothrow | is_require,
673 
674         DT_WARN_EQ    = is_normal | is_eq | is_warn,
675         DT_CHECK_EQ   = is_normal | is_eq | is_check,
676         DT_REQUIRE_EQ = is_normal | is_eq | is_require,
677 
678         DT_WARN_NE    = is_normal | is_ne | is_warn,
679         DT_CHECK_NE   = is_normal | is_ne | is_check,
680         DT_REQUIRE_NE = is_normal | is_ne | is_require,
681 
682         DT_WARN_GT    = is_normal | is_gt | is_warn,
683         DT_CHECK_GT   = is_normal | is_gt | is_check,
684         DT_REQUIRE_GT = is_normal | is_gt | is_require,
685 
686         DT_WARN_LT    = is_normal | is_lt | is_warn,
687         DT_CHECK_LT   = is_normal | is_lt | is_check,
688         DT_REQUIRE_LT = is_normal | is_lt | is_require,
689 
690         DT_WARN_GE    = is_normal | is_ge | is_warn,
691         DT_CHECK_GE   = is_normal | is_ge | is_check,
692         DT_REQUIRE_GE = is_normal | is_ge | is_require,
693 
694         DT_WARN_LE    = is_normal | is_le | is_warn,
695         DT_CHECK_LE   = is_normal | is_le | is_check,
696         DT_REQUIRE_LE = is_normal | is_le | is_require,
697 
698         DT_WARN_UNARY    = is_normal | is_unary | is_warn,
699         DT_CHECK_UNARY   = is_normal | is_unary | is_check,
700         DT_REQUIRE_UNARY = is_normal | is_unary | is_require,
701 
702         DT_WARN_UNARY_FALSE    = is_normal | is_false | is_unary | is_warn,
703         DT_CHECK_UNARY_FALSE   = is_normal | is_false | is_unary | is_check,
704         DT_REQUIRE_UNARY_FALSE = is_normal | is_false | is_unary | is_require,
705     };
706 } // namespace assertType
707 
708 DOCTEST_INTERFACE const char* assertString(assertType::Enum at);
709 DOCTEST_INTERFACE const char* failureString(assertType::Enum at);
710 DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file);
711 
712 struct DOCTEST_INTERFACE TestCaseData
713 {
714     String      m_file;       // the file in which the test was registered (using String - see #350)
715     unsigned    m_line;       // the line where the test was registered
716     const char* m_name;       // name of the test case
717     const char* m_test_suite; // the test suite in which the test was added
718     const char* m_description;
719     bool        m_skip;
720     bool        m_no_breaks;
721     bool        m_no_output;
722     bool        m_may_fail;
723     bool        m_should_fail;
724     int         m_expected_failures;
725     double      m_timeout;
726 };
727 
728 struct DOCTEST_INTERFACE AssertData
729 {
730     // common - for all asserts
731     const TestCaseData* m_test_case;
732     assertType::Enum    m_at;
733     const char*         m_file;
734     int                 m_line;
735     const char*         m_expr;
736     bool                m_failed;
737 
738     // exception-related - for all asserts
739     bool   m_threw;
740     String m_exception;
741 
742     // for normal asserts
743     String m_decomp;
744 
745     // for specific exception-related asserts
746     bool        m_threw_as;
747     const char* m_exception_type;
748     const char* m_exception_string;
749 };
750 
751 struct DOCTEST_INTERFACE MessageData
752 {
753     String           m_string;
754     const char*      m_file;
755     int              m_line;
756     assertType::Enum m_severity;
757 };
758 
759 struct DOCTEST_INTERFACE SubcaseSignature
760 {
761     String      m_name;
762     const char* m_file;
763     int         m_line;
764 
765     bool operator<(const SubcaseSignature& other) const;
766 };
767 
768 struct DOCTEST_INTERFACE IContextScope
769 {
770     IContextScope();
771     virtual ~IContextScope();
772     virtual void stringify(std::ostream*) const = 0;
773 };
774 
775 namespace detail {
776     struct DOCTEST_INTERFACE TestCase;
777 } // namespace detail
778 
779 struct ContextOptions //!OCLINT too many fields
780 {
781     std::ostream* cout;        // stdout stream - std::cout by default
782     std::ostream* cerr;        // stderr stream - std::cerr by default
783     String        binary_name; // the test binary name
784 
785     const detail::TestCase* currentTest = nullptr;
786 
787     // == parameters from the command line
788     String   out;       // output filename
789     String   order_by;  // how tests should be ordered
790     unsigned rand_seed; // the seed for rand ordering
791 
792     unsigned first; // the first (matching) test to be executed
793     unsigned last;  // the last (matching) test to be executed
794 
795     int abort_after;           // stop tests after this many failed assertions
796     int subcase_filter_levels; // apply the subcase filters for the first N levels
797 
798     bool success;              // include successful assertions in output
799     bool case_sensitive;       // if filtering should be case sensitive
800     bool exit;                 // if the program should be exited after the tests are ran/whatever
801     bool duration;             // print the time duration of each test case
802     bool no_throw;             // to skip exceptions-related assertion macros
803     bool no_exitcode;          // if the framework should return 0 as the exitcode
804     bool no_run;               // to not run the tests at all (can be done with an "*" exclude)
805     bool no_version;           // to not print the version of the framework
806     bool no_colors;            // if output to the console should be colorized
807     bool force_colors;         // forces the use of colors even when a tty cannot be detected
808     bool no_breaks;            // to not break into the debugger
809     bool no_skip;              // don't skip test cases which are marked to be skipped
810     bool gnu_file_line;        // if line numbers should be surrounded with :x: and not (x):
811     bool no_path_in_filenames; // if the path to files should be removed from the output
812     bool no_line_numbers;      // if source code line numbers should be omitted from the output
813     bool no_debug_output;      // no output in the debug console when a debugger is attached
814     bool no_skipped_summary;   // don't print "skipped" in the summary !!! UNDOCUMENTED !!!
815     bool no_time_in_output;    // omit any time/timestamps from output !!! UNDOCUMENTED !!!
816 
817     bool help;             // to print the help
818     bool version;          // to print the version
819     bool count;            // if only the count of matching tests is to be retrieved
820     bool list_test_cases;  // to list all tests matching the filters
821     bool list_test_suites; // to list all suites matching the filters
822     bool list_reporters;   // lists all registered reporters
823 };
824 
825 namespace detail {
826     template <bool CONDITION, typename TYPE = void>
827     struct enable_if
828     {};
829 
830     template <typename TYPE>
831     struct enable_if<true, TYPE>
832     { typedef TYPE type; };
833 
834     // clang-format off
835     template<class T> struct remove_reference      { typedef T type; };
836     template<class T> struct remove_reference<T&>  { typedef T type; };
837     template<class T> struct remove_reference<T&&> { typedef T type; };
838 
839     template<typename T, typename U = T&&> U declval(int);
840 
841     template<typename T> T declval(long);
842 
843     template<typename T> auto declval() DOCTEST_NOEXCEPT -> decltype(declval<T>(0)) ;
844 
845     // TODO: upstream the change to doctest : fix "storage class is not first" warning
846     template<class T> struct is_lvalue_reference { static const bool value=false; };
847     template<class T> struct is_lvalue_reference<T&> { static const bool value=true; };
848 
849     template <class T>
850     inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT
851     {
852         return static_cast<T&&>(t);
853     }
854 
855     template <class T>
856     inline T&& forward(typename remove_reference<T>::type&& t) DOCTEST_NOEXCEPT
857     {
858         static_assert(!is_lvalue_reference<T>::value,
859                         "Can not forward an rvalue as an lvalue.");
860         return static_cast<T&&>(t);
861     }
862 
863     template<class T> struct remove_const          { typedef T type; };
864     template<class T> struct remove_const<const T> { typedef T type; };
865 #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
866     template<class T> struct is_enum : public std::is_enum<T> {};
867     template<class T> struct underlying_type : public std::underlying_type<T> {};
868 #else
869     // Use compiler intrinsics
870     template<class T> struct is_enum { constexpr static bool value = __is_enum(T); };
871     template<class T> struct underlying_type { typedef __underlying_type(T) type; };
872 #endif
873     // clang-format on
874 
875     template <typename T>
876     struct deferred_false
877     // cppcheck-suppress unusedStructMember
878     { static const bool value = false; };
879 
880     namespace has_insertion_operator_impl {
881         std::ostream &os();
882         template<class T>
883         DOCTEST_REF_WRAP(T) val();
884 
885         template<class, class = void>
886         struct check {
887             static constexpr bool value = false;
888         };
889 
890         template<class T>
891         struct check<T, decltype(os() << val<T>(), void())> {
892             static constexpr bool value = true;
893         };
894     } // namespace has_insertion_operator_impl
895 
896     template<class T>
897     using has_insertion_operator = has_insertion_operator_impl::check<const T>;
898 
899     DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned num);
900 
901     DOCTEST_INTERFACE std::ostream* getTlsOss(); // returns a thread-local ostringstream
902     DOCTEST_INTERFACE String getTlsOssResult();
903 
904     template <bool C>
905     struct StringMakerBase
906     {
907         template <typename T>
908         static String convert(const DOCTEST_REF_WRAP(T)) {
909             return "{?}";
910         }
911     };
912 
913     template <>
914     struct StringMakerBase<true>
915     {
916         template <typename T>
917         static String convert(const DOCTEST_REF_WRAP(T) in) {
918             *getTlsOss() << in;
919             return getTlsOssResult();
920         }
921     };
922 
923     DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size);
924 
925     template <typename T>
926     String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) {
927         return rawMemoryToString(&object, sizeof(object));
928     }
929 
930     template <typename T>
931     const char* type_to_string() {
932         return "<>";
933     }
934 } // namespace detail
935 
936 template <typename T>
937 struct StringMaker : public detail::StringMakerBase<detail::has_insertion_operator<T>::value>
938 {};
939 
940 template <typename T>
941 struct StringMaker<T*>
942 {
943     template <typename U>
944     static String convert(U* p) {
945         if(p)
946             return detail::rawMemoryToString(p);
947         return "NULL";
948     }
949 };
950 
951 template <typename R, typename C>
952 struct StringMaker<R C::*>
953 {
954     static String convert(R C::*p) {
955         if(p)
956             return detail::rawMemoryToString(p);
957         return "NULL";
958     }
959 };
960 
961 template <typename T, typename detail::enable_if<!detail::is_enum<T>::value, bool>::type = true>
962 String toString(const DOCTEST_REF_WRAP(T) value) {
963     return StringMaker<T>::convert(value);
964 }
965 
966 #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
967 DOCTEST_INTERFACE String toString(char* in);
968 DOCTEST_INTERFACE String toString(const char* in);
969 #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
970 DOCTEST_INTERFACE String toString(bool in);
971 DOCTEST_INTERFACE String toString(float in);
972 DOCTEST_INTERFACE String toString(double in);
973 DOCTEST_INTERFACE String toString(double long in);
974 
975 DOCTEST_INTERFACE String toString(char in);
976 DOCTEST_INTERFACE String toString(char signed in);
977 DOCTEST_INTERFACE String toString(char unsigned in);
978 DOCTEST_INTERFACE String toString(int short in);
979 DOCTEST_INTERFACE String toString(int short unsigned in);
980 DOCTEST_INTERFACE String toString(int in);
981 DOCTEST_INTERFACE String toString(int unsigned in);
982 DOCTEST_INTERFACE String toString(int long in);
983 DOCTEST_INTERFACE String toString(int long unsigned in);
984 DOCTEST_INTERFACE String toString(int long long in);
985 DOCTEST_INTERFACE String toString(int long long unsigned in);
986 DOCTEST_INTERFACE String toString(std::nullptr_t in);
987 
988 template <typename T, typename detail::enable_if<detail::is_enum<T>::value, bool>::type = true>
989 String toString(const DOCTEST_REF_WRAP(T) value) {
990     typedef typename detail::underlying_type<T>::type UT;
991     return toString(static_cast<UT>(value));
992 }
993 
994 #if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
995 // see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183
996 DOCTEST_INTERFACE String toString(const std::string& in);
997 #endif // VS 2019
998 
999 class DOCTEST_INTERFACE Approx
1000 {
1001 public:
1002     explicit Approx(double value);
1003 
1004     Approx operator()(double value) const;
1005 
1006 #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
1007     template <typename T>
1008     explicit Approx(const T& value,
1009                     typename detail::enable_if<std::is_constructible<double, T>::value>::type* =
1010                             static_cast<T*>(nullptr)) {
1011         *this = Approx(static_cast<double>(value));
1012     }
1013 #endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
1014 
1015     Approx& epsilon(double newEpsilon);
1016 
1017 #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
1018     template <typename T>
1019     typename detail::enable_if<std::is_constructible<double, T>::value, Approx&>::type epsilon(
1020             const T& newEpsilon) {
1021         m_epsilon = static_cast<double>(newEpsilon);
1022         return *this;
1023     }
1024 #endif //  DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
1025 
1026     Approx& scale(double newScale);
1027 
1028 #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
1029     template <typename T>
1030     typename detail::enable_if<std::is_constructible<double, T>::value, Approx&>::type scale(
1031             const T& newScale) {
1032         m_scale = static_cast<double>(newScale);
1033         return *this;
1034     }
1035 #endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
1036 
1037     // clang-format off
1038     DOCTEST_INTERFACE friend bool operator==(double lhs, const Approx & rhs);
1039     DOCTEST_INTERFACE friend bool operator==(const Approx & lhs, double rhs);
1040     DOCTEST_INTERFACE friend bool operator!=(double lhs, const Approx & rhs);
1041     DOCTEST_INTERFACE friend bool operator!=(const Approx & lhs, double rhs);
1042     DOCTEST_INTERFACE friend bool operator<=(double lhs, const Approx & rhs);
1043     DOCTEST_INTERFACE friend bool operator<=(const Approx & lhs, double rhs);
1044     DOCTEST_INTERFACE friend bool operator>=(double lhs, const Approx & rhs);
1045     DOCTEST_INTERFACE friend bool operator>=(const Approx & lhs, double rhs);
1046     DOCTEST_INTERFACE friend bool operator< (double lhs, const Approx & rhs);
1047     DOCTEST_INTERFACE friend bool operator< (const Approx & lhs, double rhs);
1048     DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs);
1049     DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs);
1050 
1051     DOCTEST_INTERFACE friend String toString(const Approx& in);
1052 
1053 #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
1054 #define DOCTEST_APPROX_PREFIX \
1055     template <typename T> friend typename detail::enable_if<std::is_constructible<double, T>::value, bool>::type
1056 
1057     DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); }
1058     DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); }
1059     DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); }
1060     DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); }
1061     DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value || lhs == rhs; }
1062     DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) || lhs == rhs; }
1063     DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value || lhs == rhs; }
1064     DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) || lhs == rhs; }
1065     DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value && lhs != rhs; }
1066     DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) && lhs != rhs; }
1067     DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value && lhs != rhs; }
1068     DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) && lhs != rhs; }
1069 #undef DOCTEST_APPROX_PREFIX
1070 #endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
1071 
1072     // clang-format on
1073 
1074 private:
1075     double m_epsilon;
1076     double m_scale;
1077     double m_value;
1078 };
1079 
1080 DOCTEST_INTERFACE String toString(const Approx& in);
1081 
1082 DOCTEST_INTERFACE const ContextOptions* getContextOptions();
1083 
1084 #if !defined(DOCTEST_CONFIG_DISABLE)
1085 
1086 namespace detail {
1087     // clang-format off
1088 #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1089     template<class T>               struct decay_array       { typedef T type; };
1090     template<class T, unsigned N>   struct decay_array<T[N]> { typedef T* type; };
1091     template<class T>               struct decay_array<T[]>  { typedef T* type; };
1092 
1093     template<class T>   struct not_char_pointer              { enum { value = 1 }; };
1094     template<>          struct not_char_pointer<char*>       { enum { value = 0 }; };
1095     template<>          struct not_char_pointer<const char*> { enum { value = 0 }; };
1096 
1097     template<class T> struct can_use_op : public not_char_pointer<typename decay_array<T>::type> {};
1098 #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1099     // clang-format on
1100 
1101     struct DOCTEST_INTERFACE TestFailureException
1102     {
1103     };
1104 
1105     DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at);
1106 
1107 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
1108     DOCTEST_NORETURN
1109 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
1110     DOCTEST_INTERFACE void throwException();
1111 
1112     struct DOCTEST_INTERFACE Subcase
1113     {
1114         SubcaseSignature m_signature;
1115         bool             m_entered = false;
1116 
1117         Subcase(const String& name, const char* file, int line);
1118         ~Subcase();
1119 
1120         operator bool() const;
1121     };
1122 
1123     template <typename L, typename R>
1124     String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op,
1125                                const DOCTEST_REF_WRAP(R) rhs) {
1126         // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1127         return toString(lhs) + op + toString(rhs);
1128     }
1129 
1130 #if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)
1131 DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
1132 #endif
1133 
1134 // This will check if there is any way it could find a operator like member or friend and uses it.
1135 // If not it doesn't find the operator or if the operator at global scope is defined after
1136 // this template, the template won't be instantiated due to SFINAE. Once the template is not
1137 // instantiated it can look for global operator using normal conversions.
1138 // TODO: upstream the change to doctest : Implement old version of check due to Intel Compiler
1139 // internal error: assertion failed at: "shared/cfe/edgcpfe/exprutil.c", line 5155
1140 #if !DOCTEST_ICC
1141 #define SFINAE_OP(ret,op) decltype(doctest::detail::declval<L>() op doctest::detail::declval<R>(),static_cast<ret>(0))
1142 #else
1143 #define SFINAE_OP(ret,op) ret
1144 #endif
1145 
1146 #define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro)                              \
1147     template <typename R>                                                                          \
1148     DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& rhs) {                                   \
1149         bool res = op_macro(doctest::detail::forward<L>(lhs), doctest::detail::forward<R>(rhs));   \
1150         if(m_at & assertType::is_false)                                                            \
1151             res = !res;                                                                            \
1152         if(!res || doctest::getContextOptions()->success)                                          \
1153             return Result(res, stringifyBinaryExpr(lhs, op_str, rhs));                             \
1154         return Result(res);                                                                        \
1155     }
1156 
1157     // more checks could be added - like in Catch:
1158     // https://github.com/catchorg/Catch2/pull/1480/files
1159     // https://github.com/catchorg/Catch2/pull/1481/files
1160 #define DOCTEST_FORBIT_EXPRESSION(rt, op)                                                          \
1161     template <typename R>                                                                          \
1162     rt& operator op(const R&) {                                                                    \
1163         static_assert(deferred_false<R>::value,                                                    \
1164                       "Expression Too Complex Please Rewrite As Binary Comparison!");              \
1165         return *this;                                                                              \
1166     }
1167 
1168     struct DOCTEST_INTERFACE Result
1169     {
1170         bool   m_passed;
1171         String m_decomp;
1172 
1173         Result(bool passed, const String& decomposition = String());
1174 
1175         // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence
1176         DOCTEST_FORBIT_EXPRESSION(Result, &)
1177         DOCTEST_FORBIT_EXPRESSION(Result, ^)
1178         DOCTEST_FORBIT_EXPRESSION(Result, |)
1179         DOCTEST_FORBIT_EXPRESSION(Result, &&)
1180         DOCTEST_FORBIT_EXPRESSION(Result, ||)
1181         DOCTEST_FORBIT_EXPRESSION(Result, ==)
1182         DOCTEST_FORBIT_EXPRESSION(Result, !=)
1183         DOCTEST_FORBIT_EXPRESSION(Result, <)
1184         DOCTEST_FORBIT_EXPRESSION(Result, >)
1185         DOCTEST_FORBIT_EXPRESSION(Result, <=)
1186         DOCTEST_FORBIT_EXPRESSION(Result, >=)
1187         DOCTEST_FORBIT_EXPRESSION(Result, =)
1188         DOCTEST_FORBIT_EXPRESSION(Result, +=)
1189         DOCTEST_FORBIT_EXPRESSION(Result, -=)
1190         DOCTEST_FORBIT_EXPRESSION(Result, *=)
1191         DOCTEST_FORBIT_EXPRESSION(Result, /=)
1192         DOCTEST_FORBIT_EXPRESSION(Result, %=)
1193         DOCTEST_FORBIT_EXPRESSION(Result, <<=)
1194         DOCTEST_FORBIT_EXPRESSION(Result, >>=)
1195         DOCTEST_FORBIT_EXPRESSION(Result, &=)
1196         DOCTEST_FORBIT_EXPRESSION(Result, ^=)
1197         DOCTEST_FORBIT_EXPRESSION(Result, |=)
1198     };
1199 
1200 #ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION
1201 
1202     DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
1203     DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion")
1204     DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-compare")
1205     //DOCTEST_CLANG_SUPPRESS_WARNING("-Wdouble-promotion")
1206     //DOCTEST_CLANG_SUPPRESS_WARNING("-Wconversion")
1207     //DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-equal")
1208 
1209     DOCTEST_GCC_SUPPRESS_WARNING_PUSH
1210     DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion")
1211     DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-compare")
1212     //DOCTEST_GCC_SUPPRESS_WARNING("-Wdouble-promotion")
1213     //DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion")
1214     //DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal")
1215 
1216     DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
1217     // https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389
1218     DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch
1219     DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch
1220     DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch
1221     //DOCTEST_MSVC_SUPPRESS_WARNING(4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation
1222 
1223 #endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION
1224 
1225     // clang-format off
1226 #ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1227 #define DOCTEST_COMPARISON_RETURN_TYPE bool
1228 #else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1229 #define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type
1230     // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1231     inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); }
1232     inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); }
1233     inline bool lt(const char* lhs, const char* rhs) { return String(lhs) <  String(rhs); }
1234     inline bool gt(const char* lhs, const char* rhs) { return String(lhs) >  String(rhs); }
1235     inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); }
1236     inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); }
1237 #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1238     // clang-format on
1239 
1240 #define DOCTEST_RELATIONAL_OP(name, op)                                                            \
1241     template <typename L, typename R>                                                              \
1242     DOCTEST_COMPARISON_RETURN_TYPE name(const DOCTEST_REF_WRAP(L) lhs,                             \
1243                                         const DOCTEST_REF_WRAP(R) rhs) {                           \
1244         return lhs op rhs;                                                                         \
1245     }
1246 
1247     DOCTEST_RELATIONAL_OP(eq, ==)
1248     DOCTEST_RELATIONAL_OP(ne, !=)
1249     DOCTEST_RELATIONAL_OP(lt, <)
1250     DOCTEST_RELATIONAL_OP(gt, >)
1251     DOCTEST_RELATIONAL_OP(le, <=)
1252     DOCTEST_RELATIONAL_OP(ge, >=)
1253 
1254 #ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1255 #define DOCTEST_CMP_EQ(l, r) l == r
1256 #define DOCTEST_CMP_NE(l, r) l != r
1257 #define DOCTEST_CMP_GT(l, r) l > r
1258 #define DOCTEST_CMP_LT(l, r) l < r
1259 #define DOCTEST_CMP_GE(l, r) l >= r
1260 #define DOCTEST_CMP_LE(l, r) l <= r
1261 #else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1262 #define DOCTEST_CMP_EQ(l, r) eq(l, r)
1263 #define DOCTEST_CMP_NE(l, r) ne(l, r)
1264 #define DOCTEST_CMP_GT(l, r) gt(l, r)
1265 #define DOCTEST_CMP_LT(l, r) lt(l, r)
1266 #define DOCTEST_CMP_GE(l, r) ge(l, r)
1267 #define DOCTEST_CMP_LE(l, r) le(l, r)
1268 #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1269 
1270     template <typename L>
1271     // cppcheck-suppress copyCtorAndEqOperator
1272     struct Expression_lhs
1273     {
1274         L                lhs;
1275         assertType::Enum m_at;
1276 
1277         explicit Expression_lhs(L&& in, assertType::Enum at)
1278                 : lhs(doctest::detail::forward<L>(in))
1279                 , m_at(at) {}
1280 
1281         DOCTEST_NOINLINE operator Result() {
1282 // this is needed only foc MSVC 2015:
1283 // https://ci.appveyor.com/project/onqtam/doctest/builds/38181202
1284 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool
1285             bool res = static_cast<bool>(lhs);
1286 DOCTEST_MSVC_SUPPRESS_WARNING_POP
1287             if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional
1288                 res = !res;
1289 
1290             if(!res || getContextOptions()->success)
1291                 return Result(res, toString(lhs));
1292             return Result(res);
1293         }
1294 
1295 	/* This is required for user-defined conversions from Expression_lhs to L */
1296 	//operator L() const { return lhs; }
1297 	operator L() const { return lhs; }
1298 
1299         // clang-format off
1300         DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional
1301         DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional
1302         DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>,  " >  ", DOCTEST_CMP_GT) //!OCLINT bitwise operator in conditional
1303         DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<,  " <  ", DOCTEST_CMP_LT) //!OCLINT bitwise operator in conditional
1304         DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, " >= ", DOCTEST_CMP_GE) //!OCLINT bitwise operator in conditional
1305         DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional
1306 
1307         // clang-format on
1308 
1309         // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence
1310         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &)
1311         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^)
1312         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |)
1313         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &&)
1314         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ||)
1315         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, =)
1316         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, +=)
1317         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, -=)
1318         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, *=)
1319         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, /=)
1320         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, %=)
1321         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<=)
1322         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>=)
1323         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &=)
1324         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^=)
1325         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |=)
1326         // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the
1327         // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression...
1328         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<)
1329         DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>)
1330     };
1331 
1332 #ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION
1333 
1334     DOCTEST_CLANG_SUPPRESS_WARNING_POP
1335     DOCTEST_MSVC_SUPPRESS_WARNING_POP
1336     DOCTEST_GCC_SUPPRESS_WARNING_POP
1337 
1338 #endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION
1339 
1340 #if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)
1341 DOCTEST_CLANG_SUPPRESS_WARNING_POP
1342 #endif
1343 
1344     struct DOCTEST_INTERFACE ExpressionDecomposer
1345     {
1346         assertType::Enum m_at;
1347 
1348         ExpressionDecomposer(assertType::Enum at);
1349 
1350         // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator precedence table)
1351         // but then there will be warnings from GCC about "-Wparentheses" and since "_Pragma()" is problematic this will stay for now...
1352         // https://github.com/catchorg/Catch2/issues/870
1353         // https://github.com/catchorg/Catch2/issues/565
1354         template <typename L>
1355 	Expression_lhs<L> operator<<(L &&operand) {
1356             return Expression_lhs<L>(doctest::detail::forward<L>(operand), m_at);
1357         }
1358     };
1359 
1360     struct DOCTEST_INTERFACE TestSuite
1361     {
1362         // TODO: upstream the change to doctest : missing initializer for member
1363         const char* m_test_suite = nullptr;
1364         const char* m_description = nullptr;
1365         bool        m_skip = false;
1366         bool        m_no_breaks = false;
1367         bool        m_no_output = false;
1368         bool        m_may_fail = false;
1369         bool        m_should_fail = false;
1370         int         m_expected_failures = 0;
1371         double      m_timeout = 0;
1372 
1373         // TODO: upstream the change to doctest : Fix segfault on Intel Compiler 2021 during the DOCTEST_TEST_SUITE_END execution
1374         TestSuite(const char* in = nullptr) {
1375             m_test_suite = in;
1376         }
1377 
1378         TestSuite& operator*(const char* in);
1379 
1380         template <typename T>
1381         TestSuite& operator*(const T& in) {
1382             in.fill(*this);
1383             return *this;
1384         }
1385     };
1386 
1387     typedef void (*funcType)();
1388 
1389     struct DOCTEST_INTERFACE TestCase : public TestCaseData
1390     {
1391         funcType m_test; // a function pointer to the test case
1392 
1393         const char* m_type; // for templated test cases - gets appended to the real name
1394         int m_template_id; // an ID used to distinguish between the different versions of a templated test case
1395         String m_full_name; // contains the name (only for templated test cases!) + the template type
1396 
1397         TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,
1398                  const char* type = "", int template_id = -1);
1399 
1400         TestCase(const TestCase& other);
1401 
1402         DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function
1403         TestCase& operator=(const TestCase& other);
1404         DOCTEST_MSVC_SUPPRESS_WARNING_POP
1405 
1406         TestCase& operator*(const char* in);
1407 
1408         template <typename T>
1409         TestCase& operator*(const T& in) {
1410             in.fill(*this);
1411             return *this;
1412         }
1413 
1414         bool operator<(const TestCase& other) const;
1415     };
1416 
1417     // forward declarations of functions used by the macros
1418     DOCTEST_INTERFACE int  regTest(const TestCase& tc);
1419     DOCTEST_INTERFACE int  setTestSuite(const TestSuite& ts);
1420     DOCTEST_INTERFACE bool isDebuggerActive();
1421 
1422     template<typename T>
1423     int instantiationHelper(const T&) { return 0; }
1424 
1425     namespace binaryAssertComparison {
1426         enum Enum
1427         {
1428             eq = 0,
1429             ne,
1430             gt,
1431             lt,
1432             ge,
1433             le
1434         };
1435     } // namespace binaryAssertComparison
1436 
1437     // clang-format off
1438     template <int, class L, class R> struct RelationalComparator     { bool operator()(const DOCTEST_REF_WRAP(L),     const DOCTEST_REF_WRAP(R)    ) const { return false;        } };
1439 
1440 #define DOCTEST_BINARY_RELATIONAL_OP(n, op) \
1441     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); } };
1442     // clang-format on
1443 
1444     DOCTEST_BINARY_RELATIONAL_OP(0, doctest::detail::eq)
1445     DOCTEST_BINARY_RELATIONAL_OP(1, doctest::detail::ne)
1446     DOCTEST_BINARY_RELATIONAL_OP(2, doctest::detail::gt)
1447     DOCTEST_BINARY_RELATIONAL_OP(3, doctest::detail::lt)
1448     DOCTEST_BINARY_RELATIONAL_OP(4, doctest::detail::ge)
1449     DOCTEST_BINARY_RELATIONAL_OP(5, doctest::detail::le)
1450 
1451     struct DOCTEST_INTERFACE ResultBuilder : public AssertData
1452     {
1453         ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr,
1454                       const char* exception_type = "", const char* exception_string = "");
1455 
1456         void setResult(const Result& res);
1457 
1458         template <int comparison, typename L, typename R>
1459         DOCTEST_NOINLINE void binary_assert(const DOCTEST_REF_WRAP(L) lhs,
1460                                             const DOCTEST_REF_WRAP(R) rhs) {
1461             m_failed = !RelationalComparator<comparison, L, R>()(lhs, rhs);
1462             if(m_failed || getContextOptions()->success)
1463                 m_decomp = stringifyBinaryExpr(lhs, ", ", rhs);
1464         }
1465 
1466         template <typename L>
1467         DOCTEST_NOINLINE void unary_assert(const DOCTEST_REF_WRAP(L) val) {
1468             m_failed = !val;
1469 
1470             if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional
1471                 m_failed = !m_failed;
1472 
1473             if(m_failed || getContextOptions()->success)
1474                 m_decomp = toString(val);
1475         }
1476 
1477         void translateException();
1478 
1479         bool log();
1480         void react() const;
1481     };
1482 
1483     namespace assertAction {
1484         enum Enum
1485         {
1486             nothing     = 0,
1487             dbgbreak    = 1,
1488             shouldthrow = 2
1489         };
1490     } // namespace assertAction
1491 
1492     DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData& ad);
1493 
1494     DOCTEST_INTERFACE void decomp_assert(assertType::Enum at, const char* file, int line,
1495                                          const char* expr, Result result);
1496 
1497 #define DOCTEST_ASSERT_OUT_OF_TESTS(decomp)                                                        \
1498     do {                                                                                           \
1499         if(!is_running_in_test) {                                                                  \
1500             if(failed) {                                                                           \
1501                 ResultBuilder rb(at, file, line, expr);                                            \
1502                 rb.m_failed = failed;                                                              \
1503                 rb.m_decomp = decomp;                                                              \
1504                 failed_out_of_a_testing_context(rb);                                               \
1505                 if(isDebuggerActive() && !getContextOptions()->no_breaks)                          \
1506                     DOCTEST_BREAK_INTO_DEBUGGER();                                                 \
1507                 if(checkIfShouldThrow(at))                                                         \
1508                     throwException();                                                              \
1509             }                                                                                      \
1510             return;                                                                                \
1511         }                                                                                          \
1512     } while(false)
1513 
1514 #define DOCTEST_ASSERT_IN_TESTS(decomp)                                                            \
1515     ResultBuilder rb(at, file, line, expr);                                                        \
1516     rb.m_failed = failed;                                                                          \
1517     if(rb.m_failed || getContextOptions()->success)                                                \
1518         rb.m_decomp = decomp;                                                                      \
1519     if(rb.log())                                                                                   \
1520         DOCTEST_BREAK_INTO_DEBUGGER();                                                             \
1521     if(rb.m_failed && checkIfShouldThrow(at))                                                      \
1522     throwException()
1523 
1524     template <int comparison, typename L, typename R>
1525     DOCTEST_NOINLINE void binary_assert(assertType::Enum at, const char* file, int line,
1526                                         const char* expr, const DOCTEST_REF_WRAP(L) lhs,
1527                                         const DOCTEST_REF_WRAP(R) rhs) {
1528         bool failed = !RelationalComparator<comparison, L, R>()(lhs, rhs);
1529 
1530         // ###################################################################################
1531         // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT
1532         // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED
1533         // ###################################################################################
1534         DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, ", ", rhs));
1535         DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, ", ", rhs));
1536     }
1537 
1538     template <typename L>
1539     DOCTEST_NOINLINE void unary_assert(assertType::Enum at, const char* file, int line,
1540                                        const char* expr, const DOCTEST_REF_WRAP(L) val) {
1541         bool failed = !val;
1542 
1543         if(at & assertType::is_false) //!OCLINT bitwise operator in conditional
1544             failed = !failed;
1545 
1546         // ###################################################################################
1547         // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT
1548         // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED
1549         // ###################################################################################
1550         DOCTEST_ASSERT_OUT_OF_TESTS(toString(val));
1551         DOCTEST_ASSERT_IN_TESTS(toString(val));
1552     }
1553 
1554     struct DOCTEST_INTERFACE IExceptionTranslator
1555     {
1556         IExceptionTranslator();
1557         virtual ~IExceptionTranslator();
1558         virtual bool translate(String&) const = 0;
1559     };
1560 
1561     template <typename T>
1562     class ExceptionTranslator : public IExceptionTranslator //!OCLINT destructor of virtual class
1563     {
1564     public:
1565         explicit ExceptionTranslator(String (*translateFunction)(T))
1566                 : m_translateFunction(translateFunction) {}
1567 
1568         bool translate(String& res) const override {
1569 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
1570             try {
1571                 throw; // lgtm [cpp/rethrow-no-exception]
1572                 // cppcheck-suppress catchExceptionByValue
1573             } catch(T ex) {                    // NOLINT
1574                 res = m_translateFunction(ex); //!OCLINT parameter reassignment
1575                 return true;
1576             } catch(...) {}         //!OCLINT -  empty catch statement
1577 #endif                              // DOCTEST_CONFIG_NO_EXCEPTIONS
1578             static_cast<void>(res); // to silence -Wunused-parameter
1579             return false;
1580         }
1581 
1582     private:
1583         String (*m_translateFunction)(T);
1584     };
1585 
1586     DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et);
1587 
1588     template <bool C>
1589     struct StringStreamBase
1590     {
1591         template <typename T>
1592         static void convert(std::ostream* s, const T& in) {
1593             *s << toString(in);
1594         }
1595 
1596         // always treat char* as a string in this context - no matter
1597         // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined
1598         static void convert(std::ostream* s, const char* in) { *s << String(in); }
1599     };
1600 
1601     template <>
1602     struct StringStreamBase<true>
1603     {
1604         template <typename T>
1605         static void convert(std::ostream* s, const T& in) {
1606             *s << in;
1607         }
1608     };
1609 
1610     template <typename T>
1611     struct StringStream : public StringStreamBase<has_insertion_operator<T>::value>
1612     {};
1613 
1614     template <typename T>
1615     void toStream(std::ostream* s, const T& value) {
1616         StringStream<T>::convert(s, value);
1617     }
1618 
1619 #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1620     DOCTEST_INTERFACE void toStream(std::ostream* s, char* in);
1621     DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in);
1622 #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
1623     DOCTEST_INTERFACE void toStream(std::ostream* s, bool in);
1624     DOCTEST_INTERFACE void toStream(std::ostream* s, float in);
1625     DOCTEST_INTERFACE void toStream(std::ostream* s, double in);
1626     DOCTEST_INTERFACE void toStream(std::ostream* s, double long in);
1627 
1628     DOCTEST_INTERFACE void toStream(std::ostream* s, char in);
1629     DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in);
1630     DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in);
1631     DOCTEST_INTERFACE void toStream(std::ostream* s, int short in);
1632     DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in);
1633     DOCTEST_INTERFACE void toStream(std::ostream* s, int in);
1634     DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in);
1635     DOCTEST_INTERFACE void toStream(std::ostream* s, int long in);
1636     DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in);
1637     DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in);
1638     DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in);
1639 
1640     // ContextScope base class used to allow implementing methods of ContextScope
1641     // that don't depend on the template parameter in doctest.cpp.
1642     class DOCTEST_INTERFACE ContextScopeBase : public IContextScope {
1643     protected:
1644         ContextScopeBase();
1645         ContextScopeBase(ContextScopeBase&& other);
1646 
1647         void destroy();
1648         bool need_to_destroy{true};
1649     };
1650 
1651     template <typename L> class ContextScope : public ContextScopeBase
1652     {
1653         const L lambda_;
1654 
1655     public:
1656 
1657         explicit ContextScope(const L &lambda) : ContextScopeBase(), lambda_(lambda) {}
1658 
1659         // TODO: upstream the change to doctest : fix copy elision absence case
1660         // std::move cannot be applied here since there is no utility header included in this place (by some reason all headers are included later)
1661         ContextScope(ContextScope &&other) : ContextScopeBase(static_cast<ContextScopeBase&&>(other)), lambda_(other.lambda_) {}
1662 
1663         void stringify(std::ostream* s) const override { lambda_(s); }
1664 
1665         ~ContextScope() override {
1666             if (need_to_destroy) {
1667                 destroy();
1668             }
1669         }
1670 
1671         template <typename F>
1672         friend ContextScope<F> MakeContextScope(const F &lambda);
1673     };
1674 
1675     struct DOCTEST_INTERFACE MessageBuilder : public MessageData
1676     {
1677         std::ostream* m_stream;
1678 
1679         MessageBuilder(const char* file, int line, assertType::Enum severity);
1680         MessageBuilder() = delete;
1681         ~MessageBuilder();
1682 
1683         // the preferred way of chaining parameters for stringification
1684         template <typename T>
1685         MessageBuilder& operator,(const T& in) {
1686             toStream(m_stream, in);
1687             return *this;
1688         }
1689 
1690         // kept here just for backwards-compatibility - the comma operator should be preferred now
1691         template <typename T>
1692         MessageBuilder& operator<<(const T& in) { return this->operator,(in); }
1693 
1694         // the `,` operator has the lowest operator precedence - if `<<` is used by the user then
1695         // the `,` operator will be called last which is not what we want and thus the `*` operator
1696         // is used first (has higher operator precedence compared to `<<`) so that we guarantee that
1697         // an operator of the MessageBuilder class is called first before the rest of the parameters
1698         template <typename T>
1699         MessageBuilder& operator*(const T& in) { return this->operator,(in); }
1700 
1701         bool log();
1702         void react();
1703     };
1704 
1705     template <typename L>
1706     ContextScope<L> MakeContextScope(const L &lambda) {
1707         return ContextScope<L>(lambda);
1708     }
1709 } // namespace detail
1710 
1711 #define DOCTEST_DEFINE_DECORATOR(name, type, def)                                                  \
1712     struct name                                                                                    \
1713     {                                                                                              \
1714         type data;                                                                                 \
1715         name(type in = def)                                                                        \
1716                 : data(in) {}                                                                      \
1717         void fill(detail::TestCase& state) const { state.DOCTEST_CAT(m_, name) = data; }           \
1718         void fill(detail::TestSuite& state) const { state.DOCTEST_CAT(m_, name) = data; }          \
1719     }
1720 
1721 DOCTEST_DEFINE_DECORATOR(test_suite, const char*, "");
1722 DOCTEST_DEFINE_DECORATOR(description, const char*, "");
1723 DOCTEST_DEFINE_DECORATOR(skip, bool, true);
1724 DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true);
1725 DOCTEST_DEFINE_DECORATOR(no_output, bool, true);
1726 DOCTEST_DEFINE_DECORATOR(timeout, double, 0);
1727 DOCTEST_DEFINE_DECORATOR(may_fail, bool, true);
1728 DOCTEST_DEFINE_DECORATOR(should_fail, bool, true);
1729 DOCTEST_DEFINE_DECORATOR(expected_failures, int, 0);
1730 
1731 template <typename T>
1732 int registerExceptionTranslator(String (*translateFunction)(T)) {
1733     DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors")
1734     static detail::ExceptionTranslator<T> exceptionTranslator(translateFunction);
1735     DOCTEST_CLANG_SUPPRESS_WARNING_POP
1736     detail::registerExceptionTranslatorImpl(&exceptionTranslator);
1737     return 0;
1738 }
1739 
1740 } // namespace doctest
1741 
1742 // in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro
1743 // introduces an anonymous namespace in which getCurrentTestSuite gets overridden
1744 namespace doctest_detail_test_suite_ns {
1745 DOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite();
1746 } // namespace doctest_detail_test_suite_ns
1747 
1748 namespace doctest {
1749 #else  // DOCTEST_CONFIG_DISABLE
1750 template <typename T>
1751 int registerExceptionTranslator(String (*)(T)) {
1752     return 0;
1753 }
1754 #endif // DOCTEST_CONFIG_DISABLE
1755 
1756 namespace detail {
1757     typedef void (*assert_handler)(const AssertData&);
1758     struct ContextState;
1759 } // namespace detail
1760 
1761 class DOCTEST_INTERFACE Context
1762 {
1763     detail::ContextState* p;
1764 
1765     void parseArgs(int argc, const char* const* argv, bool withDefaults = false);
1766 
1767 public:
1768     explicit Context(int argc = 0, const char* const* argv = nullptr);
1769 
1770     ~Context();
1771 
1772     void applyCommandLine(int argc, const char* const* argv);
1773 
1774     void addFilter(const char* filter, const char* value);
1775     void clearFilters();
1776     void setOption(const char* option, int value);
1777     void setOption(const char* option, const char* value);
1778 
1779     bool shouldExit();
1780 
1781     void setAsDefaultForAssertsOutOfTestCases();
1782 
1783     void setAssertHandler(detail::assert_handler ah);
1784 
1785     int run();
1786 };
1787 
1788 namespace TestCaseFailureReason {
1789     enum Enum
1790     {
1791         None                     = 0,
1792         AssertFailure            = 1,   // an assertion has failed in the test case
1793         Exception                = 2,   // test case threw an exception
1794         Crash                    = 4,   // a crash...
1795         TooManyFailedAsserts     = 8,   // the abort-after option
1796         Timeout                  = 16,  // see the timeout decorator
1797         ShouldHaveFailedButDidnt = 32,  // see the should_fail decorator
1798         ShouldHaveFailedAndDid   = 64,  // see the should_fail decorator
1799         DidntFailExactlyNumTimes = 128, // see the expected_failures decorator
1800         FailedExactlyNumTimes    = 256, // see the expected_failures decorator
1801         CouldHaveFailedAndDid    = 512  // see the may_fail decorator
1802     };
1803 } // namespace TestCaseFailureReason
1804 
1805 struct DOCTEST_INTERFACE CurrentTestCaseStats
1806 {
1807     int    numAssertsCurrentTest;
1808     int    numAssertsFailedCurrentTest;
1809     double seconds;
1810     int    failure_flags; // use TestCaseFailureReason::Enum
1811 };
1812 
1813 struct DOCTEST_INTERFACE TestCaseException
1814 {
1815     String error_string;
1816     bool   is_crash;
1817 };
1818 
1819 struct DOCTEST_INTERFACE TestRunStats
1820 {
1821     unsigned numTestCases;
1822     unsigned numTestCasesPassingFilters;
1823     unsigned numTestSuitesPassingFilters;
1824     unsigned numTestCasesFailed;
1825     int      numAsserts;
1826     int      numAssertsFailed;
1827 };
1828 
1829 struct QueryData
1830 {
1831     const TestRunStats*  run_stats = nullptr;
1832     const TestCaseData** data      = nullptr;
1833     unsigned             num_data  = 0;
1834 };
1835 
1836 struct DOCTEST_INTERFACE IReporter
1837 {
1838     // The constructor has to accept "const ContextOptions&" as a single argument
1839     // which has most of the options for the run + a pointer to the stdout stream
1840     // Reporter(const ContextOptions& in)
1841 
1842     // called when a query should be reported (listing test cases, printing the version, etc.)
1843     virtual void report_query(const QueryData&) = 0;
1844 
1845     // called when the whole test run starts
1846     virtual void test_run_start() = 0;
1847     // called when the whole test run ends (caching a pointer to the input doesn't make sense here)
1848     virtual void test_run_end(const TestRunStats&) = 0;
1849 
1850     // called when a test case is started (safe to cache a pointer to the input)
1851     virtual void test_case_start(const TestCaseData&) = 0;
1852     // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input)
1853     virtual void test_case_reenter(const TestCaseData&) = 0;
1854     // called when a test case has ended
1855     virtual void test_case_end(const CurrentTestCaseStats&) = 0;
1856 
1857     // called when an exception is thrown from the test case (or it crashes)
1858     virtual void test_case_exception(const TestCaseException&) = 0;
1859 
1860     // called whenever a subcase is entered (don't cache pointers to the input)
1861     virtual void subcase_start(const SubcaseSignature&) = 0;
1862     // called whenever a subcase is exited (don't cache pointers to the input)
1863     virtual void subcase_end() = 0;
1864 
1865     // called for each assert (don't cache pointers to the input)
1866     virtual void log_assert(const AssertData&) = 0;
1867     // called for each message (don't cache pointers to the input)
1868     virtual void log_message(const MessageData&) = 0;
1869 
1870     // called when a test case is skipped either because it doesn't pass the filters, has a skip decorator
1871     // or isn't in the execution range (between first and last) (safe to cache a pointer to the input)
1872     virtual void test_case_skipped(const TestCaseData&) = 0;
1873 
1874     // doctest will not be managing the lifetimes of reporters given to it but this would still be nice to have
1875     virtual ~IReporter();
1876 
1877     // can obtain all currently active contexts and stringify them if one wishes to do so
1878     static int                         get_num_active_contexts();
1879     static const IContextScope* const* get_active_contexts();
1880 
1881     // can iterate through contexts which have been stringified automatically in their destructors when an exception has been thrown
1882     static int           get_num_stringified_contexts();
1883     static const String* get_stringified_contexts();
1884 };
1885 
1886 namespace detail {
1887     typedef IReporter* (*reporterCreatorFunc)(const ContextOptions&);
1888 
1889     DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c, bool isReporter);
1890 
1891     template <typename Reporter>
1892     IReporter* reporterCreator(const ContextOptions& o) {
1893         return new Reporter(o);
1894     }
1895 } // namespace detail
1896 
1897 template <typename Reporter>
1898 int registerReporter(const char* name, int priority, bool isReporter) {
1899     detail::registerReporterImpl(name, priority, detail::reporterCreator<Reporter>, isReporter);
1900     return 0;
1901 }
1902 } // namespace doctest
1903 
1904 // if registering is not disabled
1905 #if !defined(DOCTEST_CONFIG_DISABLE)
1906 
1907 // common code in asserts - for convenience
1908 #define DOCTEST_ASSERT_LOG_AND_REACT(b)                                                            \
1909     if(b.log())                                                                                    \
1910         DOCTEST_BREAK_INTO_DEBUGGER();                                                             \
1911     b.react()
1912 
1913 #ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
1914 #define DOCTEST_WRAP_IN_TRY(x) x;
1915 #else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
1916 #define DOCTEST_WRAP_IN_TRY(x)                                                                     \
1917     try {                                                                                          \
1918         x;                                                                                         \
1919     } catch(...) { _DOCTEST_RB.translateException(); }
1920 #endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
1921 
1922 #ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS
1923 #define DOCTEST_CAST_TO_VOID(...)                                                                  \
1924     DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast")                                       \
1925     static_cast<void>(__VA_ARGS__);                                                                \
1926     DOCTEST_GCC_SUPPRESS_WARNING_POP
1927 #else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS
1928 #define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__;
1929 #endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS
1930 
1931 // registers the test by initializing a dummy var with a function
1932 #define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators)                                    \
1933     global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) =              \
1934             doctest::detail::regTest(                                                              \
1935                     doctest::detail::TestCase(                                                     \
1936                             f, __FILE__, __LINE__,                                                 \
1937                             doctest_detail_test_suite_ns::getCurrentTestSuite()) *                 \
1938                     decorators);                                                                   \
1939     DOCTEST_GLOBAL_NO_WARNINGS_END()
1940 
1941 #define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators)                                     \
1942     namespace {                                                                                    \
1943         struct der : public base                                                                   \
1944         {                                                                                          \
1945             void f();                                                                              \
1946         };                                                                                         \
1947         static void func() {                                                                       \
1948             der v;                                                                                 \
1949             v.f();                                                                                 \
1950         }                                                                                          \
1951         DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators)                                 \
1952     }                                                                                              \
1953     inline DOCTEST_NOINLINE void der::f()
1954 
1955 #define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators)                                        \
1956     static void f();                                                                               \
1957     DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, f, decorators)                                        \
1958     static void f()
1959 
1960 #define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators)                        \
1961     static doctest::detail::funcType proxy() { return f; }                                         \
1962     DOCTEST_REGISTER_FUNCTION(inline const, proxy(), decorators)                                   \
1963     static void f()
1964 
1965 // for registering tests
1966 #define DOCTEST_TEST_CASE(decorators)                                                              \
1967     DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators)
1968 
1969 // for registering tests in classes - requires C++17 for inline variables!
1970 #if __cplusplus >= 201703L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 12, 0) && _MSVC_LANG >= 201703L)
1971 #define DOCTEST_TEST_CASE_CLASS(decorators)                                                        \
1972     DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_),          \
1973                                                   DOCTEST_ANONYMOUS(_DOCTEST_ANON_PROXY_),         \
1974                                                   decorators)
1975 #else // DOCTEST_TEST_CASE_CLASS
1976 #define DOCTEST_TEST_CASE_CLASS(...)                                                               \
1977     TEST_CASES_CAN_BE_REGISTERED_IN_CLASSES_ONLY_IN_CPP17_MODE_OR_WITH_VS_2017_OR_NEWER
1978 #endif // DOCTEST_TEST_CASE_CLASS
1979 
1980 // for registering tests with a fixture
1981 #define DOCTEST_TEST_CASE_FIXTURE(c, decorators)                                                   \
1982     DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c,                          \
1983                               DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators)
1984 
1985 // for converting types to strings without the <typeinfo> header and demangling
1986 #define DOCTEST_TYPE_TO_STRING_IMPL(...)                                                           \
1987     template <>                                                                                    \
1988     inline const char* type_to_string<__VA_ARGS__>() {                                             \
1989         return "<" #__VA_ARGS__ ">";                                                               \
1990     }
1991 #define DOCTEST_TYPE_TO_STRING(...)                                                                \
1992     namespace doctest { namespace detail {                                                         \
1993             DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__)                                               \
1994         }                                                                                          \
1995     }                                                                                              \
1996     typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
1997 
1998 #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func)                                 \
1999     template <typename T>                                                                          \
2000     static void func();                                                                            \
2001     namespace {                                                                                    \
2002         template <typename Tuple>                                                                  \
2003         struct iter;                                                                               \
2004         template <typename Type, typename... Rest>                                                 \
2005         struct iter<std::tuple<Type, Rest...>>                                                     \
2006         {                                                                                          \
2007             iter(const char* file, unsigned line, int index) {                                     \
2008                 doctest::detail::regTest(doctest::detail::TestCase(func<Type>, file, line,         \
2009                                             doctest_detail_test_suite_ns::getCurrentTestSuite(),   \
2010                                             doctest::detail::type_to_string<Type>(),               \
2011                                             int(line) * 1000 + index)                              \
2012                                          * dec);                                                   \
2013                 iter<std::tuple<Rest...>>(file, line, index + 1);                                  \
2014             }                                                                                      \
2015         };                                                                                         \
2016         template <>                                                                                \
2017         struct iter<std::tuple<>>                                                                  \
2018         {                                                                                          \
2019             iter(const char*, unsigned, int) {}                                                    \
2020         };                                                                                         \
2021     }                                                                                              \
2022     template <typename T>                                                                          \
2023     static void func()
2024 
2025 #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id)                                              \
2026     DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR),                      \
2027                                            DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_))
2028 
2029 #define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...)                                 \
2030     DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) =                                         \
2031         doctest::detail::instantiationHelper(DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0));\
2032     DOCTEST_GLOBAL_NO_WARNINGS_END()
2033 
2034 #define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...)                                                 \
2035     DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \
2036     typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2037 
2038 #define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...)                                                  \
2039     DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \
2040     typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2041 
2042 #define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...)                                         \
2043     DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon);             \
2044     DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>)               \
2045     template <typename T>                                                                          \
2046     static void anon()
2047 
2048 #define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...)                                                    \
2049     DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__)
2050 
2051 // for subcases
2052 #define DOCTEST_SUBCASE(name)                                                                      \
2053     if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \
2054                doctest::detail::Subcase(name, __FILE__, __LINE__))
2055 
2056 // for grouping tests in test suites by using code blocks
2057 #define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name)                                               \
2058     namespace ns_name { namespace doctest_detail_test_suite_ns {                                   \
2059             static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() {            \
2060                 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640)                                      \
2061                 DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors")                \
2062                 DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers")             \
2063                 static doctest::detail::TestSuite data{};                                          \
2064                 static bool                       inited = false;                                  \
2065                 DOCTEST_MSVC_SUPPRESS_WARNING_POP                                                  \
2066                 DOCTEST_CLANG_SUPPRESS_WARNING_POP                                                 \
2067                 DOCTEST_GCC_SUPPRESS_WARNING_POP                                                   \
2068                 if(!inited) {                                                                      \
2069                     data* decorators;                                                              \
2070                     inited = true;                                                                 \
2071                 }                                                                                  \
2072                 return data;                                                                       \
2073             }                                                                                      \
2074         }                                                                                          \
2075     }                                                                                              \
2076     namespace ns_name
2077 
2078 #define DOCTEST_TEST_SUITE(decorators)                                                             \
2079     DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_))
2080 
2081 // for starting a testsuite block
2082 #define DOCTEST_TEST_SUITE_BEGIN(decorators)                                                       \
2083     DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) =                            \
2084             doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators);              \
2085     DOCTEST_GLOBAL_NO_WARNINGS_END()                                                               \
2086     typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2087 
2088 // for ending a testsuite block
2089 #define DOCTEST_TEST_SUITE_END                                                                     \
2090     DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) =                            \
2091             doctest::detail::setTestSuite(doctest::detail::TestSuite(""));                      \
2092     DOCTEST_GLOBAL_NO_WARNINGS_END()                                                               \
2093     typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2094 
2095 // for registering exception translators
2096 #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature)                      \
2097     inline doctest::String translatorName(signature);                                              \
2098     DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)) =                     \
2099             doctest::registerExceptionTranslator(translatorName);                                  \
2100     DOCTEST_GLOBAL_NO_WARNINGS_END()                                                               \
2101     doctest::String translatorName(signature)
2102 
2103 #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)                                           \
2104     DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_),       \
2105                                                signature)
2106 
2107 // for registering reporters
2108 #define DOCTEST_REGISTER_REPORTER(name, priority, reporter)                                        \
2109     DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) =                       \
2110             doctest::registerReporter<reporter>(name, priority, true);                             \
2111     DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2112 
2113 // for registering listeners
2114 #define DOCTEST_REGISTER_LISTENER(name, priority, reporter)                                        \
2115     DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) =                       \
2116             doctest::registerReporter<reporter>(name, priority, false);                            \
2117     DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2118 
2119 // for logging
2120 // TODO: upstream the change to doctest : DOCTEST_ANONYMOUS doesn't work on the same line here on MSVS 15.9.13
2121 #define DOCTEST_INFO(...)                                                                          \
2122     DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_),                                        \
2123                       _DOCTEST_CAPTURE_##__COUNTER__,                                              \
2124                       __VA_ARGS__)
2125 
2126 #define DOCTEST_INFO_IMPL(mb_name, s_name, ...)                                       \
2127     auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope(                 \
2128         [&](std::ostream* s_name) {                                                                \
2129         doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \
2130         mb_name.m_stream = s_name;                                                                 \
2131         mb_name * __VA_ARGS__;                                                                     \
2132     })
2133 
2134 #define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x)
2135 
2136 #define DOCTEST_ADD_AT_IMPL(type, file, line, mb, ...)                                             \
2137     do {                                                                                           \
2138         doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type);                 \
2139         mb * __VA_ARGS__;                                                                          \
2140         DOCTEST_ASSERT_LOG_AND_REACT(mb);                                                          \
2141     } while(false)
2142 
2143 // clang-format off
2144 #define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__)
2145 #define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__)
2146 #define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__)
2147 // clang-format on
2148 
2149 #define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, __VA_ARGS__)
2150 #define DOCTEST_FAIL_CHECK(...) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, __VA_ARGS__)
2151 #define DOCTEST_FAIL(...) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, __VA_ARGS__)
2152 
2153 #define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility.
2154 
2155 #ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS
2156 
2157 #define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...)                                               \
2158     DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses")                  \
2159     doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__,         \
2160                                                __LINE__, #__VA_ARGS__);                            \
2161     DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.setResult(                                                     \
2162             doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type)                \
2163             << __VA_ARGS__))                                                                       \
2164     DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB)                                                      \
2165     DOCTEST_CLANG_SUPPRESS_WARNING_POP
2166 
2167 #define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...)                                               \
2168     do {                                                                                           \
2169         DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__);                                      \
2170     } while(false)
2171 
2172 #else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS
2173 
2174 // necessary for <ASSERT>_MESSAGE
2175 #define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1
2176 
2177 #define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...)                                               \
2178     DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses")                  \
2179     doctest::detail::decomp_assert(                                                                \
2180             doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__,                    \
2181             doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type)                \
2182                     << __VA_ARGS__) DOCTEST_CLANG_SUPPRESS_WARNING_POP
2183 
2184 #endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS
2185 
2186 #define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN, __VA_ARGS__)
2187 #define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK, __VA_ARGS__)
2188 #define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE, __VA_ARGS__)
2189 #define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN_FALSE, __VA_ARGS__)
2190 #define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK_FALSE, __VA_ARGS__)
2191 #define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__)
2192 
2193 // clang-format off
2194 #define DOCTEST_WARN_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } while(false)
2195 #define DOCTEST_CHECK_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } while(false)
2196 #define DOCTEST_REQUIRE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } while(false)
2197 #define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } while(false)
2198 #define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } while(false)
2199 #define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } while(false)
2200 // clang-format on
2201 
2202 #define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...)                                  \
2203     do {                                                                                           \
2204         if(!doctest::getContextOptions()->no_throw) {                                              \
2205             doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \
2206                                                        __LINE__, #expr, #__VA_ARGS__, message);    \
2207             try {                                                                                  \
2208                 DOCTEST_CAST_TO_VOID(expr)                                                         \
2209             } catch(const typename doctest::detail::remove_const<                                  \
2210                     typename doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) {       \
2211                 _DOCTEST_RB.translateException();                                                  \
2212                 _DOCTEST_RB.m_threw_as = true;                                                     \
2213             } catch(...) { _DOCTEST_RB.translateException(); }                                     \
2214             DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                                             \
2215         }                                                                                          \
2216     } while(false)
2217 
2218 #define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...)                               \
2219     do {                                                                                           \
2220         if(!doctest::getContextOptions()->no_throw) {                                              \
2221             doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \
2222                                                        __LINE__, expr_str, "", __VA_ARGS__);       \
2223             try {                                                                                  \
2224                 DOCTEST_CAST_TO_VOID(expr)                                                         \
2225             } catch(...) { _DOCTEST_RB.translateException(); }                                     \
2226             DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                                             \
2227         }                                                                                          \
2228     } while(false)
2229 
2230 #define DOCTEST_ASSERT_NOTHROW(assert_type, ...)                                                   \
2231     do {                                                                                           \
2232         doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__,     \
2233                                                    __LINE__, #__VA_ARGS__);                        \
2234         try {                                                                                      \
2235             DOCTEST_CAST_TO_VOID(__VA_ARGS__)                                                      \
2236         } catch(...) { _DOCTEST_RB.translateException(); }                                         \
2237         DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                                                 \
2238     } while(false)
2239 
2240 // clang-format off
2241 #define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "")
2242 #define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "")
2243 #define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "")
2244 
2245 #define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__)
2246 #define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__)
2247 #define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__)
2248 
2249 #define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__)
2250 #define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__)
2251 #define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__)
2252 
2253 #define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__)
2254 #define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__)
2255 #define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__)
2256 
2257 #define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__)
2258 #define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__)
2259 #define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__)
2260 
2261 #define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS(expr); } while(false)
2262 #define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS(expr); } while(false)
2263 #define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS(expr); } while(false)
2264 #define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_AS(expr, ex); } while(false)
2265 #define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_AS(expr, ex); } while(false)
2266 #define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while(false)
2267 #define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH(expr, with); } while(false)
2268 #define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH(expr, with); } while(false)
2269 #define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } while(false)
2270 #define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } while(false)
2271 #define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } while(false)
2272 #define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } while(false)
2273 #define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_NOTHROW(expr); } while(false)
2274 #define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_NOTHROW(expr); } while(false)
2275 #define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_NOTHROW(expr); } while(false)
2276 // clang-format on
2277 
2278 #ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS
2279 
2280 #define DOCTEST_BINARY_ASSERT(assert_type, comp, ...)                                              \
2281     do {                                                                                           \
2282         doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__,     \
2283                                                    __LINE__, #__VA_ARGS__);                        \
2284         DOCTEST_WRAP_IN_TRY(                                                                       \
2285                 _DOCTEST_RB.binary_assert<doctest::detail::binaryAssertComparison::comp>(          \
2286                         __VA_ARGS__))                                                              \
2287         DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                                                 \
2288     } while(false)
2289 
2290 #define DOCTEST_UNARY_ASSERT(assert_type, ...)                                                     \
2291     do {                                                                                           \
2292         doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__,     \
2293                                                    __LINE__, #__VA_ARGS__);                        \
2294         DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(__VA_ARGS__))                                 \
2295         DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                                                 \
2296     } while(false)
2297 
2298 #else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS
2299 
2300 #define DOCTEST_BINARY_ASSERT(assert_type, comparison, ...)                                        \
2301     doctest::detail::binary_assert<doctest::detail::binaryAssertComparison::comparison>(           \
2302             doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__)
2303 
2304 #define DOCTEST_UNARY_ASSERT(assert_type, ...)                                                     \
2305     doctest::detail::unary_assert(doctest::assertType::assert_type, __FILE__, __LINE__,            \
2306                                   #__VA_ARGS__, __VA_ARGS__)
2307 
2308 #endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS
2309 
2310 #define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, eq, __VA_ARGS__)
2311 #define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, eq, __VA_ARGS__)
2312 #define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, eq, __VA_ARGS__)
2313 #define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, ne, __VA_ARGS__)
2314 #define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, ne, __VA_ARGS__)
2315 #define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, ne, __VA_ARGS__)
2316 #define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, gt, __VA_ARGS__)
2317 #define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, gt, __VA_ARGS__)
2318 #define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, gt, __VA_ARGS__)
2319 #define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lt, __VA_ARGS__)
2320 #define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lt, __VA_ARGS__)
2321 #define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lt, __VA_ARGS__)
2322 #define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, ge, __VA_ARGS__)
2323 #define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, ge, __VA_ARGS__)
2324 #define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, ge, __VA_ARGS__)
2325 #define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, le, __VA_ARGS__)
2326 #define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, le, __VA_ARGS__)
2327 #define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, le, __VA_ARGS__)
2328 
2329 #define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, __VA_ARGS__)
2330 #define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, __VA_ARGS__)
2331 #define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, __VA_ARGS__)
2332 #define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, __VA_ARGS__)
2333 #define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, __VA_ARGS__)
2334 #define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, __VA_ARGS__)
2335 
2336 #ifdef DOCTEST_CONFIG_NO_EXCEPTIONS
2337 
2338 #undef DOCTEST_WARN_THROWS
2339 #undef DOCTEST_CHECK_THROWS
2340 #undef DOCTEST_REQUIRE_THROWS
2341 #undef DOCTEST_WARN_THROWS_AS
2342 #undef DOCTEST_CHECK_THROWS_AS
2343 #undef DOCTEST_REQUIRE_THROWS_AS
2344 #undef DOCTEST_WARN_THROWS_WITH
2345 #undef DOCTEST_CHECK_THROWS_WITH
2346 #undef DOCTEST_REQUIRE_THROWS_WITH
2347 #undef DOCTEST_WARN_THROWS_WITH_AS
2348 #undef DOCTEST_CHECK_THROWS_WITH_AS
2349 #undef DOCTEST_REQUIRE_THROWS_WITH_AS
2350 #undef DOCTEST_WARN_NOTHROW
2351 #undef DOCTEST_CHECK_NOTHROW
2352 #undef DOCTEST_REQUIRE_NOTHROW
2353 
2354 #undef DOCTEST_WARN_THROWS_MESSAGE
2355 #undef DOCTEST_CHECK_THROWS_MESSAGE
2356 #undef DOCTEST_REQUIRE_THROWS_MESSAGE
2357 #undef DOCTEST_WARN_THROWS_AS_MESSAGE
2358 #undef DOCTEST_CHECK_THROWS_AS_MESSAGE
2359 #undef DOCTEST_REQUIRE_THROWS_AS_MESSAGE
2360 #undef DOCTEST_WARN_THROWS_WITH_MESSAGE
2361 #undef DOCTEST_CHECK_THROWS_WITH_MESSAGE
2362 #undef DOCTEST_REQUIRE_THROWS_WITH_MESSAGE
2363 #undef DOCTEST_WARN_THROWS_WITH_AS_MESSAGE
2364 #undef DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE
2365 #undef DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE
2366 #undef DOCTEST_WARN_NOTHROW_MESSAGE
2367 #undef DOCTEST_CHECK_NOTHROW_MESSAGE
2368 #undef DOCTEST_REQUIRE_NOTHROW_MESSAGE
2369 
2370 #ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS
2371 
2372 #define DOCTEST_WARN_THROWS(...) (static_cast<void>(0))
2373 #define DOCTEST_CHECK_THROWS(...) (static_cast<void>(0))
2374 #define DOCTEST_REQUIRE_THROWS(...) (static_cast<void>(0))
2375 #define DOCTEST_WARN_THROWS_AS(expr, ...) (static_cast<void>(0))
2376 #define DOCTEST_CHECK_THROWS_AS(expr, ...) (static_cast<void>(0))
2377 #define DOCTEST_REQUIRE_THROWS_AS(expr, ...) (static_cast<void>(0))
2378 #define DOCTEST_WARN_THROWS_WITH(expr, ...) (static_cast<void>(0))
2379 #define DOCTEST_CHECK_THROWS_WITH(expr, ...) (static_cast<void>(0))
2380 #define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) (static_cast<void>(0))
2381 #define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
2382 #define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
2383 #define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
2384 #define DOCTEST_WARN_NOTHROW(...) (static_cast<void>(0))
2385 #define DOCTEST_CHECK_NOTHROW(...) (static_cast<void>(0))
2386 #define DOCTEST_REQUIRE_NOTHROW(...) (static_cast<void>(0))
2387 
2388 #define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
2389 #define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
2390 #define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
2391 #define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
2392 #define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
2393 #define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
2394 #define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
2395 #define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
2396 #define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
2397 #define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
2398 #define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
2399 #define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
2400 #define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
2401 #define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
2402 #define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
2403 
2404 #else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS
2405 
2406 #undef DOCTEST_REQUIRE
2407 #undef DOCTEST_REQUIRE_FALSE
2408 #undef DOCTEST_REQUIRE_MESSAGE
2409 #undef DOCTEST_REQUIRE_FALSE_MESSAGE
2410 #undef DOCTEST_REQUIRE_EQ
2411 #undef DOCTEST_REQUIRE_NE
2412 #undef DOCTEST_REQUIRE_GT
2413 #undef DOCTEST_REQUIRE_LT
2414 #undef DOCTEST_REQUIRE_GE
2415 #undef DOCTEST_REQUIRE_LE
2416 #undef DOCTEST_REQUIRE_UNARY
2417 #undef DOCTEST_REQUIRE_UNARY_FALSE
2418 
2419 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS
2420 
2421 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
2422 
2423 // =================================================================================================
2424 // == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING!                      ==
2425 // == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY!                            ==
2426 // =================================================================================================
2427 #else // DOCTEST_CONFIG_DISABLE
2428 
2429 #define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name)                                           \
2430     namespace {                                                                                    \
2431         template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                                           \
2432         struct der : public base                                                                   \
2433         { void f(); };                                                                             \
2434     }                                                                                              \
2435     template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                                               \
2436     inline void der<DOCTEST_UNUSED_TEMPLATE_TYPE>::f()
2437 
2438 #define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name)                                              \
2439     template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                                               \
2440     static inline void f()
2441 
2442 // for registering tests
2443 #define DOCTEST_TEST_CASE(name)                                                                    \
2444     DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name)
2445 
2446 // for registering tests in classes
2447 #define DOCTEST_TEST_CASE_CLASS(name)                                                              \
2448     DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name)
2449 
2450 // for registering tests with a fixture
2451 #define DOCTEST_TEST_CASE_FIXTURE(x, name)                                                         \
2452     DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x,                          \
2453                               DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name)
2454 
2455 // for converting types to strings without the <typeinfo> header and demangling
2456 #define DOCTEST_TYPE_TO_STRING(...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2457 #define DOCTEST_TYPE_TO_STRING_IMPL(...)
2458 
2459 // for typed tests
2460 #define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...)                                                \
2461     template <typename type>                                                                       \
2462     inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)()
2463 
2464 #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id)                                          \
2465     template <typename type>                                                                       \
2466     inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)()
2467 
2468 #define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...)                                                 \
2469     typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2470 
2471 #define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...)                                                  \
2472     typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2473 
2474 // for subcases
2475 #define DOCTEST_SUBCASE(name)
2476 
2477 // for a testsuite block
2478 #define DOCTEST_TEST_SUITE(name) namespace
2479 
2480 // for starting a testsuite block
2481 #define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2482 
2483 // for ending a testsuite block
2484 #define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
2485 
2486 #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)                                           \
2487     template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                                               \
2488     static inline doctest::String DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature)
2489 
2490 #define DOCTEST_REGISTER_REPORTER(name, priority, reporter)
2491 #define DOCTEST_REGISTER_LISTENER(name, priority, reporter)
2492 
2493 #define DOCTEST_INFO(...) (static_cast<void>(0))
2494 #define DOCTEST_CAPTURE(x) (static_cast<void>(0))
2495 #define DOCTEST_ADD_MESSAGE_AT(file, line, ...) (static_cast<void>(0))
2496 #define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) (static_cast<void>(0))
2497 #define DOCTEST_ADD_FAIL_AT(file, line, ...) (static_cast<void>(0))
2498 #define DOCTEST_MESSAGE(...) (static_cast<void>(0))
2499 #define DOCTEST_FAIL_CHECK(...) (static_cast<void>(0))
2500 #define DOCTEST_FAIL(...) (static_cast<void>(0))
2501 
2502 #define DOCTEST_WARN(...) (static_cast<void>(0))
2503 #define DOCTEST_CHECK(...) (static_cast<void>(0))
2504 #define DOCTEST_REQUIRE(...) (static_cast<void>(0))
2505 #define DOCTEST_WARN_FALSE(...) (static_cast<void>(0))
2506 #define DOCTEST_CHECK_FALSE(...) (static_cast<void>(0))
2507 #define DOCTEST_REQUIRE_FALSE(...) (static_cast<void>(0))
2508 
2509 #define DOCTEST_WARN_MESSAGE(cond, ...) (static_cast<void>(0))
2510 #define DOCTEST_CHECK_MESSAGE(cond, ...) (static_cast<void>(0))
2511 #define DOCTEST_REQUIRE_MESSAGE(cond, ...) (static_cast<void>(0))
2512 #define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) (static_cast<void>(0))
2513 #define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) (static_cast<void>(0))
2514 #define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) (static_cast<void>(0))
2515 
2516 #define DOCTEST_WARN_THROWS(...) (static_cast<void>(0))
2517 #define DOCTEST_CHECK_THROWS(...) (static_cast<void>(0))
2518 #define DOCTEST_REQUIRE_THROWS(...) (static_cast<void>(0))
2519 #define DOCTEST_WARN_THROWS_AS(expr, ...) (static_cast<void>(0))
2520 #define DOCTEST_CHECK_THROWS_AS(expr, ...) (static_cast<void>(0))
2521 #define DOCTEST_REQUIRE_THROWS_AS(expr, ...) (static_cast<void>(0))
2522 #define DOCTEST_WARN_THROWS_WITH(expr, ...) (static_cast<void>(0))
2523 #define DOCTEST_CHECK_THROWS_WITH(expr, ...) (static_cast<void>(0))
2524 #define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) (static_cast<void>(0))
2525 #define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
2526 #define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
2527 #define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
2528 #define DOCTEST_WARN_NOTHROW(...) (static_cast<void>(0))
2529 #define DOCTEST_CHECK_NOTHROW(...) (static_cast<void>(0))
2530 #define DOCTEST_REQUIRE_NOTHROW(...) (static_cast<void>(0))
2531 
2532 #define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
2533 #define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
2534 #define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
2535 #define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
2536 #define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
2537 #define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
2538 #define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
2539 #define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
2540 #define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
2541 #define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
2542 #define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
2543 #define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
2544 #define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
2545 #define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
2546 #define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
2547 
2548 #define DOCTEST_WARN_EQ(...) (static_cast<void>(0))
2549 #define DOCTEST_CHECK_EQ(...) (static_cast<void>(0))
2550 #define DOCTEST_REQUIRE_EQ(...) (static_cast<void>(0))
2551 #define DOCTEST_WARN_NE(...) (static_cast<void>(0))
2552 #define DOCTEST_CHECK_NE(...) (static_cast<void>(0))
2553 #define DOCTEST_REQUIRE_NE(...) (static_cast<void>(0))
2554 #define DOCTEST_WARN_GT(...) (static_cast<void>(0))
2555 #define DOCTEST_CHECK_GT(...) (static_cast<void>(0))
2556 #define DOCTEST_REQUIRE_GT(...) (static_cast<void>(0))
2557 #define DOCTEST_WARN_LT(...) (static_cast<void>(0))
2558 #define DOCTEST_CHECK_LT(...) (static_cast<void>(0))
2559 #define DOCTEST_REQUIRE_LT(...) (static_cast<void>(0))
2560 #define DOCTEST_WARN_GE(...) (static_cast<void>(0))
2561 #define DOCTEST_CHECK_GE(...) (static_cast<void>(0))
2562 #define DOCTEST_REQUIRE_GE(...) (static_cast<void>(0))
2563 #define DOCTEST_WARN_LE(...) (static_cast<void>(0))
2564 #define DOCTEST_CHECK_LE(...) (static_cast<void>(0))
2565 #define DOCTEST_REQUIRE_LE(...) (static_cast<void>(0))
2566 
2567 #define DOCTEST_WARN_UNARY(...) (static_cast<void>(0))
2568 #define DOCTEST_CHECK_UNARY(...) (static_cast<void>(0))
2569 #define DOCTEST_REQUIRE_UNARY(...) (static_cast<void>(0))
2570 #define DOCTEST_WARN_UNARY_FALSE(...) (static_cast<void>(0))
2571 #define DOCTEST_CHECK_UNARY_FALSE(...) (static_cast<void>(0))
2572 #define DOCTEST_REQUIRE_UNARY_FALSE(...) (static_cast<void>(0))
2573 
2574 #endif // DOCTEST_CONFIG_DISABLE
2575 
2576 // clang-format off
2577 // KEPT FOR BACKWARDS COMPATIBILITY - FORWARDING TO THE RIGHT MACROS
2578 #define DOCTEST_FAST_WARN_EQ             DOCTEST_WARN_EQ
2579 #define DOCTEST_FAST_CHECK_EQ            DOCTEST_CHECK_EQ
2580 #define DOCTEST_FAST_REQUIRE_EQ          DOCTEST_REQUIRE_EQ
2581 #define DOCTEST_FAST_WARN_NE             DOCTEST_WARN_NE
2582 #define DOCTEST_FAST_CHECK_NE            DOCTEST_CHECK_NE
2583 #define DOCTEST_FAST_REQUIRE_NE          DOCTEST_REQUIRE_NE
2584 #define DOCTEST_FAST_WARN_GT             DOCTEST_WARN_GT
2585 #define DOCTEST_FAST_CHECK_GT            DOCTEST_CHECK_GT
2586 #define DOCTEST_FAST_REQUIRE_GT          DOCTEST_REQUIRE_GT
2587 #define DOCTEST_FAST_WARN_LT             DOCTEST_WARN_LT
2588 #define DOCTEST_FAST_CHECK_LT            DOCTEST_CHECK_LT
2589 #define DOCTEST_FAST_REQUIRE_LT          DOCTEST_REQUIRE_LT
2590 #define DOCTEST_FAST_WARN_GE             DOCTEST_WARN_GE
2591 #define DOCTEST_FAST_CHECK_GE            DOCTEST_CHECK_GE
2592 #define DOCTEST_FAST_REQUIRE_GE          DOCTEST_REQUIRE_GE
2593 #define DOCTEST_FAST_WARN_LE             DOCTEST_WARN_LE
2594 #define DOCTEST_FAST_CHECK_LE            DOCTEST_CHECK_LE
2595 #define DOCTEST_FAST_REQUIRE_LE          DOCTEST_REQUIRE_LE
2596 
2597 #define DOCTEST_FAST_WARN_UNARY          DOCTEST_WARN_UNARY
2598 #define DOCTEST_FAST_CHECK_UNARY         DOCTEST_CHECK_UNARY
2599 #define DOCTEST_FAST_REQUIRE_UNARY       DOCTEST_REQUIRE_UNARY
2600 #define DOCTEST_FAST_WARN_UNARY_FALSE    DOCTEST_WARN_UNARY_FALSE
2601 #define DOCTEST_FAST_CHECK_UNARY_FALSE   DOCTEST_CHECK_UNARY_FALSE
2602 #define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE
2603 
2604 #define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__)
2605 // clang-format on
2606 
2607 // BDD style macros
2608 // clang-format off
2609 #define DOCTEST_SCENARIO(name) DOCTEST_TEST_CASE("  Scenario: " name)
2610 #define DOCTEST_SCENARIO_CLASS(name) DOCTEST_TEST_CASE_CLASS("  Scenario: " name)
2611 #define DOCTEST_SCENARIO_TEMPLATE(name, T, ...)  DOCTEST_TEST_CASE_TEMPLATE("  Scenario: " name, T, __VA_ARGS__)
2612 #define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE("  Scenario: " name, T, id)
2613 
2614 #define DOCTEST_GIVEN(name)     DOCTEST_SUBCASE("   Given: " name)
2615 #define DOCTEST_WHEN(name)      DOCTEST_SUBCASE("    When: " name)
2616 #define DOCTEST_AND_WHEN(name)  DOCTEST_SUBCASE("And when: " name)
2617 #define DOCTEST_THEN(name)      DOCTEST_SUBCASE("    Then: " name)
2618 #define DOCTEST_AND_THEN(name)  DOCTEST_SUBCASE("     And: " name)
2619 // clang-format on
2620 
2621 // == SHORT VERSIONS OF THE MACROS
2622 #if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES)
2623 
2624 #define TEST_CASE(name) DOCTEST_TEST_CASE(name)
2625 #define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name)
2626 #define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name)
2627 #define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__)
2628 #define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__)
2629 #define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id)
2630 #define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__)
2631 #define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__)
2632 #define SUBCASE(name) DOCTEST_SUBCASE(name)
2633 #define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators)
2634 #define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name)
2635 #define TEST_SUITE_END DOCTEST_TEST_SUITE_END
2636 #define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)
2637 #define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter)
2638 #define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter)
2639 #define INFO(...) DOCTEST_INFO(__VA_ARGS__)
2640 #define CAPTURE(x) DOCTEST_CAPTURE(x)
2641 #define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__)
2642 #define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__)
2643 #define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__)
2644 #define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__)
2645 #define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__)
2646 #define FAIL(...) DOCTEST_FAIL(__VA_ARGS__)
2647 #define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__)
2648 
2649 #define WARN(...) DOCTEST_WARN(__VA_ARGS__)
2650 #define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__)
2651 #define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__)
2652 #define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__)
2653 #define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__)
2654 #define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__)
2655 #define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__)
2656 #define CHECK(...) DOCTEST_CHECK(__VA_ARGS__)
2657 #define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__)
2658 #define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__)
2659 #define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__)
2660 #define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__)
2661 #define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__)
2662 #define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__)
2663 #define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__)
2664 #define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__)
2665 #define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__)
2666 #define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__)
2667 #define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__)
2668 #define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__)
2669 #define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__)
2670 
2671 #define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__)
2672 #define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__)
2673 #define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__)
2674 #define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
2675 #define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
2676 #define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
2677 #define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__)
2678 #define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__)
2679 #define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__)
2680 #define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__)
2681 #define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
2682 #define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
2683 #define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
2684 #define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__)
2685 #define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__)
2686 #define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__)
2687 #define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__)
2688 #define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
2689 #define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
2690 #define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
2691 #define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__)
2692 
2693 #define SCENARIO(name) DOCTEST_SCENARIO(name)
2694 #define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name)
2695 #define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__)
2696 #define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id)
2697 #define GIVEN(name) DOCTEST_GIVEN(name)
2698 #define WHEN(name) DOCTEST_WHEN(name)
2699 #define AND_WHEN(name) DOCTEST_AND_WHEN(name)
2700 #define THEN(name) DOCTEST_THEN(name)
2701 #define AND_THEN(name) DOCTEST_AND_THEN(name)
2702 
2703 #define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__)
2704 #define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__)
2705 #define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__)
2706 #define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__)
2707 #define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__)
2708 #define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__)
2709 #define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__)
2710 #define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__)
2711 #define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__)
2712 #define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__)
2713 #define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__)
2714 #define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__)
2715 #define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__)
2716 #define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__)
2717 #define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__)
2718 #define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__)
2719 #define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__)
2720 #define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__)
2721 #define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__)
2722 #define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__)
2723 #define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__)
2724 #define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__)
2725 #define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__)
2726 #define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__)
2727 
2728 // KEPT FOR BACKWARDS COMPATIBILITY
2729 #define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__)
2730 #define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__)
2731 #define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__)
2732 #define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__)
2733 #define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__)
2734 #define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__)
2735 #define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__)
2736 #define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__)
2737 #define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__)
2738 #define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__)
2739 #define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__)
2740 #define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__)
2741 #define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__)
2742 #define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__)
2743 #define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__)
2744 #define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__)
2745 #define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__)
2746 #define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__)
2747 
2748 #define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__)
2749 #define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__)
2750 #define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__)
2751 #define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__)
2752 #define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__)
2753 #define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__)
2754 
2755 #define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__)
2756 
2757 #endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES
2758 
2759 #if !defined(DOCTEST_CONFIG_DISABLE)
2760 
2761 // this is here to clear the 'current test suite' for the current translation unit - at the top
2762 DOCTEST_TEST_SUITE_END();
2763 
2764 // add stringification for primitive/fundamental types
2765 namespace doctest { namespace detail {
2766     DOCTEST_TYPE_TO_STRING_IMPL(bool)
2767     DOCTEST_TYPE_TO_STRING_IMPL(float)
2768     DOCTEST_TYPE_TO_STRING_IMPL(double)
2769     DOCTEST_TYPE_TO_STRING_IMPL(long double)
2770     DOCTEST_TYPE_TO_STRING_IMPL(char)
2771     DOCTEST_TYPE_TO_STRING_IMPL(signed char)
2772     DOCTEST_TYPE_TO_STRING_IMPL(unsigned char)
2773 #if !DOCTEST_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
2774     DOCTEST_TYPE_TO_STRING_IMPL(wchar_t)
2775 #endif // not MSVC or wchar_t support enabled
2776     DOCTEST_TYPE_TO_STRING_IMPL(short int)
2777     DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int)
2778     DOCTEST_TYPE_TO_STRING_IMPL(int)
2779     DOCTEST_TYPE_TO_STRING_IMPL(unsigned int)
2780     DOCTEST_TYPE_TO_STRING_IMPL(long int)
2781     DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int)
2782     DOCTEST_TYPE_TO_STRING_IMPL(long long int)
2783     DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int)
2784 }} // namespace doctest::detail
2785 
2786 #endif // DOCTEST_CONFIG_DISABLE
2787 
2788 DOCTEST_CLANG_SUPPRESS_WARNING_POP
2789 DOCTEST_MSVC_SUPPRESS_WARNING_POP
2790 DOCTEST_GCC_SUPPRESS_WARNING_POP
2791 
2792 #endif // DOCTEST_LIBRARY_INCLUDED
2793 
2794 #ifndef DOCTEST_SINGLE_HEADER
2795 #define DOCTEST_SINGLE_HEADER
2796 #endif // DOCTEST_SINGLE_HEADER
2797 
2798 #if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER)
2799 
2800 #ifndef DOCTEST_SINGLE_HEADER
2801 #include "doctest_fwd.h"
2802 #endif // DOCTEST_SINGLE_HEADER
2803 
2804 DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros")
2805 
2806 #ifndef DOCTEST_LIBRARY_IMPLEMENTATION
2807 #define DOCTEST_LIBRARY_IMPLEMENTATION
2808 
2809 DOCTEST_CLANG_SUPPRESS_WARNING_POP
2810 
2811 DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
2812 DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas")
2813 DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded")
2814 DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables")
2815 DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors")
2816 DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
2817 DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes")
2818 DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion")
2819 DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32")
2820 DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations")
2821 DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch")
2822 DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum")
2823 DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default")
2824 DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn")
2825 DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef")
2826 DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion")
2827 DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces")
2828 DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers")
2829 DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
2830 DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
2831 DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function")
2832 DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path")
2833 
2834 DOCTEST_GCC_SUPPRESS_WARNING_PUSH
2835 DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas")
2836 DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas")
2837 DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion")
2838 DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++")
2839 DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion")
2840 DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow")
2841 DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing")
2842 DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers")
2843 DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces")
2844 DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations")
2845 DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch")
2846 DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum")
2847 DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default")
2848 DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations")
2849 DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast")
2850 DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs")
2851 DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast")
2852 DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function")
2853 DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance")
2854 DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept")
2855 DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute")
2856 
2857 DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
2858 DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning
2859 DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning
2860 DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration
2861 DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data
2862 DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression
2863 DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated
2864 DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant
2865 DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled
2866 DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified
2867 DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal
2868 DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch
2869 DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding in structs
2870 DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe
2871 DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C
2872 DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation stuff
2873 DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted
2874 DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted
2875 DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted
2876 DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted
2877 DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning)
2878 // static analysis
2879 DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept'
2880 DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable
2881 DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ...
2882 DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtor...
2883 DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum'
2884 
2885 DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
2886 
2887 // required includes - will go only in one translation unit!
2888 #include <ctime>
2889 #include <cmath>
2890 #include <climits>
2891 // borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37
2892 #ifdef __BORLANDC__
2893 #include <math.h>
2894 #endif // __BORLANDC__
2895 #include <new>
2896 #include <cstdio>
2897 #include <cstdlib>
2898 #include <cstring>
2899 #include <limits>
2900 #include <utility>
2901 #include <fstream>
2902 #include <sstream>
2903 #include <iostream>
2904 #include <algorithm>
2905 #include <iomanip>
2906 #include <vector>
2907 #include <atomic>
2908 #include <mutex>
2909 #include <set>
2910 #include <map>
2911 #include <exception>
2912 #include <stdexcept>
2913 #include <csignal>
2914 #include <cfloat>
2915 #include <cctype>
2916 #include <cstdint>
2917 
2918 #ifdef DOCTEST_PLATFORM_MAC
2919 #include <sys/types.h>
2920 #include <unistd.h>
2921 #include <sys/sysctl.h>
2922 #endif // DOCTEST_PLATFORM_MAC
2923 
2924 #ifdef DOCTEST_PLATFORM_WINDOWS
2925 
2926 // defines for a leaner windows.h
2927 #ifndef WIN32_LEAN_AND_MEAN
2928 #define WIN32_LEAN_AND_MEAN
2929 #endif // WIN32_LEAN_AND_MEAN
2930 #ifndef NOMINMAX
2931 #define NOMINMAX
2932 #endif // NOMINMAX
2933 
2934 // not sure what AfxWin.h is for - here I do what Catch does
2935 #ifdef __AFXDLL
2936 #include <AfxWin.h>
2937 #else
2938 #include <windows.h>
2939 #endif
2940 #include <io.h>
2941 
2942 #else // DOCTEST_PLATFORM_WINDOWS
2943 
2944 #include <sys/time.h>
2945 #include <unistd.h>
2946 
2947 #endif // DOCTEST_PLATFORM_WINDOWS
2948 
2949 // this is a fix for https://github.com/onqtam/doctest/issues/348
2950 // https://mail.gnome.org/archives/xml/2012-January/msg00000.html
2951 #if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO)
2952 #define STDOUT_FILENO fileno(stdout)
2953 #endif // HAVE_UNISTD_H
2954 
2955 DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
2956 
2957 // counts the number of elements in a C array
2958 #define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0]))
2959 
2960 #ifdef DOCTEST_CONFIG_DISABLE
2961 #define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled
2962 #else // DOCTEST_CONFIG_DISABLE
2963 #define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled
2964 #endif // DOCTEST_CONFIG_DISABLE
2965 
2966 #ifndef DOCTEST_CONFIG_OPTIONS_PREFIX
2967 #define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-"
2968 #endif
2969 
2970 #ifndef DOCTEST_THREAD_LOCAL
2971 #define DOCTEST_THREAD_LOCAL thread_local
2972 #endif
2973 
2974 #ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES
2975 #define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32
2976 #endif
2977 
2978 #ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE
2979 #define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64
2980 #endif
2981 
2982 #ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
2983 #define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX
2984 #else
2985 #define DOCTEST_OPTIONS_PREFIX_DISPLAY ""
2986 #endif
2987 
2988 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
2989 #define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
2990 #endif
2991 
2992 namespace doctest {
2993 
2994 bool is_running_in_test = false;
2995 
2996 namespace {
2997     using namespace detail;
2998     // case insensitive strcmp
2999     int stricmp(const char* a, const char* b) {
3000         for(;; a++, b++) {
3001             const int d = tolower(*a) - tolower(*b);
3002             if(d != 0 || !*a)
3003                 return d;
3004         }
3005     }
3006 
3007     template <typename T>
3008     String fpToString(T value, int precision) {
3009         std::ostringstream oss;
3010         oss << std::setprecision(precision) << std::fixed << value;
3011         std::string d = oss.str();
3012         size_t      i = d.find_last_not_of('0');
3013         if(i != std::string::npos && i != d.size() - 1) {
3014             if(d[i] == '.')
3015                 i++;
3016             d = d.substr(0, i + 1);
3017         }
3018         return d.c_str();
3019     }
3020 
3021     struct Endianness
3022     {
3023         enum Arch
3024         {
3025             Big,
3026             Little
3027         };
3028 
3029         static Arch which() {
3030             int x = 1;
3031             // casting any data pointer to char* is allowed
3032             auto ptr = reinterpret_cast<char*>(&x);
3033             if(*ptr)
3034                 return Little;
3035             return Big;
3036         }
3037     };
3038 } // namespace
3039 
3040 namespace detail {
3041     void my_memcpy(void* dest, const void* src, unsigned num) { memcpy(dest, src, num); }
3042 
3043     String rawMemoryToString(const void* object, unsigned size) {
3044         // Reverse order for little endian architectures
3045         int i = 0, end = static_cast<int>(size), inc = 1;
3046         if(Endianness::which() == Endianness::Little) {
3047             i   = end - 1;
3048             end = inc = -1;
3049         }
3050 
3051         unsigned const char* bytes = static_cast<unsigned const char*>(object);
3052         std::ostringstream   oss;
3053         oss << "0x" << std::setfill('0') << std::hex;
3054         for(; i != end; i += inc)
3055             oss << std::setw(2) << static_cast<unsigned>(bytes[i]);
3056         return oss.str().c_str();
3057     }
3058 
3059     DOCTEST_THREAD_LOCAL doctest_thread_local_wrapper<std::ostringstream> wrapped_g_oss; // NOLINT(cert-err58-cpp)
3060 
3061     std::ostream* getTlsOss() {
3062         auto& g_oss = wrapped_g_oss.get();
3063         g_oss.clear(); // there shouldn't be anything worth clearing in the flags
3064         g_oss.str(""); // the slow way of resetting a string stream
3065         //g_oss.seekp(0); // optimal reset - as seen here: https://stackoverflow.com/a/624291/3162383
3066         return &g_oss;
3067     }
3068 
3069     String getTlsOssResult() {
3070         //g_oss << std::ends; // needed - as shown here: https://stackoverflow.com/a/624291/3162383
3071         return wrapped_g_oss.get().str().c_str();
3072     }
3073 
3074 #ifndef DOCTEST_CONFIG_DISABLE
3075 
3076 namespace timer_large_integer
3077 {
3078 
3079 #if defined(DOCTEST_PLATFORM_WINDOWS)
3080     typedef ULONGLONG type;
3081 #else // DOCTEST_PLATFORM_WINDOWS
3082     using namespace std;
3083     typedef uint64_t type;
3084 #endif // DOCTEST_PLATFORM_WINDOWS
3085 }
3086 
3087 typedef timer_large_integer::type ticks_t;
3088 
3089 #ifdef DOCTEST_CONFIG_GETCURRENTTICKS
3090     ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); }
3091 #elif defined(DOCTEST_PLATFORM_WINDOWS)
3092     ticks_t getCurrentTicks() {
3093         static LARGE_INTEGER hz = {0}, hzo = {0};
3094         if(!hz.QuadPart) {
3095             QueryPerformanceFrequency(&hz);
3096             QueryPerformanceCounter(&hzo);
3097         }
3098         LARGE_INTEGER t;
3099         QueryPerformanceCounter(&t);
3100         return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart;
3101     }
3102 #else  // DOCTEST_PLATFORM_WINDOWS
3103     ticks_t getCurrentTicks() {
3104         timeval t;
3105         gettimeofday(&t, nullptr);
3106         return static_cast<ticks_t>(t.tv_sec) * 1000000 + static_cast<ticks_t>(t.tv_usec);
3107     }
3108 #endif // DOCTEST_PLATFORM_WINDOWS
3109 
3110     struct Timer
3111     {
3112         void         start() { m_ticks = getCurrentTicks(); }
3113         unsigned int getElapsedMicroseconds() const {
3114             return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
3115         }
3116         //unsigned int getElapsedMilliseconds() const {
3117         //    return static_cast<unsigned int>(getElapsedMicroseconds() / 1000);
3118         //}
3119         double getElapsedSeconds() const { return static_cast<double>(getCurrentTicks() - m_ticks) / 1000000.0; }
3120 
3121     private:
3122         ticks_t m_ticks = 0;
3123     };
3124 
3125 #ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
3126     template <typename T>
3127     using AtomicOrMultiLaneAtomic = std::atomic<T>;
3128 #else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
3129     // Provides a multilane implementation of an atomic variable that supports add, sub, load,
3130     // store. Instead of using a single atomic variable, this splits up into multiple ones,
3131     // each sitting on a separate cache line. The goal is to provide a speedup when most
3132     // operations are modifying. It achieves this with two properties:
3133     //
3134     // * Multiple atomics are used, so chance of congestion from the same atomic is reduced.
3135     // * Each atomic sits on a separate cache line, so false sharing is reduced.
3136     //
3137     // The disadvantage is that there is a small overhead due to the use of TLS, and load/store
3138     // is slower because all atomics have to be accessed.
3139     template <typename T>
3140     class MultiLaneAtomic
3141     {
3142         struct CacheLineAlignedAtomic
3143         {
3144             std::atomic<T> atomic{};
3145             char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)];
3146         };
3147         CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES];
3148 
3149         static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE,
3150                       "guarantee one atomic takes exactly one cache line");
3151 
3152     public:
3153         T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; }
3154 
3155         T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); }
3156 
3157         T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
3158             return myAtomic().fetch_add(arg, order);
3159         }
3160 
3161         T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
3162             return myAtomic().fetch_sub(arg, order);
3163         }
3164 
3165         operator T() const DOCTEST_NOEXCEPT { return load(); }
3166 
3167         T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT {
3168             auto result = T();
3169             for(auto const& c : m_atomics) {
3170                 result += c.atomic.load(order);
3171             }
3172             return result;
3173         }
3174 
3175         T operator=(T desired) DOCTEST_NOEXCEPT {
3176             store(desired);
3177             return desired;
3178         }
3179 
3180         void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
3181             // first value becomes desired", all others become 0.
3182             for(auto& c : m_atomics) {
3183                 c.atomic.store(desired, order);
3184                 desired = {};
3185             }
3186         }
3187 
3188     private:
3189         // TODO: upstream the change to doctest : Fix the typo (word "degrade")
3190         // Each thread has a different atomic that it operates on. If more than NumLanes threads
3191         // use this, some will use the same atomic. So performance will degrade a bit, but still
3192         // everything will work.
3193         //
3194         // The logic here is a bit tricky. The call should be as fast as possible, so that there
3195         // is minimal to no overhead in determining the correct atomic for the current thread.
3196         //
3197         // 1. A global static counter laneCounter counts continuously up.
3198         // 2. Each successive thread will use modulo operation of that counter so it gets an atomic
3199         //    assigned in a round-robin fashion.
3200         // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with
3201         //    little overhead.
3202         std::atomic<T>& myAtomic() DOCTEST_NOEXCEPT {
3203             static std::atomic<size_t> laneCounter;
3204             DOCTEST_THREAD_LOCAL size_t tlsLaneIdx =
3205                     laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES;
3206 
3207             return m_atomics[tlsLaneIdx].atomic;
3208         }
3209     };
3210 
3211     template <typename T>
3212     using AtomicOrMultiLaneAtomic = MultiLaneAtomic<T>;
3213 #endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
3214 
3215     // this holds both parameters from the command line and runtime data for tests
3216     struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats
3217     {
3218         AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic;
3219         AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
3220 
3221         std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters
3222 
3223         std::vector<IReporter*> reporters_currently_used;
3224 
3225         assert_handler ah = nullptr;
3226 
3227         Timer timer;
3228 
3229         std::vector<String> stringifiedContexts; // logging from INFO() due to an exception
3230 
3231         // stuff for subcases
3232         std::vector<SubcaseSignature>     subcasesStack;
3233         std::set<decltype(subcasesStack)> subcasesPassed;
3234         int                               subcasesCurrentMaxLevel;
3235         bool                              should_reenter;
3236         std::atomic<bool>                 shouldLogCurrentException;
3237 
3238         void resetRunData() {
3239             numTestCases                = 0;
3240             numTestCasesPassingFilters  = 0;
3241             numTestSuitesPassingFilters = 0;
3242             numTestCasesFailed          = 0;
3243             numAsserts                  = 0;
3244             numAssertsFailed            = 0;
3245             numAssertsCurrentTest       = 0;
3246             numAssertsFailedCurrentTest = 0;
3247         }
3248 
3249         void finalizeTestCaseData() {
3250             seconds = timer.getElapsedSeconds();
3251 
3252             // update the non-atomic counters
3253             numAsserts += numAssertsCurrentTest_atomic;
3254             numAssertsFailed += numAssertsFailedCurrentTest_atomic;
3255             numAssertsCurrentTest       = numAssertsCurrentTest_atomic;
3256             numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic;
3257 
3258             if(numAssertsFailedCurrentTest)
3259                 failure_flags |= TestCaseFailureReason::AssertFailure;
3260 
3261             if(Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 &&
3262                Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout)
3263                 failure_flags |= TestCaseFailureReason::Timeout;
3264 
3265             if(currentTest->m_should_fail) {
3266                 if(failure_flags) {
3267                     failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid;
3268                 } else {
3269                     failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt;
3270                 }
3271             } else if(failure_flags && currentTest->m_may_fail) {
3272                 failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid;
3273             } else if(currentTest->m_expected_failures > 0) {
3274                 if(numAssertsFailedCurrentTest == currentTest->m_expected_failures) {
3275                     failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes;
3276                 } else {
3277                     failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes;
3278                 }
3279             }
3280 
3281             bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) ||
3282                               (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) ||
3283                               (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags);
3284 
3285             // if any subcase has failed - the whole test case has failed
3286             if(failure_flags && !ok_to_fail)
3287                 numTestCasesFailed++;
3288         }
3289     };
3290 
3291     ContextState* g_cs = nullptr;
3292 
3293     // used to avoid locks for the debug output
3294     // TODO: figure out if this is indeed necessary/correct - seems like either there still
3295     // could be a race or that there wouldn't be a race even if using the context directly
3296     DOCTEST_THREAD_LOCAL bool g_no_colors;
3297 
3298 #endif // DOCTEST_CONFIG_DISABLE
3299 } // namespace detail
3300 
3301 void String::setOnHeap() { *reinterpret_cast<unsigned char*>(&buf[last]) = 128; }
3302 void String::setLast(unsigned in) { buf[last] = char(in); }
3303 
3304 void String::copy(const String& other) {
3305     using namespace std;
3306     if(other.isOnStack()) {
3307         memcpy(buf, other.buf, len);
3308     } else {
3309         setOnHeap();
3310         data.size     = other.data.size;
3311         data.capacity = data.size + 1;
3312         data.ptr      = new char[data.capacity];
3313         memcpy(data.ptr, other.data.ptr, data.size + 1);
3314     }
3315 }
3316 
3317 String::String() {
3318     buf[0] = '\0';
3319     setLast();
3320 }
3321 
3322 String::~String() {
3323     if(!isOnStack())
3324         delete[] data.ptr;
3325     // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
3326 }
3327 
3328 String::String(const char* in)
3329         : String(in, strlen(in)) {}
3330 
3331 String::String(const char* in, unsigned in_size) {
3332     using namespace std;
3333     if(in_size <= last) {
3334         memcpy(buf, in, in_size);
3335         buf[in_size] = '\0';
3336         setLast(last - in_size);
3337     } else {
3338         setOnHeap();
3339         data.size     = in_size;
3340         data.capacity = data.size + 1;
3341         data.ptr      = new char[data.capacity];
3342         memcpy(data.ptr, in, in_size);
3343         data.ptr[in_size] = '\0';
3344     }
3345 }
3346 
3347 String::String(const String& other) { copy(other); }
3348 
3349 String& String::operator=(const String& other) {
3350     if(this != &other) {
3351         if(!isOnStack())
3352             delete[] data.ptr;
3353 
3354         copy(other);
3355     }
3356 
3357     return *this;
3358 }
3359 
3360 String& String::operator+=(const String& other) {
3361     const unsigned my_old_size = size();
3362     const unsigned other_size  = other.size();
3363     const unsigned total_size  = my_old_size + other_size;
3364     using namespace std;
3365     if(isOnStack()) {
3366         if(total_size < len) {
3367             // append to the current stack space
3368             memcpy(buf + my_old_size, other.c_str(), other_size + 1);
3369             // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
3370             setLast(last - total_size);
3371         } else {
3372             // alloc new chunk
3373             char* temp = new char[total_size + 1];
3374             // copy current data to new location before writing in the union
3375             memcpy(temp, buf, my_old_size); // skip the +1 ('\0') for speed
3376             // update data in union
3377             setOnHeap();
3378             data.size     = total_size;
3379             data.capacity = data.size + 1;
3380             data.ptr      = temp;
3381             // transfer the rest of the data
3382             memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);
3383         }
3384     } else {
3385         if(data.capacity > total_size) {
3386             // append to the current heap block
3387             data.size = total_size;
3388             memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);
3389         } else {
3390             // resize
3391             data.capacity *= 2;
3392             if(data.capacity <= total_size)
3393                 data.capacity = total_size + 1;
3394             // alloc new chunk
3395             char* temp = new char[data.capacity];
3396             // copy current data to new location before releasing it
3397             memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\0') for speed
3398             // release old chunk
3399             delete[] data.ptr;
3400             // update the rest of the union members
3401             data.size = total_size;
3402             data.ptr  = temp;
3403             // transfer the rest of the data
3404             memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);
3405         }
3406     }
3407 
3408     return *this;
3409 }
3410 
3411 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
3412 String String::operator+(const String& other) const { return String(*this) += other; }
3413 
3414 String::String(String&& other) {
3415     using namespace std;
3416     memcpy(buf, other.buf, len);
3417     other.buf[0] = '\0';
3418     other.setLast();
3419 }
3420 
3421 String& String::operator=(String&& other) {
3422     using namespace std;
3423     if(this != &other) {
3424         if(!isOnStack())
3425             delete[] data.ptr;
3426         memcpy(buf, other.buf, len);
3427         other.buf[0] = '\0';
3428         other.setLast();
3429     }
3430     return *this;
3431 }
3432 
3433 char String::operator[](unsigned i) const {
3434     return const_cast<String*>(this)->operator[](i); // NOLINT
3435 }
3436 
3437 char& String::operator[](unsigned i) {
3438     if(isOnStack())
3439         return reinterpret_cast<char*>(buf)[i];
3440     return data.ptr[i];
3441 }
3442 
3443 DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized")
3444 unsigned String::size() const {
3445     if(isOnStack())
3446         return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32
3447     return data.size;
3448 }
3449 DOCTEST_GCC_SUPPRESS_WARNING_POP
3450 
3451 unsigned String::capacity() const {
3452     if(isOnStack())
3453         return len;
3454     return data.capacity;
3455 }
3456 
3457 int String::compare(const char* other, bool no_case) const {
3458     if(no_case)
3459         return doctest::stricmp(c_str(), other);
3460     return std::strcmp(c_str(), other);
3461 }
3462 
3463 int String::compare(const String& other, bool no_case) const {
3464     return compare(other.c_str(), no_case);
3465 }
3466 
3467 // clang-format off
3468 bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; }
3469 bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; }
3470 bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; }
3471 bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; }
3472 bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; }
3473 bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; }
3474 // clang-format on
3475 
3476 std::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); }
3477 
3478 namespace {
3479     void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;)
3480 } // namespace
3481 
3482 namespace Color {
3483     std::ostream& operator<<(std::ostream& s, Color::Enum code) {
3484         color_to_stream(s, code);
3485         return s;
3486     }
3487 } // namespace Color
3488 
3489 // clang-format off
3490 const char* assertString(assertType::Enum at) {
3491     DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4062) // enum 'x' in switch of enum 'y' is not handled
3492     switch(at) {  //!OCLINT missing default in switch statements
3493         case assertType::DT_WARN                    : return "WARN";
3494         case assertType::DT_CHECK                   : return "CHECK";
3495         case assertType::DT_REQUIRE                 : return "REQUIRE";
3496 
3497         case assertType::DT_WARN_FALSE              : return "WARN_FALSE";
3498         case assertType::DT_CHECK_FALSE             : return "CHECK_FALSE";
3499         case assertType::DT_REQUIRE_FALSE           : return "REQUIRE_FALSE";
3500 
3501         case assertType::DT_WARN_THROWS             : return "WARN_THROWS";
3502         case assertType::DT_CHECK_THROWS            : return "CHECK_THROWS";
3503         case assertType::DT_REQUIRE_THROWS          : return "REQUIRE_THROWS";
3504 
3505         case assertType::DT_WARN_THROWS_AS          : return "WARN_THROWS_AS";
3506         case assertType::DT_CHECK_THROWS_AS         : return "CHECK_THROWS_AS";
3507         case assertType::DT_REQUIRE_THROWS_AS       : return "REQUIRE_THROWS_AS";
3508 
3509         case assertType::DT_WARN_THROWS_WITH        : return "WARN_THROWS_WITH";
3510         case assertType::DT_CHECK_THROWS_WITH       : return "CHECK_THROWS_WITH";
3511         case assertType::DT_REQUIRE_THROWS_WITH     : return "REQUIRE_THROWS_WITH";
3512 
3513         case assertType::DT_WARN_THROWS_WITH_AS     : return "WARN_THROWS_WITH_AS";
3514         case assertType::DT_CHECK_THROWS_WITH_AS    : return "CHECK_THROWS_WITH_AS";
3515         case assertType::DT_REQUIRE_THROWS_WITH_AS  : return "REQUIRE_THROWS_WITH_AS";
3516 
3517         case assertType::DT_WARN_NOTHROW            : return "WARN_NOTHROW";
3518         case assertType::DT_CHECK_NOTHROW           : return "CHECK_NOTHROW";
3519         case assertType::DT_REQUIRE_NOTHROW         : return "REQUIRE_NOTHROW";
3520 
3521         case assertType::DT_WARN_EQ                 : return "WARN_EQ";
3522         case assertType::DT_CHECK_EQ                : return "CHECK_EQ";
3523         case assertType::DT_REQUIRE_EQ              : return "REQUIRE_EQ";
3524         case assertType::DT_WARN_NE                 : return "WARN_NE";
3525         case assertType::DT_CHECK_NE                : return "CHECK_NE";
3526         case assertType::DT_REQUIRE_NE              : return "REQUIRE_NE";
3527         case assertType::DT_WARN_GT                 : return "WARN_GT";
3528         case assertType::DT_CHECK_GT                : return "CHECK_GT";
3529         case assertType::DT_REQUIRE_GT              : return "REQUIRE_GT";
3530         case assertType::DT_WARN_LT                 : return "WARN_LT";
3531         case assertType::DT_CHECK_LT                : return "CHECK_LT";
3532         case assertType::DT_REQUIRE_LT              : return "REQUIRE_LT";
3533         case assertType::DT_WARN_GE                 : return "WARN_GE";
3534         case assertType::DT_CHECK_GE                : return "CHECK_GE";
3535         case assertType::DT_REQUIRE_GE              : return "REQUIRE_GE";
3536         case assertType::DT_WARN_LE                 : return "WARN_LE";
3537         case assertType::DT_CHECK_LE                : return "CHECK_LE";
3538         case assertType::DT_REQUIRE_LE              : return "REQUIRE_LE";
3539 
3540         case assertType::DT_WARN_UNARY              : return "WARN_UNARY";
3541         case assertType::DT_CHECK_UNARY             : return "CHECK_UNARY";
3542         case assertType::DT_REQUIRE_UNARY           : return "REQUIRE_UNARY";
3543         case assertType::DT_WARN_UNARY_FALSE        : return "WARN_UNARY_FALSE";
3544         case assertType::DT_CHECK_UNARY_FALSE       : return "CHECK_UNARY_FALSE";
3545         case assertType::DT_REQUIRE_UNARY_FALSE     : return "REQUIRE_UNARY_FALSE";
3546     }
3547     DOCTEST_MSVC_SUPPRESS_WARNING_POP
3548     return "";
3549 }
3550 // clang-format on
3551 
3552 const char* failureString(assertType::Enum at) {
3553     if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional
3554         return "WARNING";
3555     if(at & assertType::is_check) //!OCLINT bitwise operator in conditional
3556         return "ERROR";
3557     if(at & assertType::is_require) //!OCLINT bitwise operator in conditional
3558         return "FATAL ERROR";
3559     return "";
3560 }
3561 
3562 DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference")
3563 DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference")
3564 // depending on the current options this will remove the path of filenames
3565 const char* skipPathFromFilename(const char* file) {
3566 #ifndef DOCTEST_CONFIG_DISABLE
3567     if(getContextOptions()->no_path_in_filenames) {
3568         auto back    = std::strrchr(file, '\\');
3569         auto forward = std::strrchr(file, '/');
3570         if(back || forward) {
3571             if(back > forward)
3572                 forward = back;
3573             return forward + 1;
3574         }
3575     }
3576 #endif // DOCTEST_CONFIG_DISABLE
3577     return file;
3578 }
3579 DOCTEST_CLANG_SUPPRESS_WARNING_POP
3580 DOCTEST_GCC_SUPPRESS_WARNING_POP
3581 
3582 bool SubcaseSignature::operator<(const SubcaseSignature& other) const {
3583     if(m_line != other.m_line)
3584         return m_line < other.m_line;
3585     if(std::strcmp(m_file, other.m_file) != 0)
3586         return std::strcmp(m_file, other.m_file) < 0;
3587     return m_name.compare(other.m_name) < 0;
3588 }
3589 
3590 IContextScope::IContextScope()  = default;
3591 IContextScope::~IContextScope() = default;
3592 
3593 #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
3594 String toString(char* in) { return toString(static_cast<const char*>(in)); }
3595 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
3596 String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; }
3597 #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
3598 String toString(bool in) { return in ? "true" : "false"; }
3599 String toString(float in) { return fpToString(in, 5) + "f"; }
3600 String toString(double in) { return fpToString(in, 10); }
3601 String toString(double long in) { return fpToString(in, 15); }
3602 
3603 #define DOCTEST_TO_STRING_OVERLOAD(type, fmt)                                                      \
3604     String toString(type in) {                                                                     \
3605         char buf[64];                                                                              \
3606         std::sprintf(buf, fmt, in);                                                                \
3607         return buf;                                                                                \
3608     }
3609 
3610 DOCTEST_TO_STRING_OVERLOAD(char, "%d")
3611 DOCTEST_TO_STRING_OVERLOAD(char signed, "%d")
3612 DOCTEST_TO_STRING_OVERLOAD(char unsigned, "%u")
3613 DOCTEST_TO_STRING_OVERLOAD(int short, "%d")
3614 DOCTEST_TO_STRING_OVERLOAD(int short unsigned, "%u")
3615 DOCTEST_TO_STRING_OVERLOAD(int, "%d")
3616 DOCTEST_TO_STRING_OVERLOAD(unsigned, "%u")
3617 DOCTEST_TO_STRING_OVERLOAD(int long, "%ld")
3618 DOCTEST_TO_STRING_OVERLOAD(int long unsigned, "%lu")
3619 DOCTEST_TO_STRING_OVERLOAD(int long long, "%lld")
3620 DOCTEST_TO_STRING_OVERLOAD(int long long unsigned, "%llu")
3621 
3622 String toString(std::nullptr_t) { return "NULL"; }
3623 
3624 #if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
3625 // see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183
3626 String toString(const std::string& in) { return in.c_str(); }
3627 #endif // VS 2019
3628 
3629 Approx::Approx(double value)
3630         : m_epsilon(static_cast<double>(std::numeric_limits<float>::epsilon()) * 100)
3631         , m_scale(1.0)
3632         , m_value(value) {}
3633 
3634 Approx Approx::operator()(double value) const {
3635     Approx approx(value);
3636     approx.epsilon(m_epsilon);
3637     approx.scale(m_scale);
3638     return approx;
3639 }
3640 
3641 Approx& Approx::epsilon(double newEpsilon) {
3642     m_epsilon = newEpsilon;
3643     return *this;
3644 }
3645 Approx& Approx::scale(double newScale) {
3646     m_scale = newScale;
3647     return *this;
3648 }
3649 
3650 bool operator==(double lhs, const Approx& rhs) {
3651     // Thanks to Richard Harris for his help refining this formula
3652     return std::fabs(lhs - rhs.m_value) <
3653            rhs.m_epsilon * (rhs.m_scale + std::max<double>(std::fabs(lhs), std::fabs(rhs.m_value)));
3654 }
3655 bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); }
3656 bool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); }
3657 bool operator!=(const Approx& lhs, double rhs) { return !operator==(rhs, lhs); }
3658 bool operator<=(double lhs, const Approx& rhs) { return lhs < rhs.m_value || lhs == rhs; }
3659 bool operator<=(const Approx& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; }
3660 bool operator>=(double lhs, const Approx& rhs) { return lhs > rhs.m_value || lhs == rhs; }
3661 bool operator>=(const Approx& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; }
3662 bool operator<(double lhs, const Approx& rhs) { return lhs < rhs.m_value && lhs != rhs; }
3663 bool operator<(const Approx& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; }
3664 bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs != rhs; }
3665 bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; }
3666 
3667 String toString(const Approx& in) {
3668     // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
3669     return String("Approx( ") + doctest::toString(in.m_value) + " )";
3670 }
3671 const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); }
3672 
3673 } // namespace doctest
3674 
3675 #ifdef DOCTEST_CONFIG_DISABLE
3676 namespace doctest {
3677 Context::Context(int, const char* const*) {}
3678 Context::~Context() = default;
3679 void Context::applyCommandLine(int, const char* const*) {}
3680 void Context::addFilter(const char*, const char*) {}
3681 void Context::clearFilters() {}
3682 void Context::setOption(const char*, int) {}
3683 void Context::setOption(const char*, const char*) {}
3684 bool Context::shouldExit() { return false; }
3685 void Context::setAsDefaultForAssertsOutOfTestCases() {}
3686 void Context::setAssertHandler(detail::assert_handler) {}
3687 int  Context::run() { return 0; }
3688 
3689 IReporter::~IReporter() = default;
3690 
3691 int                         IReporter::get_num_active_contexts() { return 0; }
3692 const IContextScope* const* IReporter::get_active_contexts() { return nullptr; }
3693 int                         IReporter::get_num_stringified_contexts() { return 0; }
3694 const String*               IReporter::get_stringified_contexts() { return nullptr; }
3695 
3696 int registerReporter(const char*, int, IReporter*) { return 0; }
3697 
3698 } // namespace doctest
3699 #else // DOCTEST_CONFIG_DISABLE
3700 
3701 #if !defined(DOCTEST_CONFIG_COLORS_NONE)
3702 #if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI)
3703 #ifdef DOCTEST_PLATFORM_WINDOWS
3704 #define DOCTEST_CONFIG_COLORS_WINDOWS
3705 #else // linux
3706 #define DOCTEST_CONFIG_COLORS_ANSI
3707 #endif // platform
3708 #endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI
3709 #endif // DOCTEST_CONFIG_COLORS_NONE
3710 
3711 namespace doctest_detail_test_suite_ns {
3712 // holds the current test suite
3713 doctest::detail::TestSuite& getCurrentTestSuite() {
3714     static doctest::detail::TestSuite data{};
3715     return data;
3716 }
3717 } // namespace doctest_detail_test_suite_ns
3718 
3719 namespace doctest {
3720 namespace {
3721     // the int (priority) is part of the key for automatic sorting - sadly one can register a
3722     // reporter with a duplicate name and a different priority but hopefully that won't happen often :|
3723     typedef std::map<std::pair<int, String>, reporterCreatorFunc> reporterMap;
3724 
3725     reporterMap& getReporters() {
3726         static reporterMap data;
3727         return data;
3728     }
3729     reporterMap& getListeners() {
3730         static reporterMap data;
3731         return data;
3732     }
3733 } // namespace
3734 namespace detail {
3735 #define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...)                                           \
3736     for(auto& curr_rep : g_cs->reporters_currently_used)                                           \
3737     curr_rep->function(__VA_ARGS__)
3738 
3739     bool checkIfShouldThrow(assertType::Enum at) {
3740         if(at & assertType::is_require) //!OCLINT bitwise operator in conditional
3741             return true;
3742 
3743         if((at & assertType::is_check) //!OCLINT bitwise operator in conditional
3744            && getContextOptions()->abort_after > 0 &&
3745            (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >=
3746                    getContextOptions()->abort_after)
3747             return true;
3748 
3749         return false;
3750     }
3751 
3752 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
3753     DOCTEST_NORETURN void throwException() {
3754         g_cs->shouldLogCurrentException = false;
3755         throw TestFailureException();
3756     } // NOLINT(cert-err60-cpp)
3757 #else // DOCTEST_CONFIG_NO_EXCEPTIONS
3758     void throwException() {}
3759 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
3760 } // namespace detail
3761 
3762 namespace {
3763     using namespace detail;
3764     // matching of a string against a wildcard mask (case sensitivity configurable) taken from
3765     // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing
3766     int wildcmp(const char* str, const char* wild, bool caseSensitive) {
3767         const char* cp = str;
3768         const char* mp = wild;
3769 
3770         while((*str) && (*wild != '*')) {
3771             if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) &&
3772                (*wild != '?')) {
3773                 return 0;
3774             }
3775             wild++;
3776             str++;
3777         }
3778 
3779         while(*str) {
3780             if(*wild == '*') {
3781                 if(!*++wild) {
3782                     return 1;
3783                 }
3784                 mp = wild;
3785                 cp = str + 1;
3786             } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) ||
3787                       (*wild == '?')) {
3788                 wild++;
3789                 str++;
3790             } else {
3791                 wild = mp;   //!OCLINT parameter reassignment
3792                 str  = cp++; //!OCLINT parameter reassignment
3793             }
3794         }
3795 
3796         while(*wild == '*') {
3797             wild++;
3798         }
3799         return !*wild;
3800     }
3801 
3802     //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html
3803     //unsigned hashStr(unsigned const char* str) {
3804     //    unsigned long hash = 5381;
3805     //    char          c;
3806     //    while((c = *str++))
3807     //        hash = ((hash << 5) + hash) + c; // hash * 33 + c
3808     //    return hash;
3809     //}
3810 
3811     // checks if the name matches any of the filters (and can be configured what to do when empty)
3812     bool matchesAny(const char* name, const std::vector<String>& filters, bool matchEmpty,
3813                     bool caseSensitive) {
3814         if(filters.empty() && matchEmpty)
3815             return true;
3816         for(auto& curr : filters)
3817             if(wildcmp(name, curr.c_str(), caseSensitive))
3818                 return true;
3819         return false;
3820     }
3821 } // namespace
3822 namespace detail {
3823 
3824     Subcase::Subcase(const String& name, const char* file, int line)
3825             : m_signature({name, file, line}) {
3826         auto* s = g_cs;
3827 
3828         // check subcase filters
3829         if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) {
3830             if(!matchesAny(m_signature.m_name.c_str(), s->filters[6], true, s->case_sensitive))
3831                 return;
3832             if(matchesAny(m_signature.m_name.c_str(), s->filters[7], false, s->case_sensitive))
3833                 return;
3834         }
3835 
3836         // if a Subcase on the same level has already been entered
3837         if(s->subcasesStack.size() < size_t(s->subcasesCurrentMaxLevel)) {
3838             s->should_reenter = true;
3839             return;
3840         }
3841 
3842         // push the current signature to the stack so we can check if the
3843         // current stack + the current new subcase have been traversed
3844         s->subcasesStack.push_back(m_signature);
3845         if(s->subcasesPassed.count(s->subcasesStack) != 0) {
3846             // pop - revert to previous stack since we've already passed this
3847             s->subcasesStack.pop_back();
3848             return;
3849         }
3850 
3851         s->subcasesCurrentMaxLevel = s->subcasesStack.size();
3852         m_entered = true;
3853 
3854         DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature);
3855     }
3856 
3857     DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17
3858     DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
3859     DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
3860 
3861     Subcase::~Subcase() {
3862         if(m_entered) {
3863             // only mark the subcase stack as passed if no subcases have been skipped
3864             if(g_cs->should_reenter == false)
3865                 g_cs->subcasesPassed.insert(g_cs->subcasesStack);
3866             g_cs->subcasesStack.pop_back();
3867 
3868 #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)
3869             if(std::uncaught_exceptions() > 0
3870 #else
3871             if(std::uncaught_exception()
3872 #endif
3873             && g_cs->shouldLogCurrentException) {
3874                 DOCTEST_ITERATE_THROUGH_REPORTERS(
3875                         test_case_exception, {"exception thrown in subcase - will translate later "
3876                                               "when the whole test case has been exited (cannot "
3877                                               "translate while there is an active exception)",
3878                                               false});
3879                 g_cs->shouldLogCurrentException = false;
3880             }
3881             DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY);
3882         }
3883     }
3884 
3885     DOCTEST_CLANG_SUPPRESS_WARNING_POP
3886     DOCTEST_GCC_SUPPRESS_WARNING_POP
3887     DOCTEST_MSVC_SUPPRESS_WARNING_POP
3888 
3889     Subcase::operator bool() const { return m_entered; }
3890 
3891     Result::Result(bool passed, const String& decomposition)
3892             : m_passed(passed)
3893             , m_decomp(decomposition) {}
3894 
3895     ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at)
3896             : m_at(at) {}
3897 
3898     TestSuite& TestSuite::operator*(const char* in) {
3899         m_test_suite = in;
3900         // clear state
3901         m_description       = nullptr;
3902         m_skip              = false;
3903         m_no_breaks         = false;
3904         m_no_output         = false;
3905         m_may_fail          = false;
3906         m_should_fail       = false;
3907         m_expected_failures = 0;
3908         m_timeout           = 0;
3909         return *this;
3910     }
3911 
3912     TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,
3913                        const char* type, int template_id) {
3914         m_file              = file;
3915         m_line              = line;
3916         m_name              = nullptr; // will be later overridden in operator*
3917         m_test_suite        = test_suite.m_test_suite;
3918         m_description       = test_suite.m_description;
3919         m_skip              = test_suite.m_skip;
3920         m_no_breaks         = test_suite.m_no_breaks;
3921         m_no_output         = test_suite.m_no_output;
3922         m_may_fail          = test_suite.m_may_fail;
3923         m_should_fail       = test_suite.m_should_fail;
3924         m_expected_failures = test_suite.m_expected_failures;
3925         m_timeout           = test_suite.m_timeout;
3926 
3927         m_test        = test;
3928         m_type        = type;
3929         m_template_id = template_id;
3930     }
3931 
3932     TestCase::TestCase(const TestCase& other)
3933             : TestCaseData() {
3934         *this = other;
3935     }
3936 
3937     DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function
3938     DOCTEST_MSVC_SUPPRESS_WARNING(26437)           // Do not slice
3939     TestCase& TestCase::operator=(const TestCase& other) {
3940         static_cast<TestCaseData&>(*this) = static_cast<const TestCaseData&>(other);
3941 
3942         m_test        = other.m_test;
3943         m_type        = other.m_type;
3944         m_template_id = other.m_template_id;
3945         m_full_name   = other.m_full_name;
3946 
3947         if(m_template_id != -1)
3948             m_name = m_full_name.c_str();
3949         return *this;
3950     }
3951     DOCTEST_MSVC_SUPPRESS_WARNING_POP
3952 
3953     TestCase& TestCase::operator*(const char* in) {
3954         m_name = in;
3955         // make a new name with an appended type for templated test case
3956         if(m_template_id != -1) {
3957             m_full_name = String(m_name) + m_type;
3958             // redirect the name to point to the newly constructed full name
3959             m_name = m_full_name.c_str();
3960         }
3961         return *this;
3962     }
3963 
3964     bool TestCase::operator<(const TestCase& other) const {
3965         // this will be used only to differentiate between test cases - not relevant for sorting
3966         if(m_line != other.m_line)
3967             return m_line < other.m_line;
3968         const int name_cmp = strcmp(m_name, other.m_name);
3969         if(name_cmp != 0)
3970             return name_cmp < 0;
3971         const int file_cmp = m_file.compare(other.m_file);
3972         if(file_cmp != 0)
3973             return file_cmp < 0;
3974         return m_template_id < other.m_template_id;
3975     }
3976 
3977     // all the registered tests
3978     std::set<TestCase>& getRegisteredTests() {
3979         static std::set<TestCase> data;
3980         return data;
3981     }
3982 } // namespace detail
3983 namespace {
3984     using namespace detail;
3985     // for sorting tests by file/line
3986     bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) {
3987         // this is needed because MSVC gives different case for drive letters
3988         // for __FILE__ when evaluated in a header and a source file
3989         const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC));
3990         if(res != 0)
3991             return res < 0;
3992         if(lhs->m_line != rhs->m_line)
3993             return lhs->m_line < rhs->m_line;
3994         return lhs->m_template_id < rhs->m_template_id;
3995     }
3996 
3997     // for sorting tests by suite/file/line
3998     bool suiteOrderComparator(const TestCase* lhs, const TestCase* rhs) {
3999         const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite);
4000         if(res != 0)
4001             return res < 0;
4002         return fileOrderComparator(lhs, rhs);
4003     }
4004 
4005     // for sorting tests by name/suite/file/line
4006     bool nameOrderComparator(const TestCase* lhs, const TestCase* rhs) {
4007         const int res = std::strcmp(lhs->m_name, rhs->m_name);
4008         if(res != 0)
4009             return res < 0;
4010         return suiteOrderComparator(lhs, rhs);
4011     }
4012 
4013 #ifdef DOCTEST_CONFIG_COLORS_WINDOWS
4014     HANDLE g_stdoutHandle;
4015     WORD   g_origFgAttrs;
4016     WORD   g_origBgAttrs;
4017     bool   g_attrsInitted = false;
4018 
4019     int colors_init() {
4020         if(!g_attrsInitted) {
4021             g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
4022             g_attrsInitted = true;
4023             CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
4024             GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo);
4025             g_origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED |
4026                                                      BACKGROUND_BLUE | BACKGROUND_INTENSITY);
4027             g_origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED |
4028                                                      FOREGROUND_BLUE | FOREGROUND_INTENSITY);
4029         }
4030         return 0;
4031     }
4032 
4033     // TODO: upstream the change to doctest : add volatile to get rid of "unused variable warning" + fix typo
4034     volatile int dummy_init_console_colors = colors_init();
4035 #endif // DOCTEST_CONFIG_COLORS_WINDOWS
4036 
4037     DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
4038     void color_to_stream(std::ostream& s, Color::Enum code) {
4039         static_cast<void>(s);    // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS
4040         static_cast<void>(code); // for DOCTEST_CONFIG_COLORS_NONE
4041 #ifdef DOCTEST_CONFIG_COLORS_ANSI
4042         if(g_no_colors ||
4043            (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false))
4044             return;
4045 
4046         auto col = "";
4047         // clang-format off
4048             switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement
4049                 case Color::Red:         col = "[0;31m"; break;
4050                 case Color::Green:       col = "[0;32m"; break;
4051                 case Color::Blue:        col = "[0;34m"; break;
4052                 case Color::Cyan:        col = "[0;36m"; break;
4053                 case Color::Yellow:      col = "[0;33m"; break;
4054                 case Color::Grey:        col = "[1;30m"; break;
4055                 case Color::LightGrey:   col = "[0;37m"; break;
4056                 case Color::BrightRed:   col = "[1;31m"; break;
4057                 case Color::BrightGreen: col = "[1;32m"; break;
4058                 case Color::BrightWhite: col = "[1;37m"; break;
4059                 case Color::Bright: // invalid
4060                 case Color::None:
4061                 case Color::White:
4062                 default:                 col = "[0m";
4063             }
4064         // clang-format on
4065         s << "\033" << col;
4066 #endif // DOCTEST_CONFIG_COLORS_ANSI
4067 
4068 #ifdef DOCTEST_CONFIG_COLORS_WINDOWS
4069         if(g_no_colors ||
4070            (isatty(fileno(stdout)) == false && getContextOptions()->force_colors == false))
4071             return;
4072 
4073 #define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(g_stdoutHandle, x | g_origBgAttrs)
4074 
4075         // clang-format off
4076         switch (code) {
4077             case Color::White:       DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break;
4078             case Color::Red:         DOCTEST_SET_ATTR(FOREGROUND_RED);                                      break;
4079             case Color::Green:       DOCTEST_SET_ATTR(FOREGROUND_GREEN);                                    break;
4080             case Color::Blue:        DOCTEST_SET_ATTR(FOREGROUND_BLUE);                                     break;
4081             case Color::Cyan:        DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN);                  break;
4082             case Color::Yellow:      DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN);                   break;
4083             case Color::Grey:        DOCTEST_SET_ATTR(0);                                                   break;
4084             case Color::LightGrey:   DOCTEST_SET_ATTR(FOREGROUND_INTENSITY);                                break;
4085             case Color::BrightRed:   DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED);               break;
4086             case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN);             break;
4087             case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break;
4088             case Color::None:
4089             case Color::Bright: // invalid
4090             default:                 DOCTEST_SET_ATTR(g_origFgAttrs);
4091         }
4092             // clang-format on
4093 #endif // DOCTEST_CONFIG_COLORS_WINDOWS
4094     }
4095     DOCTEST_CLANG_SUPPRESS_WARNING_POP
4096 
4097     std::vector<const IExceptionTranslator*>& getExceptionTranslators() {
4098         static std::vector<const IExceptionTranslator*> data;
4099         return data;
4100     }
4101 
4102     String translateActiveException() {
4103 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
4104         String res;
4105         auto&  translators = getExceptionTranslators();
4106         for(auto& curr : translators)
4107             if(curr->translate(res))
4108                 return res;
4109         // clang-format off
4110         DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value")
4111         try {
4112             throw;
4113         } catch(std::exception& ex) {
4114             return ex.what();
4115         } catch(std::string& msg) {
4116             return msg.c_str();
4117         } catch(const char* msg) {
4118             return msg;
4119         } catch(...) {
4120             return "unknown exception";
4121         }
4122         DOCTEST_GCC_SUPPRESS_WARNING_POP
4123 // clang-format on
4124 #else  // DOCTEST_CONFIG_NO_EXCEPTIONS
4125         return "";
4126 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
4127     }
4128 } // namespace
4129 
4130 namespace detail {
4131     // used by the macros for registering tests
4132     int regTest(const TestCase& tc) {
4133         getRegisteredTests().insert(tc);
4134         return 0;
4135     }
4136 
4137     // sets the current test suite
4138     int setTestSuite(const TestSuite& ts) {
4139         doctest_detail_test_suite_ns::getCurrentTestSuite() = ts;
4140         return 0;
4141     }
4142 
4143 #ifdef DOCTEST_IS_DEBUGGER_ACTIVE
4144     bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); }
4145 #else // DOCTEST_IS_DEBUGGER_ACTIVE
4146 #ifdef DOCTEST_PLATFORM_LINUX
4147     class ErrnoGuard {
4148     public:
4149         ErrnoGuard() : m_oldErrno(errno) {}
4150         ~ErrnoGuard() { errno = m_oldErrno; }
4151     private:
4152         int m_oldErrno;
4153     };
4154     // See the comments in Catch2 for the reasoning behind this implementation:
4155     // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102
4156     bool isDebuggerActive() {
4157         ErrnoGuard guard;
4158         std::ifstream in("/proc/self/status");
4159         for(std::string line; std::getline(in, line);) {
4160             static const int PREFIX_LEN = 11;
4161             if(line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) {
4162                 return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
4163             }
4164         }
4165         return false;
4166     }
4167 #elif defined(DOCTEST_PLATFORM_MAC)
4168     // The following function is taken directly from the following technical note:
4169     // https://developer.apple.com/library/archive/qa/qa1361/_index.html
4170     // Returns true if the current process is being debugged (either
4171     // running under the debugger or has a debugger attached post facto).
4172     bool isDebuggerActive() {
4173         int        mib[4];
4174         kinfo_proc info;
4175         size_t     size;
4176         // Initialize the flags so that, if sysctl fails for some bizarre
4177         // reason, we get a predictable result.
4178         info.kp_proc.p_flag = 0;
4179         // Initialize mib, which tells sysctl the info we want, in this case
4180         // we're looking for information about a specific process ID.
4181         mib[0] = CTL_KERN;
4182         mib[1] = KERN_PROC;
4183         mib[2] = KERN_PROC_PID;
4184         mib[3] = getpid();
4185         // Call sysctl.
4186         size = sizeof(info);
4187         if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) {
4188             std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n";
4189             return false;
4190         }
4191         // We're being debugged if the P_TRACED flag is set.
4192         return ((info.kp_proc.p_flag & P_TRACED) != 0);
4193     }
4194 #elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__)
4195     bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; }
4196 #else
4197     bool isDebuggerActive() { return false; }
4198 #endif // Platform
4199 #endif // DOCTEST_IS_DEBUGGER_ACTIVE
4200 
4201     void registerExceptionTranslatorImpl(const IExceptionTranslator* et) {
4202         if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) ==
4203            getExceptionTranslators().end())
4204             getExceptionTranslators().push_back(et);
4205     }
4206 
4207 #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
4208     void toStream(std::ostream* s, char* in) { *s << in; }
4209     void toStream(std::ostream* s, const char* in) { *s << in; }
4210 #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
4211     void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; }
4212     void toStream(std::ostream* s, float in) { *s << in; }
4213     void toStream(std::ostream* s, double in) { *s << in; }
4214     void toStream(std::ostream* s, double long in) { *s << in; }
4215 
4216     void toStream(std::ostream* s, char in) { *s << in; }
4217     void toStream(std::ostream* s, char signed in) { *s << in; }
4218     void toStream(std::ostream* s, char unsigned in) { *s << in; }
4219     void toStream(std::ostream* s, int short in) { *s << in; }
4220     void toStream(std::ostream* s, int short unsigned in) { *s << in; }
4221     void toStream(std::ostream* s, int in) { *s << in; }
4222     void toStream(std::ostream* s, int unsigned in) { *s << in; }
4223     void toStream(std::ostream* s, int long in) { *s << in; }
4224     void toStream(std::ostream* s, int long unsigned in) { *s << in; }
4225     void toStream(std::ostream* s, int long long in) { *s << in; }
4226     void toStream(std::ostream* s, int long long unsigned in) { *s << in; }
4227 
4228     DOCTEST_THREAD_LOCAL doctest_thread_local_wrapper<std::vector<IContextScope*>> wrapped_g_infoContexts; // for logging with INFO()
4229 
4230     ContextScopeBase::ContextScopeBase() {
4231         wrapped_g_infoContexts.get().push_back(this);
4232     }
4233 
4234     // TODO: upstream the change to doctest : fix copy elision absence case
4235     ContextScopeBase::ContextScopeBase(ContextScopeBase&& other) {
4236         if (other.need_to_destroy) {
4237             other.destroy();
4238         }
4239         other.need_to_destroy = false;
4240         wrapped_g_infoContexts.get().push_back(this);
4241     }
4242 
4243     DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17
4244     DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
4245     DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
4246 
4247     // destroy cannot be inlined into the destructor because that would mean calling stringify after
4248     // ContextScope has been destroyed (base class destructors run after derived class destructors).
4249     // Instead, ContextScope calls this method directly from its destructor.
4250     void ContextScopeBase::destroy() {
4251 #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)
4252         if(std::uncaught_exceptions() > 0) {
4253 #else
4254         if(std::uncaught_exception()) {
4255 #endif
4256             std::ostringstream s;
4257             this->stringify(&s);
4258             g_cs->stringifiedContexts.push_back(s.str().c_str());
4259         }
4260         wrapped_g_infoContexts.get().pop_back();
4261     }
4262 
4263     DOCTEST_CLANG_SUPPRESS_WARNING_POP
4264     DOCTEST_GCC_SUPPRESS_WARNING_POP
4265     DOCTEST_MSVC_SUPPRESS_WARNING_POP
4266 } // namespace detail
4267 namespace {
4268     using namespace detail;
4269 
4270 // TODO: upstream the change to doctest : Universal Windows Platform support
4271 #if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && (!defined(DOCTEST_CONFIG_WINDOWS_SEH) || defined(WINAPI_FAMILY))
4272     struct FatalConditionHandler
4273     {
4274         static void reset() {}
4275         static void allocateAltStackMem() {}
4276         static void freeAltStackMem() {}
4277     };
4278 #else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
4279 
4280     void reportFatal(const std::string&);
4281 
4282 #ifdef DOCTEST_PLATFORM_WINDOWS
4283 
4284     struct SignalDefs
4285     {
4286         DWORD id;
4287         const char* name;
4288     };
4289     // There is no 1-1 mapping between signals and windows exceptions.
4290     // Windows can easily distinguish between SO and SigSegV,
4291     // but SigInt, SigTerm, etc are handled differently.
4292     SignalDefs signalDefs[] = {
4293             {static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION),
4294              "SIGILL - Illegal instruction signal"},
4295             {static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"},
4296             {static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION),
4297              "SIGSEGV - Segmentation violation signal"},
4298             {static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"},
4299     };
4300 
4301     struct FatalConditionHandler
4302     {
4303         static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) {
4304             // Multiple threads may enter this filter/handler at once. We want the error message to be printed on the
4305             // console just once no matter how many threads have crashed.
4306             static std::mutex mutex;
4307             static bool execute = true;
4308             {
4309                 std::lock_guard<std::mutex> lock(mutex);
4310                 if(execute) {
4311                     bool reported = false;
4312                     for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
4313                         if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
4314                             reportFatal(signalDefs[i].name);
4315                             reported = true;
4316                             break;
4317                         }
4318                     }
4319                     if(reported == false)
4320                         reportFatal("Unhandled SEH exception caught");
4321                     if(isDebuggerActive() && !g_cs->no_breaks)
4322                         DOCTEST_BREAK_INTO_DEBUGGER();
4323                 }
4324                 execute = false;
4325             }
4326             std::exit(EXIT_FAILURE);
4327         }
4328 
4329         static void allocateAltStackMem() {}
4330         static void freeAltStackMem() {}
4331 
4332         FatalConditionHandler() {
4333             isSet = true;
4334             // 32k seems enough for doctest to handle stack overflow,
4335             // but the value was found experimentally, so there is no strong guarantee
4336             guaranteeSize = 32 * 1024;
4337             // Register an unhandled exception filter
4338             previousTop = SetUnhandledExceptionFilter(handleException);
4339             // Pass in guarantee size to be filled
4340             SetThreadStackGuarantee(&guaranteeSize);
4341 
4342             // On Windows uncaught exceptions from another thread, exceptions from
4343             // destructors, or calls to std::terminate are not a SEH exception
4344 
4345             // The terminal handler gets called when:
4346             // - std::terminate is called FROM THE TEST RUNNER THREAD
4347             // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD
4348             original_terminate_handler = std::get_terminate();
4349             std::set_terminate([]() DOCTEST_NOEXCEPT {
4350                 reportFatal("Terminate handler called");
4351                 if(isDebuggerActive() && !g_cs->no_breaks)
4352                     DOCTEST_BREAK_INTO_DEBUGGER();
4353                 std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well
4354             });
4355 
4356             // SIGABRT is raised when:
4357             // - std::terminate is called FROM A DIFFERENT THREAD
4358             // - an exception is thrown from a destructor FROM A DIFFERENT THREAD
4359             // - an uncaught exception is thrown FROM A DIFFERENT THREAD
4360             prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT {
4361                 if(signal == SIGABRT) {
4362                     reportFatal("SIGABRT - Abort (abnormal termination) signal");
4363                     if(isDebuggerActive() && !g_cs->no_breaks)
4364                         DOCTEST_BREAK_INTO_DEBUGGER();
4365                     std::exit(EXIT_FAILURE);
4366                 }
4367             });
4368 
4369             // The following settings are taken from google test, and more
4370             // specifically from UnitTest::Run() inside of gtest.cc
4371 
4372             // the user does not want to see pop-up dialogs about crashes
4373             prev_error_mode_1 = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
4374                                              SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
4375             // This forces the abort message to go to stderr in all circumstances.
4376             prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR);
4377             // In the debug version, Visual Studio pops up a separate dialog
4378             // offering a choice to debug the aborted program - we want to disable that.
4379             prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
4380             // In debug mode, the Windows CRT can crash with an assertion over invalid
4381             // input (e.g. passing an invalid file descriptor). The default handling
4382             // for these assertions is to pop up a dialog and wait for user input.
4383             // Instead ask the CRT to dump such assertions to stderr non-interactively.
4384             prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
4385             prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
4386         }
4387 
4388         static void reset() {
4389             if(isSet) {
4390                 // Unregister handler and restore the old guarantee
4391                 SetUnhandledExceptionFilter(previousTop);
4392                 SetThreadStackGuarantee(&guaranteeSize);
4393                 std::set_terminate(original_terminate_handler);
4394                 std::signal(SIGABRT, prev_sigabrt_handler);
4395                 SetErrorMode(prev_error_mode_1);
4396                 _set_error_mode(prev_error_mode_2);
4397                 _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
4398                 static_cast<void>(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode));
4399                 static_cast<void>(_CrtSetReportFile(_CRT_ASSERT, prev_report_file));
4400                 isSet = false;
4401             }
4402         }
4403 
4404         ~FatalConditionHandler() { reset(); }
4405 
4406     private:
4407         static UINT         prev_error_mode_1;
4408         static int          prev_error_mode_2;
4409         static unsigned int prev_abort_behavior;
4410         static int          prev_report_mode;
4411         static _HFILE       prev_report_file;
4412         static void (*prev_sigabrt_handler)(int);
4413         static std::terminate_handler original_terminate_handler;
4414         static bool isSet;
4415         static ULONG guaranteeSize;
4416         static LPTOP_LEVEL_EXCEPTION_FILTER previousTop;
4417     };
4418 
4419     UINT         FatalConditionHandler::prev_error_mode_1;
4420     int          FatalConditionHandler::prev_error_mode_2;
4421     unsigned int FatalConditionHandler::prev_abort_behavior;
4422     int          FatalConditionHandler::prev_report_mode;
4423     _HFILE       FatalConditionHandler::prev_report_file;
4424     void (*FatalConditionHandler::prev_sigabrt_handler)(int);
4425     std::terminate_handler FatalConditionHandler::original_terminate_handler;
4426     bool FatalConditionHandler::isSet = false;
4427     ULONG FatalConditionHandler::guaranteeSize = 0;
4428     LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr;
4429 
4430 #else // DOCTEST_PLATFORM_WINDOWS
4431 
4432     struct SignalDefs
4433     {
4434         int         id;
4435         const char* name;
4436     };
4437     SignalDefs signalDefs[] = {{SIGINT, "SIGINT - Terminal interrupt signal"},
4438                                {SIGILL, "SIGILL - Illegal instruction signal"},
4439                                {SIGFPE, "SIGFPE - Floating point error signal"},
4440                                {SIGSEGV, "SIGSEGV - Segmentation violation signal"},
4441                                {SIGTERM, "SIGTERM - Termination request signal"},
4442                                {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}};
4443 
4444     struct FatalConditionHandler
4445     {
4446         static bool             isSet;
4447         static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)];
4448         static stack_t          oldSigStack;
4449         static size_t           altStackSize;
4450         static char*            altStackMem;
4451 
4452         static void handleSignal(int sig) {
4453             const char* name = "<unknown signal>";
4454             for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
4455                 SignalDefs& def = signalDefs[i];
4456                 if(sig == def.id) {
4457                     name = def.name;
4458                     break;
4459                 }
4460             }
4461             reset();
4462             reportFatal(name);
4463             raise(sig);
4464         }
4465 
4466         static void allocateAltStackMem() {
4467             altStackMem = new char[altStackSize];
4468         }
4469 
4470         static void freeAltStackMem() {
4471             delete[] altStackMem;
4472         }
4473 
4474         FatalConditionHandler() {
4475             isSet = true;
4476             stack_t sigStack;
4477             sigStack.ss_sp    = altStackMem;
4478             sigStack.ss_size  = altStackSize;
4479             sigStack.ss_flags = 0;
4480             sigaltstack(&sigStack, &oldSigStack);
4481             struct sigaction sa = {};
4482             sa.sa_handler       = handleSignal; // NOLINT
4483             sa.sa_flags         = SA_ONSTACK;
4484             for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
4485                 sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
4486             }
4487         }
4488 
4489         ~FatalConditionHandler() { reset(); }
4490         static void reset() {
4491             if(isSet) {
4492                 // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
4493                 for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
4494                     sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
4495                 }
4496                 // Return the old stack
4497                 sigaltstack(&oldSigStack, nullptr);
4498                 isSet = false;
4499             }
4500         }
4501     };
4502 
4503     bool             FatalConditionHandler::isSet = false;
4504     struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {};
4505     stack_t          FatalConditionHandler::oldSigStack = {};
4506     size_t           FatalConditionHandler::altStackSize = 4 * SIGSTKSZ;
4507     char*            FatalConditionHandler::altStackMem = nullptr;
4508 
4509 #endif // DOCTEST_PLATFORM_WINDOWS
4510 #endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
4511 
4512 } // namespace
4513 
4514 namespace {
4515     using namespace detail;
4516 
4517 #ifdef DOCTEST_PLATFORM_WINDOWS
4518 #define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text)
4519 #else
4520     // TODO: integration with XCode and other IDEs
4521 #define DOCTEST_OUTPUT_DEBUG_STRING(text) // NOLINT(clang-diagnostic-unused-macros)
4522 #endif // Platform
4523 
4524     void addAssert(assertType::Enum at) {
4525         if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional
4526             g_cs->numAssertsCurrentTest_atomic++;
4527     }
4528 
4529     void addFailedAssert(assertType::Enum at) {
4530         if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional
4531             g_cs->numAssertsFailedCurrentTest_atomic++;
4532     }
4533 
4534 // TODO: upstream the change to doctest : Universal Windows Platform support
4535 #if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || (defined(DOCTEST_CONFIG_WINDOWS_SEH) && !defined(WINAPI_FAMILY))
4536     void reportFatal(const std::string& message) {
4537         g_cs->failure_flags |= TestCaseFailureReason::Crash;
4538 
4539         DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true});
4540 
4541         while(g_cs->subcasesStack.size()) {
4542             g_cs->subcasesStack.pop_back();
4543             DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY);
4544         }
4545 
4546         g_cs->finalizeTestCaseData();
4547 
4548         DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs);
4549 
4550         DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs);
4551     }
4552 #endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
4553 } // namespace
4554 namespace detail {
4555 
4556     ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr,
4557                                  const char* exception_type, const char* exception_string) {
4558         m_test_case        = g_cs->currentTest;
4559         m_at               = at;
4560         m_file             = file;
4561         m_line             = line;
4562         m_expr             = expr;
4563         m_failed           = true;
4564         m_threw            = false;
4565         m_threw_as         = false;
4566         m_exception_type   = exception_type;
4567         m_exception_string = exception_string;
4568 #if DOCTEST_MSVC
4569         if(m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC
4570             ++m_expr;
4571 #endif // MSVC
4572     }
4573 
4574     void ResultBuilder::setResult(const Result& res) {
4575         m_decomp = res.m_decomp;
4576         m_failed = !res.m_passed;
4577     }
4578 
4579     void ResultBuilder::translateException() {
4580         m_threw     = true;
4581         m_exception = translateActiveException();
4582     }
4583 
4584     bool ResultBuilder::log() {
4585         if(m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional
4586             m_failed = !m_threw;
4587         } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT
4588             m_failed = !m_threw_as || (m_exception != m_exception_string);
4589         } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional
4590             m_failed = !m_threw_as;
4591         } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional
4592             m_failed = m_exception != m_exception_string;
4593         } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional
4594             m_failed = m_threw;
4595         }
4596 
4597         if(m_exception.size())
4598             m_exception = String("\"") + m_exception + "\"";
4599 
4600         if(is_running_in_test) {
4601             addAssert(m_at);
4602             DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this);
4603 
4604             if(m_failed)
4605                 addFailedAssert(m_at);
4606         } else if(m_failed) {
4607             failed_out_of_a_testing_context(*this);
4608         }
4609 
4610         return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks &&
4611             (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
4612     }
4613 
4614     void ResultBuilder::react() const {
4615         if(m_failed && checkIfShouldThrow(m_at))
4616             throwException();
4617     }
4618 
4619     void failed_out_of_a_testing_context(const AssertData& ad) {
4620         if(g_cs->ah)
4621             g_cs->ah(ad);
4622         else
4623             std::abort();
4624     }
4625 
4626     void decomp_assert(assertType::Enum at, const char* file, int line, const char* expr,
4627                        Result result) {
4628         bool failed = !result.m_passed;
4629 
4630         // ###################################################################################
4631         // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT
4632         // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED
4633         // ###################################################################################
4634         DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp);
4635         DOCTEST_ASSERT_IN_TESTS(result.m_decomp);
4636         // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
4637     }
4638 
4639     MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) {
4640         m_stream   = getTlsOss();
4641         m_file     = file;
4642         m_line     = line;
4643         m_severity = severity;
4644     }
4645 
4646     IExceptionTranslator::IExceptionTranslator()  = default;
4647     IExceptionTranslator::~IExceptionTranslator() = default;
4648 
4649     bool MessageBuilder::log() {
4650         m_string = getTlsOssResult();
4651         DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this);
4652 
4653         const bool isWarn = m_severity & assertType::is_warn;
4654 
4655         // warn is just a message in this context so we don't treat it as an assert
4656         if(!isWarn) {
4657             addAssert(m_severity);
4658             addFailedAssert(m_severity);
4659         }
4660 
4661         return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn &&
4662             (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
4663     }
4664 
4665     void MessageBuilder::react() {
4666         if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional
4667             throwException();
4668     }
4669 
4670     MessageBuilder::~MessageBuilder() = default;
4671 } // namespace detail
4672 namespace {
4673     using namespace detail;
4674 
4675     template <typename Ex>
4676     DOCTEST_NORETURN void throw_exception(Ex const& e) {
4677 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
4678         throw e;
4679 #else  // DOCTEST_CONFIG_NO_EXCEPTIONS
4680         std::cerr << "doctest will terminate because it needed to throw an exception.\n"
4681                   << "The message was: " << e.what() << '\n';
4682         std::terminate();
4683 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
4684     }
4685 
4686 #ifndef DOCTEST_INTERNAL_ERROR
4687 #define DOCTEST_INTERNAL_ERROR(msg)                                                                \
4688     throw_exception(std::logic_error(                                                              \
4689             __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg))
4690 #endif // DOCTEST_INTERNAL_ERROR
4691 
4692     // clang-format off
4693 
4694 // =================================================================================================
4695 // The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp
4696 // This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched.
4697 // =================================================================================================
4698 
4699     class XmlEncode {
4700     public:
4701         enum ForWhat { ForTextNodes, ForAttributes };
4702 
4703         XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
4704 
4705         void encodeTo( std::ostream& os ) const;
4706 
4707         friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
4708 
4709     private:
4710         std::string m_str;
4711         ForWhat m_forWhat;
4712     };
4713 
4714     class XmlWriter {
4715     public:
4716 
4717         class ScopedElement {
4718         public:
4719             ScopedElement( XmlWriter* writer );
4720 
4721             ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT;
4722             ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT;
4723 
4724             ~ScopedElement();
4725 
4726             ScopedElement& writeText( std::string const& text, bool indent = true );
4727 
4728             template<typename T>
4729             ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
4730                 m_writer->writeAttribute( name, attribute );
4731                 return *this;
4732             }
4733 
4734         private:
4735             mutable XmlWriter* m_writer = nullptr;
4736         };
4737 
4738         XmlWriter( std::ostream& os = std::cout );
4739         ~XmlWriter();
4740 
4741         XmlWriter( XmlWriter const& ) = delete;
4742         XmlWriter& operator=( XmlWriter const& ) = delete;
4743 
4744         XmlWriter& startElement( std::string const& name );
4745 
4746         ScopedElement scopedElement( std::string const& name );
4747 
4748         XmlWriter& endElement();
4749 
4750         XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
4751 
4752         XmlWriter& writeAttribute( std::string const& name, const char* attribute );
4753 
4754         XmlWriter& writeAttribute( std::string const& name, bool attribute );
4755 
4756         template<typename T>
4757         XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
4758         std::stringstream rss;
4759             rss << attribute;
4760             return writeAttribute( name, rss.str() );
4761         }
4762 
4763         XmlWriter& writeText( std::string const& text, bool indent = true );
4764 
4765         //XmlWriter& writeComment( std::string const& text );
4766 
4767         //void writeStylesheetRef( std::string const& url );
4768 
4769         //XmlWriter& writeBlankLine();
4770 
4771         void ensureTagClosed();
4772 
4773     private:
4774 
4775         void writeDeclaration();
4776 
4777         void newlineIfNecessary();
4778 
4779         bool m_tagIsOpen = false;
4780         bool m_needsNewline = false;
4781         std::vector<std::string> m_tags;
4782         std::string m_indent;
4783         std::ostream& m_os;
4784     };
4785 
4786 // =================================================================================================
4787 // The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp
4788 // This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched.
4789 // =================================================================================================
4790 
4791 using uchar = unsigned char;
4792 
4793 namespace {
4794 
4795     size_t trailingBytes(unsigned char c) {
4796         if ((c & 0xE0) == 0xC0) {
4797             return 2;
4798         }
4799         if ((c & 0xF0) == 0xE0) {
4800             return 3;
4801         }
4802         if ((c & 0xF8) == 0xF0) {
4803             return 4;
4804         }
4805         DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
4806     }
4807 
4808     uint32_t headerValue(unsigned char c) {
4809         if ((c & 0xE0) == 0xC0) {
4810             return c & 0x1F;
4811         }
4812         if ((c & 0xF0) == 0xE0) {
4813             return c & 0x0F;
4814         }
4815         if ((c & 0xF8) == 0xF0) {
4816             return c & 0x07;
4817         }
4818         DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
4819     }
4820 
4821     void hexEscapeChar(std::ostream& os, unsigned char c) {
4822         std::ios_base::fmtflags f(os.flags());
4823         os << "\\x"
4824             << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
4825             << static_cast<int>(c);
4826         os.flags(f);
4827     }
4828 
4829 } // anonymous namespace
4830 
4831     XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
4832     :   m_str( str ),
4833         m_forWhat( forWhat )
4834     {}
4835 
4836     void XmlEncode::encodeTo( std::ostream& os ) const {
4837         // Apostrophe escaping not necessary if we always use " to write attributes
4838         // (see: https://www.w3.org/TR/xml/#syntax)
4839 
4840         for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
4841             uchar c = m_str[idx];
4842             switch (c) {
4843             case '<':   os << "&lt;"; break;
4844             case '&':   os << "&amp;"; break;
4845 
4846             case '>':
4847                 // See: https://www.w3.org/TR/xml/#syntax
4848                 if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
4849                     os << "&gt;";
4850                 else
4851                     os << c;
4852                 break;
4853 
4854             case '\"':
4855                 if (m_forWhat == ForAttributes)
4856                     os << "&quot;";
4857                 else
4858                     os << c;
4859                 break;
4860 
4861             default:
4862                 // Check for control characters and invalid utf-8
4863 
4864                 // Escape control characters in standard ascii
4865                 // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
4866                 if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
4867                     hexEscapeChar(os, c);
4868                     break;
4869                 }
4870 
4871                 // Plain ASCII: Write it to stream
4872                 if (c < 0x7F) {
4873                     os << c;
4874                     break;
4875                 }
4876 
4877                 // UTF-8 territory
4878                 // Check if the encoding is valid and if it is not, hex escape bytes.
4879                 // Important: We do not check the exact decoded values for validity, only the encoding format
4880                 // First check that this bytes is a valid lead byte:
4881                 // This means that it is not encoded as 1111 1XXX
4882                 // Or as 10XX XXXX
4883                 if (c <  0xC0 ||
4884                     c >= 0xF8) {
4885                     hexEscapeChar(os, c);
4886                     break;
4887                 }
4888 
4889                 auto encBytes = trailingBytes(c);
4890                 // Are there enough bytes left to avoid accessing out-of-bounds memory?
4891                 if (idx + encBytes - 1 >= m_str.size()) {
4892                     hexEscapeChar(os, c);
4893                     break;
4894                 }
4895                 // The header is valid, check data
4896                 // The next encBytes bytes must together be a valid utf-8
4897                 // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
4898                 bool valid = true;
4899                 uint32_t value = headerValue(c);
4900                 for (std::size_t n = 1; n < encBytes; ++n) {
4901                     uchar nc = m_str[idx + n];
4902                     valid &= ((nc & 0xC0) == 0x80);
4903                     value = (value << 6) | (nc & 0x3F);
4904                 }
4905 
4906                 if (
4907                     // Wrong bit pattern of following bytes
4908                     (!valid) ||
4909                     // Overlong encodings
4910                     (value < 0x80) ||
4911                     (                 value < 0x800   && encBytes > 2) || // removed "0x80 <= value &&" because redundant
4912                     (0x800 < value && value < 0x10000 && encBytes > 3) ||
4913                     // Encoded value out of range
4914                     (value >= 0x110000)
4915                     ) {
4916                     hexEscapeChar(os, c);
4917                     break;
4918                 }
4919 
4920                 // If we got here, this is in fact a valid(ish) utf-8 sequence
4921                 for (std::size_t n = 0; n < encBytes; ++n) {
4922                     os << m_str[idx + n];
4923                 }
4924                 idx += encBytes - 1;
4925                 break;
4926             }
4927         }
4928     }
4929 
4930     std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
4931         xmlEncode.encodeTo( os );
4932         return os;
4933     }
4934 
4935     XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
4936     :   m_writer( writer )
4937     {}
4938 
4939     XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT
4940     :   m_writer( other.m_writer ){
4941         other.m_writer = nullptr;
4942     }
4943     XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT {
4944         if ( m_writer ) {
4945             m_writer->endElement();
4946         }
4947         m_writer = other.m_writer;
4948         other.m_writer = nullptr;
4949         return *this;
4950     }
4951 
4952 
4953     XmlWriter::ScopedElement::~ScopedElement() {
4954         if( m_writer )
4955             m_writer->endElement();
4956     }
4957 
4958     XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
4959         m_writer->writeText( text, indent );
4960         return *this;
4961     }
4962 
4963     XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
4964     {
4965         writeDeclaration();
4966     }
4967 
4968     XmlWriter::~XmlWriter() {
4969         while( !m_tags.empty() )
4970             endElement();
4971     }
4972 
4973     XmlWriter& XmlWriter::startElement( std::string const& name ) {
4974         ensureTagClosed();
4975         newlineIfNecessary();
4976         m_os << m_indent << '<' << name;
4977         m_tags.push_back( name );
4978         m_indent += "  ";
4979         m_tagIsOpen = true;
4980         return *this;
4981     }
4982 
4983     XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
4984         ScopedElement scoped( this );
4985         startElement( name );
4986         return scoped;
4987     }
4988 
4989     XmlWriter& XmlWriter::endElement() {
4990         newlineIfNecessary();
4991         m_indent = m_indent.substr( 0, m_indent.size()-2 );
4992         if( m_tagIsOpen ) {
4993             m_os << "/>";
4994             m_tagIsOpen = false;
4995         }
4996         else {
4997             m_os << m_indent << "</" << m_tags.back() << ">";
4998         }
4999         m_os << std::endl;
5000         m_tags.pop_back();
5001         return *this;
5002     }
5003 
5004     XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {
5005         if( !name.empty() && !attribute.empty() )
5006             m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
5007         return *this;
5008     }
5009 
5010     XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) {
5011         if( !name.empty() && attribute && attribute[0] != '\0' )
5012             m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
5013         return *this;
5014     }
5015 
5016     XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {
5017         m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
5018         return *this;
5019     }
5020 
5021     XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
5022         if( !text.empty() ){
5023             bool tagWasOpen = m_tagIsOpen;
5024             ensureTagClosed();
5025             if( tagWasOpen && indent )
5026                 m_os << m_indent;
5027             m_os << XmlEncode( text );
5028             m_needsNewline = true;
5029         }
5030         return *this;
5031     }
5032 
5033     //XmlWriter& XmlWriter::writeComment( std::string const& text ) {
5034     //    ensureTagClosed();
5035     //    m_os << m_indent << "<!--" << text << "-->";
5036     //    m_needsNewline = true;
5037     //    return *this;
5038     //}
5039 
5040     //void XmlWriter::writeStylesheetRef( std::string const& url ) {
5041     //    m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
5042     //}
5043 
5044     //XmlWriter& XmlWriter::writeBlankLine() {
5045     //    ensureTagClosed();
5046     //    m_os << '\n';
5047     //    return *this;
5048     //}
5049 
5050     void XmlWriter::ensureTagClosed() {
5051         if( m_tagIsOpen ) {
5052             m_os << ">" << std::endl;
5053             m_tagIsOpen = false;
5054         }
5055     }
5056 
5057     void XmlWriter::writeDeclaration() {
5058         m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
5059     }
5060 
5061     void XmlWriter::newlineIfNecessary() {
5062         if( m_needsNewline ) {
5063             m_os << std::endl;
5064             m_needsNewline = false;
5065         }
5066     }
5067 
5068 // =================================================================================================
5069 // End of copy-pasted code from Catch
5070 // =================================================================================================
5071 
5072     // clang-format on
5073 
5074     struct XmlReporter : public IReporter
5075     {
5076         XmlWriter  xml;
5077         std::mutex mutex;
5078 
5079         // caching pointers/references to objects of these types - safe to do
5080         const ContextOptions& opt;
5081         const TestCaseData*   tc = nullptr;
5082 
5083         XmlReporter(const ContextOptions& co)
5084                 : xml(*co.cout)
5085                 , opt(co) {}
5086 
5087         void log_contexts() {
5088             int num_contexts = get_num_active_contexts();
5089             if(num_contexts) {
5090                 auto              contexts = get_active_contexts();
5091                 std::stringstream ss;
5092                 for(int i = 0; i < num_contexts; ++i) {
5093                     contexts[i]->stringify(&ss);
5094                     xml.scopedElement("Info").writeText(ss.str());
5095                     ss.str("");
5096                 }
5097             }
5098         }
5099 
5100         unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; }
5101 
5102         void test_case_start_impl(const TestCaseData& in) {
5103             bool open_ts_tag = false;
5104             if(tc != nullptr) { // we have already opened a test suite
5105                 if(std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) {
5106                     xml.endElement();
5107                     open_ts_tag = true;
5108                 }
5109             }
5110             else {
5111                 open_ts_tag = true; // first test case ==> first test suite
5112             }
5113 
5114             if(open_ts_tag) {
5115                 xml.startElement("TestSuite");
5116                 xml.writeAttribute("name", in.m_test_suite);
5117             }
5118 
5119             tc = &in;
5120             xml.startElement("TestCase")
5121                     .writeAttribute("name", in.m_name)
5122                     .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str()))
5123                     .writeAttribute("line", line(in.m_line))
5124                     .writeAttribute("description", in.m_description);
5125 
5126             if(Approx(in.m_timeout) != 0)
5127                 xml.writeAttribute("timeout", in.m_timeout);
5128             if(in.m_may_fail)
5129                 xml.writeAttribute("may_fail", true);
5130             if(in.m_should_fail)
5131                 xml.writeAttribute("should_fail", true);
5132         }
5133 
5134         // =========================================================================================
5135         // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE
5136         // =========================================================================================
5137 
5138         void report_query(const QueryData& in) override {
5139             test_run_start();
5140             if(opt.list_reporters) {
5141                 for(auto& curr : getListeners())
5142                     xml.scopedElement("Listener")
5143                             .writeAttribute("priority", curr.first.first)
5144                             .writeAttribute("name", curr.first.second);
5145                 for(auto& curr : getReporters())
5146                     xml.scopedElement("Reporter")
5147                             .writeAttribute("priority", curr.first.first)
5148                             .writeAttribute("name", curr.first.second);
5149             } else if(opt.count || opt.list_test_cases) {
5150                 for(unsigned i = 0; i < in.num_data; ++i) {
5151                     xml.scopedElement("TestCase").writeAttribute("name", in.data[i]->m_name)
5152                         .writeAttribute("testsuite", in.data[i]->m_test_suite)
5153                         .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str()))
5154                         .writeAttribute("line", line(in.data[i]->m_line));
5155                 }
5156                 xml.scopedElement("OverallResultsTestCases")
5157                         .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters);
5158             } else if(opt.list_test_suites) {
5159                 for(unsigned i = 0; i < in.num_data; ++i)
5160                     xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite);
5161                 xml.scopedElement("OverallResultsTestCases")
5162                         .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters);
5163                 xml.scopedElement("OverallResultsTestSuites")
5164                         .writeAttribute("unskipped", in.run_stats->numTestSuitesPassingFilters);
5165             }
5166             xml.endElement();
5167         }
5168 
5169         void test_run_start() override {
5170             // remove .exe extension - mainly to have the same output on UNIX and Windows
5171             std::string binary_name = skipPathFromFilename(opt.binary_name.c_str());
5172 #ifdef DOCTEST_PLATFORM_WINDOWS
5173             if(binary_name.rfind(".exe") != std::string::npos)
5174                 binary_name = binary_name.substr(0, binary_name.length() - 4);
5175 #endif // DOCTEST_PLATFORM_WINDOWS
5176 
5177             xml.startElement("doctest").writeAttribute("binary", binary_name);
5178             if(opt.no_version == false)
5179                 xml.writeAttribute("version", DOCTEST_VERSION_STR);
5180 
5181             // only the consequential ones (TODO: filters)
5182             xml.scopedElement("Options")
5183                     .writeAttribute("order_by", opt.order_by.c_str())
5184                     .writeAttribute("rand_seed", opt.rand_seed)
5185                     .writeAttribute("first", opt.first)
5186                     .writeAttribute("last", opt.last)
5187                     .writeAttribute("abort_after", opt.abort_after)
5188                     .writeAttribute("subcase_filter_levels", opt.subcase_filter_levels)
5189                     .writeAttribute("case_sensitive", opt.case_sensitive)
5190                     .writeAttribute("no_throw", opt.no_throw)
5191                     .writeAttribute("no_skip", opt.no_skip);
5192         }
5193 
5194         void test_run_end(const TestRunStats& p) override {
5195             if(tc) // the TestSuite tag - only if there has been at least 1 test case
5196                 xml.endElement();
5197 
5198             xml.scopedElement("OverallResultsAsserts")
5199                     .writeAttribute("successes", p.numAsserts - p.numAssertsFailed)
5200                     .writeAttribute("failures", p.numAssertsFailed);
5201 
5202             xml.startElement("OverallResultsTestCases")
5203                     .writeAttribute("successes",
5204                                     p.numTestCasesPassingFilters - p.numTestCasesFailed)
5205                     .writeAttribute("failures", p.numTestCasesFailed);
5206             if(opt.no_skipped_summary == false)
5207                 xml.writeAttribute("skipped", p.numTestCases - p.numTestCasesPassingFilters);
5208             xml.endElement();
5209 
5210             xml.endElement();
5211         }
5212 
5213         void test_case_start(const TestCaseData& in) override {
5214             test_case_start_impl(in);
5215             xml.ensureTagClosed();
5216         }
5217 
5218         void test_case_reenter(const TestCaseData&) override {}
5219 
5220         void test_case_end(const CurrentTestCaseStats& st) override {
5221             xml.startElement("OverallResultsAsserts")
5222                     .writeAttribute("successes",
5223                                     st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest)
5224                     .writeAttribute("failures", st.numAssertsFailedCurrentTest);
5225             if(opt.duration)
5226                 xml.writeAttribute("duration", st.seconds);
5227             if(tc->m_expected_failures)
5228                 xml.writeAttribute("expected_failures", tc->m_expected_failures);
5229             xml.endElement();
5230 
5231             xml.endElement();
5232         }
5233 
5234         void test_case_exception(const TestCaseException& e) override {
5235             std::lock_guard<std::mutex> lock(mutex);
5236 
5237             xml.scopedElement("Exception")
5238                     .writeAttribute("crash", e.is_crash)
5239                     .writeText(e.error_string.c_str());
5240         }
5241 
5242         void subcase_start(const SubcaseSignature& in) override {
5243             std::lock_guard<std::mutex> lock(mutex);
5244 
5245             xml.startElement("SubCase")
5246                     .writeAttribute("name", in.m_name)
5247                     .writeAttribute("filename", skipPathFromFilename(in.m_file))
5248                     .writeAttribute("line", line(in.m_line));
5249             xml.ensureTagClosed();
5250         }
5251 
5252         void subcase_end() override { xml.endElement(); }
5253 
5254         void log_assert(const AssertData& rb) override {
5255             if(!rb.m_failed && !opt.success)
5256                 return;
5257 
5258             std::lock_guard<std::mutex> lock(mutex);
5259 
5260             xml.startElement("Expression")
5261                     .writeAttribute("success", !rb.m_failed)
5262                     .writeAttribute("type", assertString(rb.m_at))
5263                     .writeAttribute("filename", skipPathFromFilename(rb.m_file))
5264                     .writeAttribute("line", line(rb.m_line));
5265 
5266             xml.scopedElement("Original").writeText(rb.m_expr);
5267 
5268             if(rb.m_threw)
5269                 xml.scopedElement("Exception").writeText(rb.m_exception.c_str());
5270 
5271             if(rb.m_at & assertType::is_throws_as)
5272                 xml.scopedElement("ExpectedException").writeText(rb.m_exception_type);
5273             if(rb.m_at & assertType::is_throws_with)
5274                 xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string);
5275             if((rb.m_at & assertType::is_normal) && !rb.m_threw)
5276                 xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str());
5277 
5278             log_contexts();
5279 
5280             xml.endElement();
5281         }
5282 
5283         void log_message(const MessageData& mb) override {
5284             std::lock_guard<std::mutex> lock(mutex);
5285 
5286             xml.startElement("Message")
5287                     .writeAttribute("type", failureString(mb.m_severity))
5288                     .writeAttribute("filename", skipPathFromFilename(mb.m_file))
5289                     .writeAttribute("line", line(mb.m_line));
5290 
5291             xml.scopedElement("Text").writeText(mb.m_string.c_str());
5292 
5293             log_contexts();
5294 
5295             xml.endElement();
5296         }
5297 
5298         void test_case_skipped(const TestCaseData& in) override {
5299             if(opt.no_skipped_summary == false) {
5300                 test_case_start_impl(in);
5301                 xml.writeAttribute("skipped", "true");
5302                 xml.endElement();
5303             }
5304         }
5305     };
5306 
5307     DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter);
5308 
5309     void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) {
5310         if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) ==
5311             0) //!OCLINT bitwise operator in conditional
5312             s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) "
5313                 << Color::None;
5314 
5315         if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional
5316             s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n";
5317         } else if((rb.m_at & assertType::is_throws_as) &&
5318                     (rb.m_at & assertType::is_throws_with)) { //!OCLINT
5319             s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \""
5320                 << rb.m_exception_string << "\", " << rb.m_exception_type << " ) " << Color::None;
5321             if(rb.m_threw) {
5322                 if(!rb.m_failed) {
5323                     s << "threw as expected!\n";
5324                 } else {
5325                     s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n";
5326                 }
5327             } else {
5328                 s << "did NOT throw at all!\n";
5329             }
5330         } else if(rb.m_at &
5331                     assertType::is_throws_as) { //!OCLINT bitwise operator in conditional
5332             s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", "
5333                 << rb.m_exception_type << " ) " << Color::None
5334                 << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" :
5335                                                 "threw a DIFFERENT exception: ") :
5336                                 "did NOT throw at all!")
5337                 << Color::Cyan << rb.m_exception << "\n";
5338         } else if(rb.m_at &
5339                     assertType::is_throws_with) { //!OCLINT bitwise operator in conditional
5340             s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \""
5341                 << rb.m_exception_string << "\" ) " << Color::None
5342                 << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" :
5343                                                 "threw a DIFFERENT exception: ") :
5344                                 "did NOT throw at all!")
5345                 << Color::Cyan << rb.m_exception << "\n";
5346         } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional
5347             s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan
5348                 << rb.m_exception << "\n";
5349         } else {
5350             s << (rb.m_threw ? "THREW exception: " :
5351                                 (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n"));
5352             if(rb.m_threw)
5353                 s << rb.m_exception << "\n";
5354             else
5355                 s << "  values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n";
5356         }
5357     }
5358 
5359     // TODO:
5360     // - log_message()
5361     // - respond to queries
5362     // - honor remaining options
5363     // - more attributes in tags
5364     struct JUnitReporter : public IReporter
5365     {
5366         XmlWriter  xml;
5367         std::mutex mutex;
5368         Timer timer;
5369         std::vector<String> deepestSubcaseStackNames;
5370 
5371         struct JUnitTestCaseData
5372         {
5373             static std::string getCurrentTimestamp() {
5374                 // Beware, this is not reentrant because of backward compatibility issues
5375                 // Also, UTC only, again because of backward compatibility (%z is C++11)
5376                 time_t rawtime;
5377                 std::time(&rawtime);
5378                 auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
5379 
5380                 std::tm timeInfo;
5381 #ifdef DOCTEST_PLATFORM_WINDOWS
5382                 gmtime_s(&timeInfo, &rawtime);
5383 #else // DOCTEST_PLATFORM_WINDOWS
5384                 gmtime_r(&rawtime, &timeInfo);
5385 #endif // DOCTEST_PLATFORM_WINDOWS
5386 
5387                 char timeStamp[timeStampSize];
5388                 const char* const fmt = "%Y-%m-%dT%H:%M:%SZ";
5389 
5390                 std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
5391                 return std::string(timeStamp);
5392             }
5393 
5394             struct JUnitTestMessage
5395             {
5396                 JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details)
5397                     : message(_message), type(_type), details(_details) {}
5398 
5399                 JUnitTestMessage(const std::string& _message, const std::string& _details)
5400                     : message(_message), type(), details(_details) {}
5401 
5402                 std::string message, type, details;
5403             };
5404 
5405             struct JUnitTestCase
5406             {
5407                 JUnitTestCase(const std::string& _classname, const std::string& _name)
5408                     : classname(_classname), name(_name), time(0), failures() {}
5409 
5410                 std::string classname, name;
5411                 double time;
5412                 std::vector<JUnitTestMessage> failures, errors;
5413             };
5414 
5415             void add(const std::string& classname, const std::string& name) {
5416                 testcases.emplace_back(classname, name);
5417             }
5418 
5419             void appendSubcaseNamesToLastTestcase(std::vector<String> nameStack) {
5420                 for(auto& curr: nameStack)
5421                     if(curr.size())
5422                         testcases.back().name += std::string("/") + curr.c_str();
5423             }
5424 
5425             void addTime(double time) {
5426                 if(time < 1e-4)
5427                     time = 0;
5428                 testcases.back().time = time;
5429                 totalSeconds += time;
5430             }
5431 
5432             void addFailure(const std::string& message, const std::string& type, const std::string& details) {
5433                 testcases.back().failures.emplace_back(message, type, details);
5434                 ++totalFailures;
5435             }
5436 
5437             void addError(const std::string& message, const std::string& details) {
5438                 testcases.back().errors.emplace_back(message, details);
5439                 ++totalErrors;
5440             }
5441 
5442             std::vector<JUnitTestCase> testcases;
5443             double totalSeconds = 0;
5444             int totalErrors = 0, totalFailures = 0;
5445         };
5446 
5447         JUnitTestCaseData testCaseData;
5448 
5449         // caching pointers/references to objects of these types - safe to do
5450         const ContextOptions& opt;
5451         const TestCaseData*   tc = nullptr;
5452 
5453         JUnitReporter(const ContextOptions& co)
5454                 : xml(*co.cout)
5455                 , opt(co) {}
5456 
5457         unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; }
5458 
5459         // =========================================================================================
5460         // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE
5461         // =========================================================================================
5462 
5463         void report_query(const QueryData&) override {}
5464 
5465         void test_run_start() override {}
5466 
5467         void test_run_end(const TestRunStats& p) override {
5468             // remove .exe extension - mainly to have the same output on UNIX and Windows
5469             std::string binary_name = skipPathFromFilename(opt.binary_name.c_str());
5470 #ifdef DOCTEST_PLATFORM_WINDOWS
5471             if(binary_name.rfind(".exe") != std::string::npos)
5472                 binary_name = binary_name.substr(0, binary_name.length() - 4);
5473 #endif // DOCTEST_PLATFORM_WINDOWS
5474             xml.startElement("testsuites");
5475             xml.startElement("testsuite").writeAttribute("name", binary_name)
5476                     .writeAttribute("errors", testCaseData.totalErrors)
5477                     .writeAttribute("failures", testCaseData.totalFailures)
5478                     .writeAttribute("tests", p.numAsserts);
5479             if(opt.no_time_in_output == false) {
5480                 xml.writeAttribute("time", testCaseData.totalSeconds);
5481                 xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp());
5482             }
5483             if(opt.no_version == false)
5484                 xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR);
5485 
5486             for(const auto& testCase : testCaseData.testcases) {
5487                 xml.startElement("testcase")
5488                     .writeAttribute("classname", testCase.classname)
5489                     .writeAttribute("name", testCase.name);
5490                 if(opt.no_time_in_output == false)
5491                     xml.writeAttribute("time", testCase.time);
5492                 // This is not ideal, but it should be enough to mimic gtest's junit output.
5493                 xml.writeAttribute("status", "run");
5494 
5495                 for(const auto& failure : testCase.failures) {
5496                     xml.scopedElement("failure")
5497                         .writeAttribute("message", failure.message)
5498                         .writeAttribute("type", failure.type)
5499                         .writeText(failure.details, false);
5500                 }
5501 
5502                 for(const auto& error : testCase.errors) {
5503                     xml.scopedElement("error")
5504                         .writeAttribute("message", error.message)
5505                         .writeText(error.details);
5506                 }
5507 
5508                 xml.endElement();
5509             }
5510             xml.endElement();
5511             xml.endElement();
5512         }
5513 
5514         void test_case_start(const TestCaseData& in) override {
5515             testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name);
5516             timer.start();
5517         }
5518 
5519         void test_case_reenter(const TestCaseData& in) override {
5520             testCaseData.addTime(timer.getElapsedSeconds());
5521             testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames);
5522             deepestSubcaseStackNames.clear();
5523 
5524             timer.start();
5525             testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name);
5526         }
5527 
5528         void test_case_end(const CurrentTestCaseStats&) override {
5529             testCaseData.addTime(timer.getElapsedSeconds());
5530             testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames);
5531             deepestSubcaseStackNames.clear();
5532         }
5533 
5534         void test_case_exception(const TestCaseException& e) override {
5535             std::lock_guard<std::mutex> lock(mutex);
5536             testCaseData.addError("exception", e.error_string.c_str());
5537         }
5538 
5539         void subcase_start(const SubcaseSignature& in) override {
5540             std::lock_guard<std::mutex> lock(mutex);
5541             deepestSubcaseStackNames.push_back(in.m_name);
5542         }
5543 
5544         void subcase_end() override {}
5545 
5546         void log_assert(const AssertData& rb) override {
5547             if(!rb.m_failed) // report only failures & ignore the `success` option
5548                 return;
5549 
5550             std::lock_guard<std::mutex> lock(mutex);
5551 
5552             std::ostringstream os;
5553             os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(")
5554               << line(rb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl;
5555 
5556             fulltext_log_assert_to_stream(os, rb);
5557             log_contexts(os);
5558             testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str());
5559         }
5560 
5561         void log_message(const MessageData&) override {}
5562 
5563         void test_case_skipped(const TestCaseData&) override {}
5564 
5565         void log_contexts(std::ostringstream& s) {
5566             int num_contexts = get_num_active_contexts();
5567             if(num_contexts) {
5568                 auto contexts = get_active_contexts();
5569 
5570                 s << "  logged: ";
5571                 for(int i = 0; i < num_contexts; ++i) {
5572                     s << (i == 0 ? "" : "          ");
5573                     contexts[i]->stringify(&s);
5574                     s << std::endl;
5575                 }
5576             }
5577         }
5578     };
5579 
5580     DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter);
5581 
5582     struct Whitespace
5583     {
5584         int nrSpaces;
5585         explicit Whitespace(int nr)
5586                 : nrSpaces(nr) {}
5587     };
5588 
5589     std::ostream& operator<<(std::ostream& out, const Whitespace& ws) {
5590         if(ws.nrSpaces != 0)
5591             out << std::setw(ws.nrSpaces) << ' ';
5592         return out;
5593     }
5594 
5595     struct ConsoleReporter : public IReporter
5596     {
5597         std::ostream&                 s;
5598         bool                          hasLoggedCurrentTestStart;
5599         std::vector<SubcaseSignature> subcasesStack;
5600         size_t                        currentSubcaseLevel;
5601         std::mutex                    mutex;
5602 
5603         // caching pointers/references to objects of these types - safe to do
5604         const ContextOptions& opt;
5605         const TestCaseData*   tc;
5606 
5607         ConsoleReporter(const ContextOptions& co)
5608                 : s(*co.cout)
5609                 , opt(co) {}
5610 
5611         ConsoleReporter(const ContextOptions& co, std::ostream& ostr)
5612                 : s(ostr)
5613                 , opt(co) {}
5614 
5615         // =========================================================================================
5616         // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE
5617         // =========================================================================================
5618 
5619         void separator_to_stream() {
5620             s << Color::Yellow
5621               << "==============================================================================="
5622                  "\n";
5623         }
5624 
5625         const char* getSuccessOrFailString(bool success, assertType::Enum at,
5626                                            const char* success_str) {
5627             if(success)
5628                 return success_str;
5629             return failureString(at);
5630         }
5631 
5632         Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) {
5633             return success ? Color::BrightGreen :
5634                              (at & assertType::is_warn) ? Color::Yellow : Color::Red;
5635         }
5636 
5637         void successOrFailColoredStringToStream(bool success, assertType::Enum at,
5638                                                 const char* success_str = "SUCCESS") {
5639             s << getSuccessOrFailColor(success, at)
5640               << getSuccessOrFailString(success, at, success_str) << ": ";
5641         }
5642 
5643         void log_contexts() {
5644             int num_contexts = get_num_active_contexts();
5645             if(num_contexts) {
5646                 auto contexts = get_active_contexts();
5647 
5648                 s << Color::None << "  logged: ";
5649                 for(int i = 0; i < num_contexts; ++i) {
5650                     s << (i == 0 ? "" : "          ");
5651                     contexts[i]->stringify(&s);
5652                     s << "\n";
5653                 }
5654             }
5655 
5656             s << "\n";
5657         }
5658 
5659         // this was requested to be made virtual so users could override it
5660         virtual void file_line_to_stream(const char* file, int line,
5661                                         const char* tail = "") {
5662             s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(")
5663             << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option
5664             << (opt.gnu_file_line ? ":" : "):") << tail;
5665         }
5666 
5667         void logTestStart() {
5668             if(hasLoggedCurrentTestStart)
5669                 return;
5670 
5671             separator_to_stream();
5672             file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n");
5673             if(tc->m_description)
5674                 s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n";
5675             if(tc->m_test_suite && tc->m_test_suite[0] != '\0')
5676                 s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n";
5677             if(strncmp(tc->m_name, "  Scenario:", 11) != 0)
5678                 s << Color::Yellow << "TEST CASE:  ";
5679             s << Color::None << tc->m_name << "\n";
5680 
5681             for(size_t i = 0; i < currentSubcaseLevel; ++i) {
5682                 if(subcasesStack[i].m_name[0] != '\0')
5683                     s << "  " << subcasesStack[i].m_name << "\n";
5684             }
5685 
5686             if(currentSubcaseLevel != subcasesStack.size()) {
5687                 s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None;
5688                 for(size_t i = 0; i < subcasesStack.size(); ++i) {
5689                     if(subcasesStack[i].m_name[0] != '\0')
5690                         s << "  " << subcasesStack[i].m_name << "\n";
5691                 }
5692             }
5693 
5694             s << "\n";
5695 
5696             hasLoggedCurrentTestStart = true;
5697         }
5698 
5699         void printVersion() {
5700             if(opt.no_version == false)
5701                 s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \""
5702                   << DOCTEST_VERSION_STR << "\"\n";
5703         }
5704 
5705         void printIntro() {
5706             printVersion();
5707             s << Color::Cyan << "[doctest] " << Color::None
5708               << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n";
5709         }
5710 
5711         void printHelp() {
5712             int sizePrefixDisplay = static_cast<int>(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY));
5713             printVersion();
5714             // clang-format off
5715             s << Color::Cyan << "[doctest]\n" << Color::None;
5716             s << Color::Cyan << "[doctest] " << Color::None;
5717             s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n";
5718             s << Color::Cyan << "[doctest] " << Color::None;
5719             s << "filter  values: \"str1,str2,str3\" (comma separated strings)\n";
5720             s << Color::Cyan << "[doctest]\n" << Color::None;
5721             s << Color::Cyan << "[doctest] " << Color::None;
5722             s << "filters use wildcards for matching strings\n";
5723             s << Color::Cyan << "[doctest] " << Color::None;
5724             s << "something passes a filter if any of the strings in a filter matches\n";
5725 #ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
5726             s << Color::Cyan << "[doctest]\n" << Color::None;
5727             s << Color::Cyan << "[doctest] " << Color::None;
5728             s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"" DOCTEST_CONFIG_OPTIONS_PREFIX "\" PREFIX!!!\n";
5729 #endif
5730             s << Color::Cyan << "[doctest]\n" << Color::None;
5731             s << Color::Cyan << "[doctest] " << Color::None;
5732             s << "Query flags - the program quits after them. Available:\n\n";
5733             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "?,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "help, -" DOCTEST_OPTIONS_PREFIX_DISPLAY "h                      "
5734               << Whitespace(sizePrefixDisplay*0) <<  "prints this message\n";
5735             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "v,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "version                       "
5736               << Whitespace(sizePrefixDisplay*1) << "prints the version\n";
5737             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "c,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "count                         "
5738               << Whitespace(sizePrefixDisplay*1) << "prints the number of matching tests\n";
5739             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ltc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-cases               "
5740               << Whitespace(sizePrefixDisplay*1) << "lists all matching tests by name\n";
5741             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-suites              "
5742               << Whitespace(sizePrefixDisplay*1) << "lists all matching test suites\n";
5743             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lr,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-reporters                "
5744               << Whitespace(sizePrefixDisplay*1) << "lists all registered reporters\n\n";
5745             // ================================================================================== << 79
5746             s << Color::Cyan << "[doctest] " << Color::None;
5747             s << "The available <int>/<string> options/filters are:\n\n";
5748             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tc,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case=<filters>           "
5749               << Whitespace(sizePrefixDisplay*1) << "filters     tests by their name\n";
5750             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case-exclude=<filters>   "
5751               << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their name\n";
5752             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sf,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file=<filters>         "
5753               << Whitespace(sizePrefixDisplay*1) << "filters     tests by their file\n";
5754             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfe, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file-exclude=<filters> "
5755               << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their file\n";
5756             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ts,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite=<filters>          "
5757               << Whitespace(sizePrefixDisplay*1) << "filters     tests by their test suite\n";
5758             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tse, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite-exclude=<filters>  "
5759               << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their test suite\n";
5760             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sc,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase=<filters>             "
5761               << Whitespace(sizePrefixDisplay*1) << "filters     subcases by their name\n";
5762             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-exclude=<filters>     "
5763               << Whitespace(sizePrefixDisplay*1) << "filters OUT subcases by their name\n";
5764             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "r,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "reporters=<filters>           "
5765               << Whitespace(sizePrefixDisplay*1) << "reporters to use (console is default)\n";
5766             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "o,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "out=<string>                  "
5767               << Whitespace(sizePrefixDisplay*1) << "output filename\n";
5768             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by=<string>             "
5769               << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n";
5770             s << Whitespace(sizePrefixDisplay*3) << "                                       <string> - [file/suite/name/rand/none]\n";
5771             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed=<int>               "
5772               << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n";
5773             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first=<int>                   "
5774               << Whitespace(sizePrefixDisplay*1) << "the first test passing the filters to\n";
5775             s << Whitespace(sizePrefixDisplay*3) << "                                       execute - for range-based execution\n";
5776             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "l,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "last=<int>                    "
5777               << Whitespace(sizePrefixDisplay*1) << "the last test passing the filters to\n";
5778             s << Whitespace(sizePrefixDisplay*3) << "                                       execute - for range-based execution\n";
5779             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "aa,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "abort-after=<int>             "
5780               << Whitespace(sizePrefixDisplay*1) << "stop after <int> failed assertions\n";
5781             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "scfl,--" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-filter-levels=<int>   "
5782               << Whitespace(sizePrefixDisplay*1) << "apply filters for the first <int> levels\n";
5783             s << Color::Cyan << "\n[doctest] " << Color::None;
5784             s << "Bool options - can be used like flags and true is assumed. Available:\n\n";
5785             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "s,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "success=<bool>                "
5786               << Whitespace(sizePrefixDisplay*1) << "include successful assertions in output\n";
5787             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "cs,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "case-sensitive=<bool>         "
5788               << Whitespace(sizePrefixDisplay*1) << "filters being treated as case sensitive\n";
5789             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "e,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "exit=<bool>                   "
5790               << Whitespace(sizePrefixDisplay*1) << "exits after the tests finish\n";
5791             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d,   --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration=<bool>               "
5792               << Whitespace(sizePrefixDisplay*1) << "prints the time duration of each test\n";
5793             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw=<bool>               "
5794               << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related assert checks\n";
5795             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode=<bool>            "
5796               << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always with success\n";
5797             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run=<bool>                 "
5798               << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest operations\n";
5799             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version=<bool>             "
5800               << Whitespace(sizePrefixDisplay*1) << "omit the framework version in the output\n";
5801             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors=<bool>              "
5802               << Whitespace(sizePrefixDisplay*1) << "disables colors in output\n";
5803             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "fc,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "force-colors=<bool>           "
5804               << Whitespace(sizePrefixDisplay*1) << "use colors even when not in a tty\n";
5805             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nb,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-breaks=<bool>              "
5806               << Whitespace(sizePrefixDisplay*1) << "disables breakpoints in debuggers\n";
5807             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ns,  --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-skip=<bool>                "
5808               << Whitespace(sizePrefixDisplay*1) << "don't skip test cases marked as skip\n";
5809             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "gfl, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "gnu-file-line=<bool>          "
5810               << Whitespace(sizePrefixDisplay*1) << ":n: vs (n): for line numbers in output\n";
5811             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "npf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-path-filenames=<bool>      "
5812               << Whitespace(sizePrefixDisplay*1) << "only filenames and no paths in output\n";
5813             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nln, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-line-numbers=<bool>        "
5814               << Whitespace(sizePrefixDisplay*1) << "0 instead of real line numbers in output\n";
5815             // ================================================================================== << 79
5816             // clang-format on
5817 
5818             s << Color::Cyan << "\n[doctest] " << Color::None;
5819             s << "for more information visit the project documentation\n\n";
5820         }
5821 
5822         void printRegisteredReporters() {
5823             printVersion();
5824             auto printReporters = [this] (const reporterMap& reporters, const char* type) {
5825                 if(reporters.size()) {
5826                     s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n";
5827                     for(auto& curr : reporters)
5828                         s << "priority: " << std::setw(5) << curr.first.first
5829                           << " name: " << curr.first.second << "\n";
5830                 }
5831             };
5832             printReporters(getListeners(), "listeners");
5833             printReporters(getReporters(), "reporters");
5834         }
5835 
5836 // TODO: upstream the change to doctest : list_query_results() was declared but never referenced
5837 #if 0 /* dead code */
5838         void list_query_results() {
5839             separator_to_stream();
5840             if(opt.count || opt.list_test_cases) {
5841                 s << Color::Cyan << "[doctest] " << Color::None
5842                   << "unskipped test cases passing the current filters: "
5843                   << g_cs->numTestCasesPassingFilters << "\n";
5844             } else if(opt.list_test_suites) {
5845                 s << Color::Cyan << "[doctest] " << Color::None
5846                   << "unskipped test cases passing the current filters: "
5847                   << g_cs->numTestCasesPassingFilters << "\n";
5848                 s << Color::Cyan << "[doctest] " << Color::None
5849                   << "test suites with unskipped test cases passing the current filters: "
5850                   << g_cs->numTestSuitesPassingFilters << "\n";
5851             }
5852         }
5853 #endif
5854 
5855         // =========================================================================================
5856         // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE
5857         // =========================================================================================
5858 
5859         void report_query(const QueryData& in) override {
5860             if(opt.version) {
5861                 printVersion();
5862             } else if(opt.help) {
5863                 printHelp();
5864             } else if(opt.list_reporters) {
5865                 printRegisteredReporters();
5866             } else if(opt.count || opt.list_test_cases) {
5867                 if(opt.list_test_cases) {
5868                     s << Color::Cyan << "[doctest] " << Color::None
5869                       << "listing all test case names\n";
5870                     separator_to_stream();
5871                 }
5872 
5873                 for(unsigned i = 0; i < in.num_data; ++i)
5874                     s << Color::None << in.data[i]->m_name << "\n";
5875 
5876                 separator_to_stream();
5877 
5878                 s << Color::Cyan << "[doctest] " << Color::None
5879                   << "unskipped test cases passing the current filters: "
5880                   << g_cs->numTestCasesPassingFilters << "\n";
5881 
5882             } else if(opt.list_test_suites) {
5883                 s << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n";
5884                 separator_to_stream();
5885 
5886                 for(unsigned i = 0; i < in.num_data; ++i)
5887                     s << Color::None << in.data[i]->m_test_suite << "\n";
5888 
5889                 separator_to_stream();
5890 
5891                 s << Color::Cyan << "[doctest] " << Color::None
5892                   << "unskipped test cases passing the current filters: "
5893                   << g_cs->numTestCasesPassingFilters << "\n";
5894                 s << Color::Cyan << "[doctest] " << Color::None
5895                   << "test suites with unskipped test cases passing the current filters: "
5896                   << g_cs->numTestSuitesPassingFilters << "\n";
5897             }
5898         }
5899 
5900         void test_run_start() override { printIntro(); }
5901 
5902         void test_run_end(const TestRunStats& p) override {
5903             separator_to_stream();
5904             s << std::dec;
5905 
5906             auto totwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters, static_cast<unsigned>(p.numAsserts))) + 1)));
5907             auto passwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast<unsigned>(p.numAsserts - p.numAssertsFailed))) + 1)));
5908             auto failwidth = int(std::ceil(log10((std::max(p.numTestCasesFailed, static_cast<unsigned>(p.numAssertsFailed))) + 1)));
5909             const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0;
5910             s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth)
5911               << p.numTestCasesPassingFilters << " | "
5912               << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None :
5913                                                                           Color::Green)
5914               << std::setw(passwidth) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed"
5915               << Color::None << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None)
5916               << std::setw(failwidth) << p.numTestCasesFailed << " failed" << Color::None << " |";
5917             if(opt.no_skipped_summary == false) {
5918                 const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters;
5919                 s << " " << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped
5920                   << " skipped" << Color::None;
5921             }
5922             s << "\n";
5923             s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(totwidth)
5924               << p.numAsserts << " | "
5925               << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green)
5926               << std::setw(passwidth) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None
5927               << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth)
5928               << p.numAssertsFailed << " failed" << Color::None << " |\n";
5929             s << Color::Cyan << "[doctest] " << Color::None
5930               << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green)
5931               << ((p.numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl;
5932         }
5933 
5934         void test_case_start(const TestCaseData& in) override {
5935             hasLoggedCurrentTestStart = false;
5936             tc                        = &in;
5937             subcasesStack.clear();
5938             currentSubcaseLevel = 0;
5939         }
5940 
5941         void test_case_reenter(const TestCaseData&) override {
5942             subcasesStack.clear();
5943         }
5944 
5945         void test_case_end(const CurrentTestCaseStats& st) override {
5946             if(tc->m_no_output)
5947                 return;
5948 
5949             // log the preamble of the test case only if there is something
5950             // else to print - something other than that an assert has failed
5951             if(opt.duration ||
5952                (st.failure_flags && st.failure_flags != TestCaseFailureReason::AssertFailure))
5953                 logTestStart();
5954 
5955             if(opt.duration)
5956                 s << Color::None << std::setprecision(6) << std::fixed << st.seconds
5957                   << " s: " << tc->m_name << "\n";
5958 
5959             if(st.failure_flags & TestCaseFailureReason::Timeout)
5960                 s << Color::Red << "Test case exceeded time limit of " << std::setprecision(6)
5961                   << std::fixed << tc->m_timeout << "!\n";
5962 
5963             if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) {
5964                 s << Color::Red << "Should have failed but didn't! Marking it as failed!\n";
5965             } else if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) {
5966                 s << Color::Yellow << "Failed as expected so marking it as not failed\n";
5967             } else if(st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) {
5968                 s << Color::Yellow << "Allowed to fail so marking it as not failed\n";
5969             } else if(st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) {
5970                 s << Color::Red << "Didn't fail exactly " << tc->m_expected_failures
5971                   << " times so marking it as failed!\n";
5972             } else if(st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) {
5973                 s << Color::Yellow << "Failed exactly " << tc->m_expected_failures
5974                   << " times as expected so marking it as not failed!\n";
5975             }
5976             if(st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) {
5977                 s << Color::Red << "Aborting - too many failed asserts!\n";
5978             }
5979             s << Color::None; // lgtm [cpp/useless-expression]
5980         }
5981 
5982         void test_case_exception(const TestCaseException& e) override {
5983             if(tc->m_no_output)
5984                 return;
5985 
5986             logTestStart();
5987 
5988             file_line_to_stream(tc->m_file.c_str(), tc->m_line, " ");
5989             successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require :
5990                                                                    assertType::is_check);
5991             s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ")
5992               << Color::Cyan << e.error_string << "\n";
5993 
5994             int num_stringified_contexts = get_num_stringified_contexts();
5995             if(num_stringified_contexts) {
5996                 auto stringified_contexts = get_stringified_contexts();
5997                 s << Color::None << "  logged: ";
5998                 for(int i = num_stringified_contexts; i > 0; --i) {
5999                     s << (i == num_stringified_contexts ? "" : "          ")
6000                       << stringified_contexts[i - 1] << "\n";
6001                 }
6002             }
6003             s << "\n" << Color::None;
6004         }
6005 
6006         void subcase_start(const SubcaseSignature& subc) override {
6007             std::lock_guard<std::mutex> lock(mutex);
6008             subcasesStack.push_back(subc);
6009             ++currentSubcaseLevel;
6010             hasLoggedCurrentTestStart = false;
6011         }
6012 
6013         void subcase_end() override {
6014             std::lock_guard<std::mutex> lock(mutex);
6015             --currentSubcaseLevel;
6016             hasLoggedCurrentTestStart = false;
6017         }
6018 
6019         void log_assert(const AssertData& rb) override {
6020             if((!rb.m_failed && !opt.success) || tc->m_no_output)
6021                 return;
6022 
6023             std::lock_guard<std::mutex> lock(mutex);
6024 
6025             logTestStart();
6026 
6027             file_line_to_stream(rb.m_file, rb.m_line, " ");
6028             successOrFailColoredStringToStream(!rb.m_failed, rb.m_at);
6029 
6030             fulltext_log_assert_to_stream(s, rb);
6031 
6032             log_contexts();
6033         }
6034 
6035         void log_message(const MessageData& mb) override {
6036             if(tc->m_no_output)
6037                 return;
6038 
6039             std::lock_guard<std::mutex> lock(mutex);
6040 
6041             logTestStart();
6042 
6043             file_line_to_stream(mb.m_file, mb.m_line, " ");
6044             s << getSuccessOrFailColor(false, mb.m_severity)
6045               << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity,
6046                                         "MESSAGE") << ": ";
6047             s << Color::None << mb.m_string << "\n";
6048             log_contexts();
6049         }
6050 
6051         void test_case_skipped(const TestCaseData&) override {}
6052     };
6053 
6054     DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter);
6055 
6056 #ifdef DOCTEST_PLATFORM_WINDOWS
6057     struct DebugOutputWindowReporter : public ConsoleReporter
6058     {
6059         DOCTEST_THREAD_LOCAL static doctest_thread_local_wrapper<std::ostringstream> wrapped_oss;
6060 
6061         DebugOutputWindowReporter(const ContextOptions& co)
6062                 : ConsoleReporter(co, wrapped_oss.get()) {}
6063 
6064 #define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg)                                    \
6065     void func(type arg) override {                                                                 \
6066         bool with_col = g_no_colors;                                                               \
6067         g_no_colors   = false;                                                                     \
6068         ConsoleReporter::func(arg);                                                                \
6069         if(wrapped_oss.get().tellp() != std::streampos{}) {                                                      \
6070             DOCTEST_OUTPUT_DEBUG_STRING(wrapped_oss.get().str().c_str());                                        \
6071             wrapped_oss.get().str("");                                                                           \
6072         }                                                                                          \
6073         g_no_colors = with_col;                                                                    \
6074     }
6075 
6076         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY)
6077         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in)
6078         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in)
6079         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in)
6080         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in)
6081         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in)
6082         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in)
6083         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY)
6084         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData&, in)
6085         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData&, in)
6086         DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData&, in)
6087     };
6088 
6089     DOCTEST_THREAD_LOCAL doctest_thread_local_wrapper<std::ostringstream> DebugOutputWindowReporter::wrapped_oss;
6090 #endif // DOCTEST_PLATFORM_WINDOWS
6091 
6092     // the implementation of parseOption()
6093     bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) {
6094         // going from the end to the beginning and stopping on the first occurrence from the end
6095         for(int i = argc; i > 0; --i) {
6096             auto index = i - 1;
6097             auto temp = std::strstr(argv[index], pattern);
6098             if(temp && (value || strlen(temp) == strlen(pattern))) { //!OCLINT prefer early exits and continue
6099                 // eliminate matches in which the chars before the option are not '-'
6100                 bool noBadCharsFound = true;
6101                 auto curr            = argv[index];
6102                 while(curr != temp) {
6103                     if(*curr++ != '-') {
6104                         noBadCharsFound = false;
6105                         break;
6106                     }
6107                 }
6108                 if(noBadCharsFound && argv[index][0] == '-') {
6109                     if(value) {
6110                         // parsing the value of an option
6111                         temp += strlen(pattern);
6112                         const unsigned len = strlen(temp);
6113                         if(len) {
6114                             *value = temp;
6115                             return true;
6116                         }
6117                     } else {
6118                         // just a flag - no value
6119                         return true;
6120                     }
6121                 }
6122             }
6123         }
6124         return false;
6125     }
6126 
6127     // parses an option and returns the string after the '=' character
6128     bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr,
6129                      const String& defaultVal = String()) {
6130         if(value)
6131             *value = defaultVal;
6132 #ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
6133         // offset (normally 3 for "dt-") to skip prefix
6134         if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value))
6135             return true;
6136 #endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
6137         return parseOptionImpl(argc, argv, pattern, value);
6138     }
6139 
6140     // locates a flag on the command line
6141     bool parseFlag(int argc, const char* const* argv, const char* pattern) {
6142         return parseOption(argc, argv, pattern);
6143     }
6144 
6145     // parses a comma separated list of words after a pattern in one of the arguments in argv
6146     bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern,
6147                            std::vector<String>& res) {
6148         String filtersString;
6149         if(parseOption(argc, argv, pattern, &filtersString)) {
6150             // tokenize with "," as a separator
6151             // cppcheck-suppress strtokCalled
6152             DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
6153             auto pch = std::strtok(filtersString.c_str(), ","); // modifies the string
6154             while(pch != nullptr) {
6155                 if(strlen(pch))
6156                     res.push_back(pch);
6157                 // uses the strtok() internal state to go to the next token
6158                 // cppcheck-suppress strtokCalled
6159                 pch = std::strtok(nullptr, ",");
6160             }
6161             DOCTEST_CLANG_SUPPRESS_WARNING_POP
6162             return true;
6163         }
6164         return false;
6165     }
6166 
6167     enum optionType
6168     {
6169         option_bool,
6170         option_int
6171     };
6172 
6173     // parses an int/bool option from the command line
6174     bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type,
6175                         int& res) {
6176         String parsedValue;
6177         if(!parseOption(argc, argv, pattern, &parsedValue))
6178             return false;
6179 
6180         if(type == 0) {
6181             // boolean
6182             const char positive[][5] = {"1", "true", "on", "yes"};  // 5 - strlen("true") + 1
6183             const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1
6184 
6185             // if the value matches any of the positive/negative possibilities
6186             for(unsigned i = 0; i < 4; i++) {
6187                 if(parsedValue.compare(positive[i], true) == 0) {
6188                     res = 1; //!OCLINT parameter reassignment
6189                     return true;
6190                 }
6191                 if(parsedValue.compare(negative[i], true) == 0) {
6192                     res = 0; //!OCLINT parameter reassignment
6193                     return true;
6194                 }
6195             }
6196         } else {
6197             // integer
6198             // TODO: change this to use std::stoi or something else! currently it uses undefined behavior - assumes '0' on failed parse...
6199             int theInt = std::atoi(parsedValue.c_str()); // NOLINT
6200             if(theInt != 0) {
6201                 res = theInt; //!OCLINT parameter reassignment
6202                 return true;
6203             }
6204         }
6205         return false;
6206     }
6207 } // namespace
6208 
6209 Context::Context(int argc, const char* const* argv)
6210         : p(new detail::ContextState) {
6211     parseArgs(argc, argv, true);
6212     if(argc)
6213         p->binary_name = argv[0];
6214 }
6215 
6216 Context::~Context() {
6217     if(g_cs == p)
6218         g_cs = nullptr;
6219     delete p;
6220 }
6221 
6222 void Context::applyCommandLine(int argc, const char* const* argv) {
6223     parseArgs(argc, argv);
6224     if(argc)
6225         p->binary_name = argv[0];
6226 }
6227 
6228 // parses args
6229 void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) {
6230     using namespace detail;
6231 
6232     // clang-format off
6233     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file=",        p->filters[0]);
6234     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sf=",                 p->filters[0]);
6235     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file-exclude=",p->filters[1]);
6236     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sfe=",                p->filters[1]);
6237     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite=",         p->filters[2]);
6238     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ts=",                 p->filters[2]);
6239     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite-exclude=", p->filters[3]);
6240     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tse=",                p->filters[3]);
6241     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case=",          p->filters[4]);
6242     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tc=",                 p->filters[4]);
6243     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case-exclude=",  p->filters[5]);
6244     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tce=",                p->filters[5]);
6245     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase=",            p->filters[6]);
6246     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sc=",                 p->filters[6]);
6247     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase-exclude=",    p->filters[7]);
6248     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sce=",                p->filters[7]);
6249     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "reporters=",          p->filters[8]);
6250     parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "r=",                  p->filters[8]);
6251     // clang-format on
6252 
6253     int    intRes = 0;
6254     String strRes;
6255 
6256 #define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default)                                   \
6257     if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) ||  \
6258        parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes))   \
6259         p->var = static_cast<bool>(intRes);                                                        \
6260     else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) ||                           \
6261             parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname))                            \
6262         p->var = true;                                                                             \
6263     else if(withDefaults)                                                                          \
6264     p->var = default
6265 
6266 #define DOCTEST_PARSE_INT_OPTION(name, sname, var, default)                                        \
6267     if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_int, intRes) ||   \
6268        parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_int, intRes))    \
6269         p->var = intRes;                                                                           \
6270     else if(withDefaults)                                                                          \
6271     p->var = default
6272 
6273 #define DOCTEST_PARSE_STR_OPTION(name, sname, var, default)                                        \
6274     if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) ||        \
6275        parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) ||       \
6276        withDefaults)                                                                               \
6277     p->var = strRes
6278 
6279     // clang-format off
6280     DOCTEST_PARSE_STR_OPTION("out", "o", out, "");
6281     DOCTEST_PARSE_STR_OPTION("order-by", "ob", order_by, "file");
6282     DOCTEST_PARSE_INT_OPTION("rand-seed", "rs", rand_seed, 0);
6283 
6284     DOCTEST_PARSE_INT_OPTION("first", "f", first, 0);
6285     DOCTEST_PARSE_INT_OPTION("last", "l", last, UINT_MAX);
6286 
6287     DOCTEST_PARSE_INT_OPTION("abort-after", "aa", abort_after, 0);
6288     DOCTEST_PARSE_INT_OPTION("subcase-filter-levels", "scfl", subcase_filter_levels, INT_MAX);
6289 
6290     DOCTEST_PARSE_AS_BOOL_OR_FLAG("success", "s", success, false);
6291     DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false);
6292     DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false);
6293     DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false);
6294     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false);
6295     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false);
6296     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false);
6297     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false);
6298     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false);
6299     DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false);
6300     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-breaks", "nb", no_breaks, false);
6301     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skip", "ns", no_skip, false);
6302     DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC));
6303     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false);
6304     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false);
6305     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-debug-output", "ndo", no_debug_output, false);
6306     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false);
6307     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false);
6308     // clang-format on
6309 
6310     if(withDefaults) {
6311         p->help             = false;
6312         p->version          = false;
6313         p->count            = false;
6314         p->list_test_cases  = false;
6315         p->list_test_suites = false;
6316         p->list_reporters   = false;
6317     }
6318     if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "help") ||
6319        parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "h") ||
6320        parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "?")) {
6321         p->help = true;
6322         p->exit = true;
6323     }
6324     if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "version") ||
6325        parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "v")) {
6326         p->version = true;
6327         p->exit    = true;
6328     }
6329     if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "count") ||
6330        parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "c")) {
6331         p->count = true;
6332         p->exit  = true;
6333     }
6334     if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-cases") ||
6335        parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ltc")) {
6336         p->list_test_cases = true;
6337         p->exit            = true;
6338     }
6339     if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-suites") ||
6340        parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lts")) {
6341         p->list_test_suites = true;
6342         p->exit             = true;
6343     }
6344     if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-reporters") ||
6345        parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lr")) {
6346         p->list_reporters = true;
6347         p->exit           = true;
6348     }
6349 }
6350 
6351 // allows the user to add procedurally to the filters from the command line
6352 void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); }
6353 
6354 // allows the user to clear all filters from the command line
6355 void Context::clearFilters() {
6356     for(auto& curr : p->filters)
6357         curr.clear();
6358 }
6359 
6360 // allows the user to override procedurally the int/bool options from the command line
6361 void Context::setOption(const char* option, int value) {
6362     setOption(option, toString(value).c_str());
6363     // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
6364 }
6365 
6366 // allows the user to override procedurally the string options from the command line
6367 void Context::setOption(const char* option, const char* value) {
6368     auto argv   = String("-") + option + "=" + value;
6369     auto lvalue = argv.c_str();
6370     parseArgs(1, &lvalue);
6371 }
6372 
6373 // users should query this in their main() and exit the program if true
6374 bool Context::shouldExit() { return p->exit; }
6375 
6376 void Context::setAsDefaultForAssertsOutOfTestCases() { g_cs = p; }
6377 
6378 void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; }
6379 
6380 // the main function that does all the filtering and test running
6381 int Context::run() {
6382     using namespace detail;
6383 
6384     // save the old context state in case such was setup - for using asserts out of a testing context
6385     auto old_cs = g_cs;
6386     // this is the current contest
6387     g_cs               = p;
6388     is_running_in_test = true;
6389 
6390     g_no_colors = p->no_colors;
6391     p->resetRunData();
6392 
6393     // stdout by default
6394     p->cout = &std::cout;
6395     p->cerr = &std::cerr;
6396 
6397     // or to a file if specified
6398     std::fstream fstr;
6399     if(p->out.size()) {
6400         fstr.open(p->out.c_str(), std::fstream::out);
6401         p->cout = &fstr;
6402     }
6403 
6404     FatalConditionHandler::allocateAltStackMem();
6405 
6406     auto cleanup_and_return = [&]() {
6407         FatalConditionHandler::freeAltStackMem();
6408 
6409         if(fstr.is_open())
6410             fstr.close();
6411 
6412         // restore context
6413         g_cs               = old_cs;
6414         is_running_in_test = false;
6415 
6416         // we have to free the reporters which were allocated when the run started
6417         for(auto& curr : p->reporters_currently_used)
6418             delete curr;
6419         p->reporters_currently_used.clear();
6420 
6421         if(p->numTestCasesFailed && !p->no_exitcode)
6422             return EXIT_FAILURE;
6423         return EXIT_SUCCESS;
6424     };
6425 
6426     // setup default reporter if none is given through the command line
6427     if(p->filters[8].empty())
6428         p->filters[8].push_back("console");
6429 
6430     // check to see if any of the registered reporters has been selected
6431     for(auto& curr : getReporters()) {
6432         if(matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive))
6433             p->reporters_currently_used.push_back(curr.second(*g_cs));
6434     }
6435 
6436     // TODO: check if there is nothing in reporters_currently_used
6437 
6438     // prepend all listeners
6439     for(auto& curr : getListeners())
6440         p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs));
6441 
6442 #ifdef DOCTEST_PLATFORM_WINDOWS
6443     if(isDebuggerActive() && p->no_debug_output == false)
6444         p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs));
6445 #endif // DOCTEST_PLATFORM_WINDOWS
6446 
6447     // handle version, help and no_run
6448     if(p->no_run || p->version || p->help || p->list_reporters) {
6449         DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData());
6450 
6451         return cleanup_and_return();
6452     }
6453 
6454     std::vector<const TestCase*> testArray;
6455     for(auto& curr : getRegisteredTests())
6456         testArray.push_back(&curr);
6457     p->numTestCases = testArray.size();
6458 
6459     // sort the collected records
6460     if(!testArray.empty()) {
6461         if(p->order_by.compare("file", true) == 0) {
6462             std::sort(testArray.begin(), testArray.end(), fileOrderComparator);
6463         } else if(p->order_by.compare("suite", true) == 0) {
6464             std::sort(testArray.begin(), testArray.end(), suiteOrderComparator);
6465         } else if(p->order_by.compare("name", true) == 0) {
6466             std::sort(testArray.begin(), testArray.end(), nameOrderComparator);
6467         } else if(p->order_by.compare("rand", true) == 0) {
6468             std::srand(p->rand_seed);
6469 
6470             // random_shuffle implementation
6471             const auto first = &testArray[0];
6472             for(size_t i = testArray.size() - 1; i > 0; --i) {
6473                 int idxToSwap = std::rand() % (i + 1); // NOLINT
6474 
6475                 const auto temp = first[i];
6476 
6477                 first[i]         = first[idxToSwap];
6478                 first[idxToSwap] = temp;
6479             }
6480         } else if(p->order_by.compare("none", true) == 0) {
6481             // means no sorting - beneficial for death tests which call into the executable
6482             // with a specific test case in mind - we don't want to slow down the startup times
6483         }
6484     }
6485 
6486     std::set<String> testSuitesPassingFilt;
6487 
6488     bool                             query_mode = p->count || p->list_test_cases || p->list_test_suites;
6489     std::vector<const TestCaseData*> queryResults;
6490 
6491     if(!query_mode)
6492         DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY);
6493 
6494     // invoke the registered functions if they match the filter criteria (or just count them)
6495     for(auto& curr : testArray) {
6496         const auto& tc = *curr;
6497 
6498         bool skip_me = false;
6499         if(tc.m_skip && !p->no_skip)
6500             skip_me = true;
6501 
6502         if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive))
6503             skip_me = true;
6504         if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive))
6505             skip_me = true;
6506         if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive))
6507             skip_me = true;
6508         if(matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive))
6509             skip_me = true;
6510         if(!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive))
6511             skip_me = true;
6512         if(matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive))
6513             skip_me = true;
6514 
6515         if(!skip_me)
6516             p->numTestCasesPassingFilters++;
6517 
6518         // skip the test if it is not in the execution range
6519         if((p->last < p->numTestCasesPassingFilters && p->first <= p->last) ||
6520            (p->first > p->numTestCasesPassingFilters))
6521             skip_me = true;
6522 
6523         if(skip_me) {
6524             if(!query_mode)
6525                 DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc);
6526             continue;
6527         }
6528 
6529         // do not execute the test if we are to only count the number of filter passing tests
6530         if(p->count)
6531             continue;
6532 
6533         // print the name of the test and don't execute it
6534         if(p->list_test_cases) {
6535             queryResults.push_back(&tc);
6536             continue;
6537         }
6538 
6539         // print the name of the test suite if not done already and don't execute it
6540         if(p->list_test_suites) {
6541             if((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') {
6542                 queryResults.push_back(&tc);
6543                 testSuitesPassingFilt.insert(tc.m_test_suite);
6544                 p->numTestSuitesPassingFilters++;
6545             }
6546             continue;
6547         }
6548 
6549         // execute the test if it passes all the filtering
6550         {
6551             p->currentTest = &tc;
6552 
6553             p->failure_flags = TestCaseFailureReason::None;
6554             p->seconds       = 0;
6555 
6556             // reset atomic counters
6557             p->numAssertsFailedCurrentTest_atomic = 0;
6558             p->numAssertsCurrentTest_atomic       = 0;
6559 
6560             p->subcasesPassed.clear();
6561 
6562             DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc);
6563 
6564             p->timer.start();
6565 
6566             bool run_test = true;
6567 
6568             do {
6569                 // reset some of the fields for subcases (except for the set of fully passed ones)
6570                 p->should_reenter          = false;
6571                 p->subcasesCurrentMaxLevel = 0;
6572                 p->subcasesStack.clear();
6573 
6574                 p->shouldLogCurrentException = true;
6575 
6576                 // reset stuff for logging with INFO()
6577                 p->stringifiedContexts.clear();
6578 
6579 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
6580                 try {
6581 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
6582 // MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method)
6583 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable
6584                     FatalConditionHandler fatalConditionHandler; // Handle signals
6585                     // execute the test
6586                     tc.m_test();
6587                     fatalConditionHandler.reset();
6588 DOCTEST_MSVC_SUPPRESS_WARNING_POP
6589 #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
6590                 } catch(const TestFailureException&) {
6591                     p->failure_flags |= TestCaseFailureReason::AssertFailure;
6592                 } catch(...) {
6593                     DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception,
6594                                                       {translateActiveException(), false});
6595                     p->failure_flags |= TestCaseFailureReason::Exception;
6596                 }
6597 #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
6598 
6599                 // exit this loop if enough assertions have failed - even if there are more subcases
6600                 if(p->abort_after > 0 &&
6601                    p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) {
6602                     run_test = false;
6603                     p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts;
6604                 }
6605 
6606                 if(p->should_reenter && run_test)
6607                     DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc);
6608                 if(!p->should_reenter)
6609                     run_test = false;
6610             } while(run_test);
6611 
6612             p->finalizeTestCaseData();
6613 
6614             DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs);
6615 
6616             p->currentTest = nullptr;
6617 
6618             // stop executing tests if enough assertions have failed
6619             if(p->abort_after > 0 && p->numAssertsFailed >= p->abort_after)
6620                 break;
6621         }
6622     }
6623 
6624     if(!query_mode) {
6625         DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs);
6626     } else {
6627         QueryData qdata;
6628         qdata.run_stats = g_cs;
6629         qdata.data      = queryResults.data();
6630         qdata.num_data  = unsigned(queryResults.size());
6631         DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata);
6632     }
6633 
6634     // see these issues on the reasoning for this:
6635     // - https://github.com/onqtam/doctest/issues/143#issuecomment-414418903
6636     // - https://github.com/onqtam/doctest/issues/126
6637     auto DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS = []() DOCTEST_NOINLINE
6638         { std::cout << std::string(); };
6639     DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS();
6640 
6641     return cleanup_and_return();
6642 }
6643 
6644 IReporter::~IReporter() = default;
6645 
6646 int IReporter::get_num_active_contexts() { return detail::wrapped_g_infoContexts.get().size(); }
6647 const IContextScope* const* IReporter::get_active_contexts() {
6648     return get_num_active_contexts() ? &detail::wrapped_g_infoContexts.get()[0] : nullptr;
6649 }
6650 
6651 int IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); }
6652 const String* IReporter::get_stringified_contexts() {
6653     return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr;
6654 }
6655 
6656 namespace detail {
6657     void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) {
6658         if(isReporter)
6659             getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c));
6660         else
6661             getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c));
6662     }
6663 } // namespace detail
6664 
6665 } // namespace doctest
6666 
6667 #endif // DOCTEST_CONFIG_DISABLE
6668 
6669 #ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
6670 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182
6671 int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); }
6672 DOCTEST_MSVC_SUPPRESS_WARNING_POP
6673 #endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
6674 
6675 DOCTEST_CLANG_SUPPRESS_WARNING_POP
6676 DOCTEST_MSVC_SUPPRESS_WARNING_POP
6677 DOCTEST_GCC_SUPPRESS_WARNING_POP
6678 
6679 #endif // DOCTEST_LIBRARY_IMPLEMENTATION
6680 #endif // DOCTEST_CONFIG_IMPLEMENT
6681