doctest: Update to 2.4.6

This commit is contained in:
Rémi Verschelde 2021-09-30 23:13:07 +02:00
parent 463dbe5210
commit 8d5475bd28
No known key found for this signature in database
GPG Key ID: C3336907360768E1
3 changed files with 387 additions and 191 deletions

View File

@ -143,7 +143,7 @@ License: Expat
Files: ./thirdparty/doctest/ Files: ./thirdparty/doctest/
Comment: doctest Comment: doctest
Copyright: 2016-2020, Viktor Kirilov Copyright: 2016-2021, Viktor Kirilov
License: Expat License: Expat
Files: ./thirdparty/embree/ Files: ./thirdparty/embree/

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016-2020 Viktor Kirilov Copyright (c) 2016-2021 Viktor Kirilov
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -4,7 +4,7 @@
// //
// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD // doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD
// //
// Copyright (c) 2016-2020 Viktor Kirilov // Copyright (c) 2016-2021 Viktor Kirilov
// //
// Distributed under the MIT Software License // Distributed under the MIT Software License
// See accompanying file LICENSE.txt or copy at // See accompanying file LICENSE.txt or copy at
@ -48,8 +48,8 @@
#define DOCTEST_VERSION_MAJOR 2 #define DOCTEST_VERSION_MAJOR 2
#define DOCTEST_VERSION_MINOR 4 #define DOCTEST_VERSION_MINOR 4
#define DOCTEST_VERSION_PATCH 4 #define DOCTEST_VERSION_PATCH 6
#define DOCTEST_VERSION_STR "2.4.4" #define DOCTEST_VERSION_STR "2.4.6"
#define DOCTEST_VERSION \ #define DOCTEST_VERSION \
(DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH)
@ -354,7 +354,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum'
#define DOCTEST_GLOBAL_NO_WARNINGS(var) \ #define DOCTEST_GLOBAL_NO_WARNINGS(var) \
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \ DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \
static int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp) static const int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp)
#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP #define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP
#ifndef DOCTEST_BREAK_INTO_DEBUGGER #ifndef DOCTEST_BREAK_INTO_DEBUGGER
@ -362,16 +362,16 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum'
#ifdef DOCTEST_PLATFORM_LINUX #ifdef DOCTEST_PLATFORM_LINUX
#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
// Break at the location of the failing check if possible // Break at the location of the failing check if possible
#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler)
#else #else
#include <signal.h> #include <signal.h>
#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP) #define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP)
#endif #endif
#elif defined(DOCTEST_PLATFORM_MAC) #elif defined(DOCTEST_PLATFORM_MAC)
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) #if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386)
#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler)
#else #else
#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT (hicpp-no-assembler)
#endif #endif
#elif DOCTEST_MSVC #elif DOCTEST_MSVC
#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() #define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak()
@ -656,12 +656,14 @@ DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file);
struct DOCTEST_INTERFACE TestCaseData struct DOCTEST_INTERFACE TestCaseData
{ {
String m_file; // the file in which the test was registered String m_file; // the file in which the test was registered (using String - see #350)
unsigned m_line; // the line where the test was registered unsigned m_line; // the line where the test was registered
const char* m_name; // name of the test case const char* m_name; // name of the test case
const char* m_test_suite; // the test suite in which the test was added const char* m_test_suite; // the test suite in which the test was added
const char* m_description; const char* m_description;
bool m_skip; bool m_skip;
bool m_no_breaks;
bool m_no_output;
bool m_may_fail; bool m_may_fail;
bool m_should_fail; bool m_should_fail;
int m_expected_failures; int m_expected_failures;
@ -715,12 +717,18 @@ struct DOCTEST_INTERFACE IContextScope
virtual void stringify(std::ostream*) const = 0; virtual void stringify(std::ostream*) const = 0;
}; };
namespace detail {
struct DOCTEST_INTERFACE TestCase;
} // namespace detail
struct ContextOptions //!OCLINT too many fields struct ContextOptions //!OCLINT too many fields
{ {
std::ostream* cout; // stdout stream - std::cout by default std::ostream* cout; // stdout stream - std::cout by default
std::ostream* cerr; // stderr stream - std::cerr by default std::ostream* cerr; // stderr stream - std::cerr by default
String binary_name; // the test binary name String binary_name; // the test binary name
const detail::TestCase* currentTest = nullptr;
// == parameters from the command line // == parameters from the command line
String out; // output filename String out; // output filename
String order_by; // how tests should be ordered String order_by; // how tests should be ordered
@ -773,6 +781,29 @@ namespace detail {
template<class T> struct remove_reference<T&> { typedef T type; }; template<class T> struct remove_reference<T&> { typedef T type; };
template<class T> struct remove_reference<T&&> { typedef T type; }; template<class T> struct remove_reference<T&&> { typedef T type; };
template<typename T, typename U = T&&> U declval(int);
template<typename T> T declval(long);
template<typename T> auto declval() DOCTEST_NOEXCEPT -> decltype(declval<T>(0)) ;
template<class T> struct is_lvalue_reference { const static bool value=false; };
template<class T> struct is_lvalue_reference<T&> { const static bool value=true; };
template <class T>
inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT
{
return static_cast<T&&>(t);
}
template <class T>
inline T&& forward(typename remove_reference<T>::type&& t) DOCTEST_NOEXCEPT
{
static_assert(!is_lvalue_reference<T>::value,
"Can not forward an rvalue as an lvalue.");
return static_cast<T&&>(t);
}
template<class T> struct remove_const { typedef T type; }; template<class T> struct remove_const { typedef T type; };
template<class T> struct remove_const<const T> { typedef T type; }; template<class T> struct remove_const<const T> { typedef T type; };
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS #ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
@ -1040,10 +1071,20 @@ namespace detail {
return toString(lhs) + op + toString(rhs); return toString(lhs) + op + toString(rhs);
} }
#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
#endif
// This will check if there is any way it could find a operator like member or friend and uses it.
// If not it doesn't find the operator or if the operator at global scope is defined after
// this template, the template won't be instantiated due to SFINAE. Once the template is not
// instantiated it can look for global operator using normal conversions.
#define SFINAE_OP(ret,op) decltype(doctest::detail::declval<L>() op doctest::detail::declval<R>(),static_cast<ret>(0))
#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ #define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \
template <typename R> \ template <typename R> \
DOCTEST_NOINLINE Result operator op(const DOCTEST_REF_WRAP(R) rhs) { \ DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& rhs) { \
bool res = op_macro(lhs, rhs); \ bool res = op_macro(doctest::detail::forward<L>(lhs), doctest::detail::forward<R>(rhs)); \
if(m_at & assertType::is_false) \ if(m_at & assertType::is_false) \
res = !res; \ res = !res; \
if(!res || doctest::getContextOptions()->success) \ if(!res || doctest::getContextOptions()->success) \
@ -1171,12 +1212,16 @@ namespace detail {
L lhs; L lhs;
assertType::Enum m_at; assertType::Enum m_at;
explicit Expression_lhs(L in, assertType::Enum at) explicit Expression_lhs(L&& in, assertType::Enum at)
: lhs(in) : lhs(doctest::detail::forward<L>(in))
, m_at(at) {} , m_at(at) {}
DOCTEST_NOINLINE operator Result() { DOCTEST_NOINLINE operator Result() {
bool res = !!lhs; // this is needed only foc MSVC 2015:
// https://ci.appveyor.com/project/onqtam/doctest/builds/38181202
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool
bool res = static_cast<bool>(lhs);
DOCTEST_MSVC_SUPPRESS_WARNING_POP
if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional
res = !res; res = !res;
@ -1185,6 +1230,10 @@ namespace detail {
return Result(res); return Result(res);
} }
/* This is required for user-defined conversions from Expression_lhs to L */
//operator L() const { return lhs; }
operator L() const { return lhs; }
// clang-format off // clang-format off
DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional
DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional
@ -1225,6 +1274,10 @@ namespace detail {
#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION #endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION
#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)
DOCTEST_CLANG_SUPPRESS_WARNING_POP
#endif
struct DOCTEST_INTERFACE ExpressionDecomposer struct DOCTEST_INTERFACE ExpressionDecomposer
{ {
assertType::Enum m_at; assertType::Enum m_at;
@ -1236,8 +1289,8 @@ namespace detail {
// https://github.com/catchorg/Catch2/issues/870 // https://github.com/catchorg/Catch2/issues/870
// https://github.com/catchorg/Catch2/issues/565 // https://github.com/catchorg/Catch2/issues/565
template <typename L> template <typename L>
Expression_lhs<const DOCTEST_REF_WRAP(L)> operator<<(const DOCTEST_REF_WRAP(L) operand) { Expression_lhs<L> operator<<(L &&operand) {
return Expression_lhs<const DOCTEST_REF_WRAP(L)>(operand, m_at); return Expression_lhs<L>(doctest::detail::forward<L>(operand), m_at);
} }
}; };
@ -1246,6 +1299,8 @@ namespace detail {
const char* m_test_suite; const char* m_test_suite;
const char* m_description; const char* m_description;
bool m_skip; bool m_skip;
bool m_no_breaks;
bool m_no_output;
bool m_may_fail; bool m_may_fail;
bool m_should_fail; bool m_should_fail;
int m_expected_failures; int m_expected_failures;
@ -1524,7 +1579,7 @@ namespace detail {
template <typename L> class ContextScope : public ContextScopeBase template <typename L> class ContextScope : public ContextScopeBase
{ {
const L &lambda_; const L lambda_;
public: public:
explicit ContextScope(const L &lambda) : lambda_(lambda) {} explicit ContextScope(const L &lambda) : lambda_(lambda) {}
@ -1585,6 +1640,8 @@ namespace detail {
DOCTEST_DEFINE_DECORATOR(test_suite, const char*, ""); DOCTEST_DEFINE_DECORATOR(test_suite, const char*, "");
DOCTEST_DEFINE_DECORATOR(description, const char*, ""); DOCTEST_DEFINE_DECORATOR(description, const char*, "");
DOCTEST_DEFINE_DECORATOR(skip, bool, true); DOCTEST_DEFINE_DECORATOR(skip, bool, true);
DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true);
DOCTEST_DEFINE_DECORATOR(no_output, bool, true);
DOCTEST_DEFINE_DECORATOR(timeout, double, 0); DOCTEST_DEFINE_DECORATOR(timeout, double, 0);
DOCTEST_DEFINE_DECORATOR(may_fail, bool, true); DOCTEST_DEFINE_DECORATOR(may_fail, bool, true);
DOCTEST_DEFINE_DECORATOR(should_fail, bool, true); DOCTEST_DEFINE_DECORATOR(should_fail, bool, true);
@ -1921,10 +1978,12 @@ int registerReporter(const char* name, int priority, bool isReporter) {
static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \ static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \ DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \
static doctest::detail::TestSuite data; \ DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers") \
static doctest::detail::TestSuite data{}; \
static bool inited = false; \ static bool inited = false; \
DOCTEST_MSVC_SUPPRESS_WARNING_POP \ DOCTEST_MSVC_SUPPRESS_WARNING_POP \
DOCTEST_CLANG_SUPPRESS_WARNING_POP \ DOCTEST_CLANG_SUPPRESS_WARNING_POP \
DOCTEST_GCC_SUPPRESS_WARNING_POP \
if(!inited) { \ if(!inited) { \
data* decorators; \ data* decorators; \
inited = true; \ inited = true; \
@ -1979,17 +2038,15 @@ int registerReporter(const char* name, int priority, bool isReporter) {
// for logging // for logging
#define DOCTEST_INFO(...) \ #define DOCTEST_INFO(...) \
DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \ DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \
DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), __VA_ARGS__) __VA_ARGS__)
#define DOCTEST_INFO_IMPL(lambda_name, mb_name, s_name, ...) \ #define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \ auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \
auto lambda_name = [&](std::ostream* s_name) { \ [&](std::ostream* s_name) { \
doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \
mb_name.m_stream = s_name; \ mb_name.m_stream = s_name; \
mb_name * __VA_ARGS__; \ mb_name * __VA_ARGS__; \
}; \ })
DOCTEST_MSVC_SUPPRESS_WARNING_POP \
auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope(lambda_name)
#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x) #define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x)
@ -2461,7 +2518,7 @@ int registerReporter(const char* name, int priority, bool isReporter) {
#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE #define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE
#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE #define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE
#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INVOKE #define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__)
// clang-format on // clang-format on
// BDD style macros // BDD style macros
@ -2481,138 +2538,138 @@ int registerReporter(const char* name, int priority, bool isReporter) {
// == SHORT VERSIONS OF THE MACROS // == SHORT VERSIONS OF THE MACROS
#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) #if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES)
#define TEST_CASE DOCTEST_TEST_CASE #define TEST_CASE(name) DOCTEST_TEST_CASE(name)
#define TEST_CASE_CLASS DOCTEST_TEST_CASE_CLASS #define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name)
#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE #define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name)
#define TYPE_TO_STRING DOCTEST_TYPE_TO_STRING #define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__)
#define TEST_CASE_TEMPLATE DOCTEST_TEST_CASE_TEMPLATE #define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__)
#define TEST_CASE_TEMPLATE_DEFINE DOCTEST_TEST_CASE_TEMPLATE_DEFINE #define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id)
#define TEST_CASE_TEMPLATE_INVOKE DOCTEST_TEST_CASE_TEMPLATE_INVOKE #define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__)
#define TEST_CASE_TEMPLATE_APPLY DOCTEST_TEST_CASE_TEMPLATE_APPLY #define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__)
#define SUBCASE DOCTEST_SUBCASE #define SUBCASE(name) DOCTEST_SUBCASE(name)
#define TEST_SUITE DOCTEST_TEST_SUITE #define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators)
#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN #define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name)
#define TEST_SUITE_END DOCTEST_TEST_SUITE_END #define TEST_SUITE_END DOCTEST_TEST_SUITE_END
#define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR #define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)
#define REGISTER_REPORTER DOCTEST_REGISTER_REPORTER #define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter)
#define REGISTER_LISTENER DOCTEST_REGISTER_LISTENER #define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter)
#define INFO DOCTEST_INFO #define INFO(...) DOCTEST_INFO(__VA_ARGS__)
#define CAPTURE DOCTEST_CAPTURE #define CAPTURE(x) DOCTEST_CAPTURE(x)
#define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT #define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__)
#define ADD_FAIL_CHECK_AT DOCTEST_ADD_FAIL_CHECK_AT #define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__)
#define ADD_FAIL_AT DOCTEST_ADD_FAIL_AT #define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__)
#define MESSAGE DOCTEST_MESSAGE #define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__)
#define FAIL_CHECK DOCTEST_FAIL_CHECK #define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__)
#define FAIL DOCTEST_FAIL #define FAIL(...) DOCTEST_FAIL(__VA_ARGS__)
#define TO_LVALUE DOCTEST_TO_LVALUE #define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__)
#define WARN DOCTEST_WARN #define WARN(...) DOCTEST_WARN(__VA_ARGS__)
#define WARN_FALSE DOCTEST_WARN_FALSE #define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__)
#define WARN_THROWS DOCTEST_WARN_THROWS #define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__)
#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS #define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__)
#define WARN_THROWS_WITH DOCTEST_WARN_THROWS_WITH #define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__)
#define WARN_THROWS_WITH_AS DOCTEST_WARN_THROWS_WITH_AS #define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__)
#define WARN_NOTHROW DOCTEST_WARN_NOTHROW #define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__)
#define CHECK DOCTEST_CHECK #define CHECK(...) DOCTEST_CHECK(__VA_ARGS__)
#define CHECK_FALSE DOCTEST_CHECK_FALSE #define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__)
#define CHECK_THROWS DOCTEST_CHECK_THROWS #define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__)
#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS #define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__)
#define CHECK_THROWS_WITH DOCTEST_CHECK_THROWS_WITH #define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__)
#define CHECK_THROWS_WITH_AS DOCTEST_CHECK_THROWS_WITH_AS #define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__)
#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW #define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__)
#define REQUIRE DOCTEST_REQUIRE #define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__)
#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE #define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__)
#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS #define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__)
#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS #define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__)
#define REQUIRE_THROWS_WITH DOCTEST_REQUIRE_THROWS_WITH #define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__)
#define REQUIRE_THROWS_WITH_AS DOCTEST_REQUIRE_THROWS_WITH_AS #define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__)
#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW #define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__)
#define WARN_MESSAGE DOCTEST_WARN_MESSAGE #define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__)
#define WARN_FALSE_MESSAGE DOCTEST_WARN_FALSE_MESSAGE #define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__)
#define WARN_THROWS_MESSAGE DOCTEST_WARN_THROWS_MESSAGE #define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__)
#define WARN_THROWS_AS_MESSAGE DOCTEST_WARN_THROWS_AS_MESSAGE #define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
#define WARN_THROWS_WITH_MESSAGE DOCTEST_WARN_THROWS_WITH_MESSAGE #define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
#define WARN_THROWS_WITH_AS_MESSAGE DOCTEST_WARN_THROWS_WITH_AS_MESSAGE #define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
#define WARN_NOTHROW_MESSAGE DOCTEST_WARN_NOTHROW_MESSAGE #define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__)
#define CHECK_MESSAGE DOCTEST_CHECK_MESSAGE #define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__)
#define CHECK_FALSE_MESSAGE DOCTEST_CHECK_FALSE_MESSAGE #define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__)
#define CHECK_THROWS_MESSAGE DOCTEST_CHECK_THROWS_MESSAGE #define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__)
#define CHECK_THROWS_AS_MESSAGE DOCTEST_CHECK_THROWS_AS_MESSAGE #define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
#define CHECK_THROWS_WITH_MESSAGE DOCTEST_CHECK_THROWS_WITH_MESSAGE #define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
#define CHECK_THROWS_WITH_AS_MESSAGE DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE #define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
#define CHECK_NOTHROW_MESSAGE DOCTEST_CHECK_NOTHROW_MESSAGE #define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__)
#define REQUIRE_MESSAGE DOCTEST_REQUIRE_MESSAGE #define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__)
#define REQUIRE_FALSE_MESSAGE DOCTEST_REQUIRE_FALSE_MESSAGE #define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__)
#define REQUIRE_THROWS_MESSAGE DOCTEST_REQUIRE_THROWS_MESSAGE #define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__)
#define REQUIRE_THROWS_AS_MESSAGE DOCTEST_REQUIRE_THROWS_AS_MESSAGE #define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
#define REQUIRE_THROWS_WITH_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_MESSAGE #define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
#define REQUIRE_THROWS_WITH_AS_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE #define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
#define REQUIRE_NOTHROW_MESSAGE DOCTEST_REQUIRE_NOTHROW_MESSAGE #define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__)
#define SCENARIO DOCTEST_SCENARIO #define SCENARIO(name) DOCTEST_SCENARIO(name)
#define SCENARIO_CLASS DOCTEST_SCENARIO_CLASS #define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name)
#define SCENARIO_TEMPLATE DOCTEST_SCENARIO_TEMPLATE #define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__)
#define SCENARIO_TEMPLATE_DEFINE DOCTEST_SCENARIO_TEMPLATE_DEFINE #define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id)
#define GIVEN DOCTEST_GIVEN #define GIVEN(name) DOCTEST_GIVEN(name)
#define WHEN DOCTEST_WHEN #define WHEN(name) DOCTEST_WHEN(name)
#define AND_WHEN DOCTEST_AND_WHEN #define AND_WHEN(name) DOCTEST_AND_WHEN(name)
#define THEN DOCTEST_THEN #define THEN(name) DOCTEST_THEN(name)
#define AND_THEN DOCTEST_AND_THEN #define AND_THEN(name) DOCTEST_AND_THEN(name)
#define WARN_EQ DOCTEST_WARN_EQ #define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__)
#define CHECK_EQ DOCTEST_CHECK_EQ #define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__)
#define REQUIRE_EQ DOCTEST_REQUIRE_EQ #define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__)
#define WARN_NE DOCTEST_WARN_NE #define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__)
#define CHECK_NE DOCTEST_CHECK_NE #define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__)
#define REQUIRE_NE DOCTEST_REQUIRE_NE #define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__)
#define WARN_GT DOCTEST_WARN_GT #define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__)
#define CHECK_GT DOCTEST_CHECK_GT #define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__)
#define REQUIRE_GT DOCTEST_REQUIRE_GT #define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__)
#define WARN_LT DOCTEST_WARN_LT #define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__)
#define CHECK_LT DOCTEST_CHECK_LT #define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__)
#define REQUIRE_LT DOCTEST_REQUIRE_LT #define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__)
#define WARN_GE DOCTEST_WARN_GE #define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__)
#define CHECK_GE DOCTEST_CHECK_GE #define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__)
#define REQUIRE_GE DOCTEST_REQUIRE_GE #define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__)
#define WARN_LE DOCTEST_WARN_LE #define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__)
#define CHECK_LE DOCTEST_CHECK_LE #define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__)
#define REQUIRE_LE DOCTEST_REQUIRE_LE #define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__)
#define WARN_UNARY DOCTEST_WARN_UNARY #define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__)
#define CHECK_UNARY DOCTEST_CHECK_UNARY #define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__)
#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY #define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__)
#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE #define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__)
#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE #define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__)
#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE #define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__)
// KEPT FOR BACKWARDS COMPATIBILITY // KEPT FOR BACKWARDS COMPATIBILITY
#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ #define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__)
#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ #define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__)
#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ #define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__)
#define FAST_WARN_NE DOCTEST_FAST_WARN_NE #define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__)
#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE #define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__)
#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE #define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__)
#define FAST_WARN_GT DOCTEST_FAST_WARN_GT #define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__)
#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT #define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__)
#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT #define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__)
#define FAST_WARN_LT DOCTEST_FAST_WARN_LT #define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__)
#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT #define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__)
#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT #define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__)
#define FAST_WARN_GE DOCTEST_FAST_WARN_GE #define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__)
#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE #define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__)
#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE #define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__)
#define FAST_WARN_LE DOCTEST_FAST_WARN_LE #define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__)
#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE #define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__)
#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE #define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__)
#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY #define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__)
#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY #define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__)
#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY #define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__)
#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE #define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__)
#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE #define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__)
#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE #define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__)
#define TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE #define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__)
#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES #endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES
@ -2689,6 +2746,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function") DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path")
DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING_PUSH
DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas")
@ -2794,11 +2852,7 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
#ifdef __AFXDLL #ifdef __AFXDLL
#include <AfxWin.h> #include <AfxWin.h>
#else #else
#if defined(__MINGW32__) || defined(__MINGW64__)
#include <windows.h> #include <windows.h>
#else // MINGW
#include <Windows.h>
#endif // MINGW
#endif #endif
#include <io.h> #include <io.h>
@ -2834,12 +2888,24 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
#define DOCTEST_THREAD_LOCAL thread_local #define DOCTEST_THREAD_LOCAL thread_local
#endif #endif
#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES
#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32
#endif
#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE
#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64
#endif
#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS #ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX #define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX
#else #else
#define DOCTEST_OPTIONS_PREFIX_DISPLAY "" #define DOCTEST_OPTIONS_PREFIX_DISPLAY ""
#endif #endif
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
#endif
namespace doctest { namespace doctest {
bool is_running_in_test = false; bool is_running_in_test = false;
@ -2972,18 +3038,105 @@ typedef timer_large_integer::type ticks_t;
ticks_t m_ticks = 0; ticks_t m_ticks = 0;
}; };
#ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
template <typename T>
using AtomicOrMultiLaneAtomic = std::atomic<T>;
#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
// Provides a multilane implementation of an atomic variable that supports add, sub, load,
// store. Instead of using a single atomic variable, this splits up into multiple ones,
// each sitting on a separate cache line. The goal is to provide a speedup when most
// operations are modifying. It achieves this with two properties:
//
// * Multiple atomics are used, so chance of congestion from the same atomic is reduced.
// * Each atomic sits on a separate cache line, so false sharing is reduced.
//
// The disadvantage is that there is a small overhead due to the use of TLS, and load/store
// is slower because all atomics have to be accessed.
template <typename T>
class MultiLaneAtomic
{
struct CacheLineAlignedAtomic
{
std::atomic<T> atomic{};
char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)];
};
CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES];
static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE,
"guarantee one atomic takes exactly one cache line");
public:
T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; }
T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); }
T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
return myAtomic().fetch_add(arg, order);
}
T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
return myAtomic().fetch_sub(arg, order);
}
operator T() const DOCTEST_NOEXCEPT { return load(); }
T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT {
auto result = T();
for(auto const& c : m_atomics) {
result += c.atomic.load(order);
}
return result;
}
T operator=(T desired) DOCTEST_NOEXCEPT {
store(desired);
return desired;
}
void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
// first value becomes desired", all others become 0.
for(auto& c : m_atomics) {
c.atomic.store(desired, order);
desired = {};
}
}
private:
// Each thread has a different atomic that it operates on. If more than NumLanes threads
// use this, some will use the same atomic. So performance will degrate a bit, but still
// everything will work.
//
// The logic here is a bit tricky. The call should be as fast as possible, so that there
// is minimal to no overhead in determining the correct atomic for the current thread.
//
// 1. A global static counter laneCounter counts continuously up.
// 2. Each successive thread will use modulo operation of that counter so it gets an atomic
// assigned in a round-robin fashion.
// 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with
// little overhead.
std::atomic<T>& myAtomic() DOCTEST_NOEXCEPT {
static std::atomic<size_t> laneCounter;
DOCTEST_THREAD_LOCAL size_t tlsLaneIdx =
laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES;
return m_atomics[tlsLaneIdx].atomic;
}
};
template <typename T>
using AtomicOrMultiLaneAtomic = MultiLaneAtomic<T>;
#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
// this holds both parameters from the command line and runtime data for tests // this holds both parameters from the command line and runtime data for tests
struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats
{ {
std::atomic<int> numAssertsCurrentTest_atomic; AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic;
std::atomic<int> numAssertsFailedCurrentTest_atomic; AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters
std::vector<IReporter*> reporters_currently_used; std::vector<IReporter*> reporters_currently_used;
const TestCase* currentTest = nullptr;
assert_handler ah = nullptr; assert_handler ah = nullptr;
Timer timer; Timer timer;
@ -3093,14 +3246,16 @@ String::String(const char* in)
String::String(const char* in, unsigned in_size) { String::String(const char* in, unsigned in_size) {
using namespace std; using namespace std;
if(in_size <= last) { if(in_size <= last) {
memcpy(buf, in, in_size + 1); memcpy(buf, in, in_size);
buf[in_size] = '\0';
setLast(last - in_size); setLast(last - in_size);
} else { } else {
setOnHeap(); setOnHeap();
data.size = in_size; data.size = in_size;
data.capacity = data.size + 1; data.capacity = data.size + 1;
data.ptr = new char[data.capacity]; data.ptr = new char[data.capacity];
memcpy(data.ptr, in, in_size + 1); memcpy(data.ptr, in, in_size);
data.ptr[in_size] = '\0';
} }
} }
@ -3471,7 +3626,7 @@ int registerReporter(const char*, int, IReporter*) { return 0; }
namespace doctest_detail_test_suite_ns { namespace doctest_detail_test_suite_ns {
// holds the current test suite // holds the current test suite
doctest::detail::TestSuite& getCurrentTestSuite() { doctest::detail::TestSuite& getCurrentTestSuite() {
static doctest::detail::TestSuite data; static doctest::detail::TestSuite data{};
return data; return data;
} }
} // namespace doctest_detail_test_suite_ns } // namespace doctest_detail_test_suite_ns
@ -3583,7 +3738,7 @@ namespace detail {
Subcase::Subcase(const String& name, const char* file, int line) Subcase::Subcase(const String& name, const char* file, int line)
: m_signature({name, file, line}) { : m_signature({name, file, line}) {
ContextState* s = g_cs; auto* s = g_cs;
// check subcase filters // check subcase filters
if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) { if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) {
@ -3625,7 +3780,7 @@ namespace detail {
g_cs->subcasesPassed.insert(g_cs->subcasesStack); g_cs->subcasesPassed.insert(g_cs->subcasesStack);
g_cs->subcasesStack.pop_back(); g_cs->subcasesStack.pop_back();
#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L #if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
if(std::uncaught_exceptions() > 0 if(std::uncaught_exceptions() > 0
#else #else
if(std::uncaught_exception() if(std::uncaught_exception()
@ -3660,6 +3815,8 @@ namespace detail {
// clear state // clear state
m_description = nullptr; m_description = nullptr;
m_skip = false; m_skip = false;
m_no_breaks = false;
m_no_output = false;
m_may_fail = false; m_may_fail = false;
m_should_fail = false; m_should_fail = false;
m_expected_failures = 0; m_expected_failures = 0;
@ -3675,6 +3832,8 @@ namespace detail {
m_test_suite = test_suite.m_test_suite; m_test_suite = test_suite.m_test_suite;
m_description = test_suite.m_description; m_description = test_suite.m_description;
m_skip = test_suite.m_skip; m_skip = test_suite.m_skip;
m_no_breaks = test_suite.m_no_breaks;
m_no_output = test_suite.m_no_output;
m_may_fail = test_suite.m_may_fail; m_may_fail = test_suite.m_may_fail;
m_should_fail = test_suite.m_should_fail; m_should_fail = test_suite.m_should_fail;
m_expected_failures = test_suite.m_expected_failures; m_expected_failures = test_suite.m_expected_failures;
@ -3721,14 +3880,20 @@ namespace detail {
// this will be used only to differentiate between test cases - not relevant for sorting // this will be used only to differentiate between test cases - not relevant for sorting
if(m_line != other.m_line) if(m_line != other.m_line)
return m_line < other.m_line; return m_line < other.m_line;
const int file_cmp = m_file.compare(other.m_file);
if(file_cmp != 0)
return file_cmp < 0;
const int name_cmp = strcmp(m_name, other.m_name); const int name_cmp = strcmp(m_name, other.m_name);
if(name_cmp != 0) if(name_cmp != 0)
return name_cmp < 0; return name_cmp < 0;
const int file_cmp = m_file.compare(other.m_file);
if(file_cmp != 0)
return file_cmp < 0;
return m_template_id < other.m_template_id; return m_template_id < other.m_template_id;
} }
// all the registered tests
std::set<TestCase>& getRegisteredTests() {
static std::set<TestCase> data;
return data;
}
} // namespace detail } // namespace detail
namespace { namespace {
using namespace detail; using namespace detail;
@ -3760,12 +3925,6 @@ namespace {
return suiteOrderComparator(lhs, rhs); return suiteOrderComparator(lhs, rhs);
} }
// all the registered tests
std::set<TestCase>& getRegisteredTests() {
static std::set<TestCase> data;
return data;
}
#ifdef DOCTEST_CONFIG_COLORS_WINDOWS #ifdef DOCTEST_CONFIG_COLORS_WINDOWS
HANDLE g_stdoutHandle; HANDLE g_stdoutHandle;
WORD g_origFgAttrs; WORD g_origFgAttrs;
@ -3994,7 +4153,7 @@ namespace detail {
// ContextScope has been destroyed (base class destructors run after derived class destructors). // ContextScope has been destroyed (base class destructors run after derived class destructors).
// Instead, ContextScope calls this method directly from its destructor. // Instead, ContextScope calls this method directly from its destructor.
void ContextScopeBase::destroy() { void ContextScopeBase::destroy() {
#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L #if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
if(std::uncaught_exceptions() > 0) { if(std::uncaught_exceptions() > 0) {
#else #else
if(std::uncaught_exception()) { if(std::uncaught_exception()) {
@ -4016,7 +4175,9 @@ namespace {
#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) #if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH)
struct FatalConditionHandler struct FatalConditionHandler
{ {
void reset() {} static void reset() {}
static void allocateAltStackMem() {}
static void freeAltStackMem() {}
}; };
#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH #else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
@ -4069,6 +4230,9 @@ namespace {
std::exit(EXIT_FAILURE); std::exit(EXIT_FAILURE);
} }
static void allocateAltStackMem() {}
static void freeAltStackMem() {}
FatalConditionHandler() { FatalConditionHandler() {
isSet = true; isSet = true;
// 32k seems enough for doctest to handle stack overflow, // 32k seems enough for doctest to handle stack overflow,
@ -4086,7 +4250,7 @@ namespace {
// - std::terminate is called FROM THE TEST RUNNER THREAD // - std::terminate is called FROM THE TEST RUNNER THREAD
// - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD
original_terminate_handler = std::get_terminate(); original_terminate_handler = std::get_terminate();
std::set_terminate([]() noexcept { std::set_terminate([]() DOCTEST_NOEXCEPT {
reportFatal("Terminate handler called"); reportFatal("Terminate handler called");
if(isDebuggerActive() && !g_cs->no_breaks) if(isDebuggerActive() && !g_cs->no_breaks)
DOCTEST_BREAK_INTO_DEBUGGER(); DOCTEST_BREAK_INTO_DEBUGGER();
@ -4097,7 +4261,7 @@ namespace {
// - std::terminate is called FROM A DIFFERENT THREAD // - std::terminate is called FROM A DIFFERENT THREAD
// - an exception is thrown from a destructor FROM A DIFFERENT THREAD // - an exception is thrown from a destructor FROM A DIFFERENT THREAD
// - an uncaught exception is thrown FROM A DIFFERENT THREAD // - an uncaught exception is thrown FROM A DIFFERENT THREAD
prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) noexcept { prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT {
if(signal == SIGABRT) { if(signal == SIGABRT) {
reportFatal("SIGABRT - Abort (abnormal termination) signal"); reportFatal("SIGABRT - Abort (abnormal termination) signal");
if(isDebuggerActive() && !g_cs->no_breaks) if(isDebuggerActive() && !g_cs->no_breaks)
@ -4135,8 +4299,8 @@ namespace {
SetErrorMode(prev_error_mode_1); SetErrorMode(prev_error_mode_1);
_set_error_mode(prev_error_mode_2); _set_error_mode(prev_error_mode_2);
_set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
_CrtSetReportMode(_CRT_ASSERT, prev_report_mode); static_cast<void>(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode));
_CrtSetReportFile(_CRT_ASSERT, prev_report_file); static_cast<void>(_CrtSetReportFile(_CRT_ASSERT, prev_report_file));
isSet = false; isSet = false;
} }
} }
@ -4186,7 +4350,8 @@ namespace {
static bool isSet; static bool isSet;
static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)];
static stack_t oldSigStack; static stack_t oldSigStack;
static char altStackMem[4 * SIGSTKSZ]; static size_t altStackSize;
static char* altStackMem;
static void handleSignal(int sig) { static void handleSignal(int sig) {
const char* name = "<unknown signal>"; const char* name = "<unknown signal>";
@ -4202,11 +4367,19 @@ namespace {
raise(sig); raise(sig);
} }
static void allocateAltStackMem() {
altStackMem = new char[altStackSize];
}
static void freeAltStackMem() {
delete[] altStackMem;
}
FatalConditionHandler() { FatalConditionHandler() {
isSet = true; isSet = true;
stack_t sigStack; stack_t sigStack;
sigStack.ss_sp = altStackMem; sigStack.ss_sp = altStackMem;
sigStack.ss_size = sizeof(altStackMem); sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0; sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack); sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = {}; struct sigaction sa = {};
@ -4231,10 +4404,11 @@ namespace {
} }
}; };
bool FatalConditionHandler::isSet = false; bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {};
stack_t FatalConditionHandler::oldSigStack = {}; stack_t FatalConditionHandler::oldSigStack = {};
char FatalConditionHandler::altStackMem[] = {}; size_t FatalConditionHandler::altStackSize = 4 * SIGSTKSZ;
char* FatalConditionHandler::altStackMem = nullptr;
#endif // DOCTEST_PLATFORM_WINDOWS #endif // DOCTEST_PLATFORM_WINDOWS
#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH #endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
@ -4336,8 +4510,8 @@ namespace detail {
failed_out_of_a_testing_context(*this); failed_out_of_a_testing_context(*this);
} }
return m_failed && isDebuggerActive() && return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks &&
!getContextOptions()->no_breaks; // break into debugger (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
} }
void ResultBuilder::react() const { void ResultBuilder::react() const {
@ -4387,7 +4561,8 @@ namespace detail {
addFailedAssert(m_severity); addFailedAssert(m_severity);
} }
return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn; // break return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn &&
(g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
} }
void MessageBuilder::react() { void MessageBuilder::react() {
@ -5495,7 +5670,7 @@ namespace {
<< Whitespace(sizePrefixDisplay*1) << "output filename\n"; << Whitespace(sizePrefixDisplay*1) << "output filename\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by=<string> " s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by=<string> "
<< Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n"; << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n";
s << Whitespace(sizePrefixDisplay*3) << " <string> - by [file/suite/name/rand]\n"; s << Whitespace(sizePrefixDisplay*3) << " <string> - [file/suite/name/rand/none]\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed=<int> " s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed=<int> "
<< Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n"; << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first=<int> " s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first=<int> "
@ -5668,6 +5843,9 @@ namespace {
} }
void test_case_end(const CurrentTestCaseStats& st) override { void test_case_end(const CurrentTestCaseStats& st) override {
if(tc->m_no_output)
return;
// log the preamble of the test case only if there is something // log the preamble of the test case only if there is something
// else to print - something other than that an assert has failed // else to print - something other than that an assert has failed
if(opt.duration || if(opt.duration ||
@ -5702,6 +5880,9 @@ namespace {
} }
void test_case_exception(const TestCaseException& e) override { void test_case_exception(const TestCaseException& e) override {
if(tc->m_no_output)
return;
logTestStart(); logTestStart();
file_line_to_stream(tc->m_file.c_str(), tc->m_line, " "); file_line_to_stream(tc->m_file.c_str(), tc->m_line, " ");
@ -5736,7 +5917,7 @@ namespace {
} }
void log_assert(const AssertData& rb) override { void log_assert(const AssertData& rb) override {
if(!rb.m_failed && !opt.success) if((!rb.m_failed && !opt.success) || tc->m_no_output)
return; return;
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
@ -5752,6 +5933,9 @@ namespace {
} }
void log_message(const MessageData& mb) override { void log_message(const MessageData& mb) override {
if(tc->m_no_output)
return;
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
logTestStart(); logTestStart();
@ -5782,8 +5966,10 @@ namespace {
bool with_col = g_no_colors; \ bool with_col = g_no_colors; \
g_no_colors = false; \ g_no_colors = false; \
ConsoleReporter::func(arg); \ ConsoleReporter::func(arg); \
DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ if(oss.tellp() != std::streampos{}) { \
oss.str(""); \ DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \
oss.str(""); \
} \
g_no_colors = with_col; \ g_no_colors = with_col; \
} }
@ -5970,7 +6156,7 @@ void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) {
#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ #define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \
if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \ if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \
parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \ parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \
p->var = !!intRes; \ p->var = static_cast<bool>(intRes); \
else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \ else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \
parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \ parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \
p->var = true; \ p->var = true; \
@ -6115,7 +6301,11 @@ int Context::run() {
p->cout = &fstr; p->cout = &fstr;
} }
FatalConditionHandler::allocateAltStackMem();
auto cleanup_and_return = [&]() { auto cleanup_and_return = [&]() {
FatalConditionHandler::freeAltStackMem();
if(fstr.is_open()) if(fstr.is_open())
fstr.close(); fstr.close();
@ -6187,6 +6377,9 @@ int Context::run() {
first[i] = first[idxToSwap]; first[i] = first[idxToSwap];
first[idxToSwap] = temp; first[idxToSwap] = temp;
} }
} else if(p->order_by.compare("none", true) == 0) {
// means no sorting - beneficial for death tests which call into the executable
// with a specific test case in mind - we don't want to slow down the startup times
} }
} }
@ -6286,10 +6479,13 @@ int Context::run() {
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
try { try {
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
// MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method)
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable
FatalConditionHandler fatalConditionHandler; // Handle signals FatalConditionHandler fatalConditionHandler; // Handle signals
// execute the test // execute the test
tc.m_test(); tc.m_test();
fatalConditionHandler.reset(); fatalConditionHandler.reset();
DOCTEST_MSVC_SUPPRESS_WARNING_POP
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
} catch(const TestFailureException&) { } catch(const TestFailureException&) {
p->failure_flags |= TestCaseFailureReason::AssertFailure; p->failure_flags |= TestCaseFailureReason::AssertFailure;