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