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