Browse Source

[Minor] Update bundled doctest to the latest version

tags/3.1
Vsevolod Stakhov 2 years ago
parent
commit
4dcee38fd3

+ 2
- 2
contrib/doctest/CMakeLists.txt View File

## DOCTEST ## DOCTEST
################################################################################ ################################################################################


project(doctest VERSION 2.4.5 LANGUAGES CXX)
project(doctest VERSION 2.4.6 LANGUAGES CXX)


# Determine if doctest is built as a subproject (using add_subdirectory) or if it is the main project. # Determine if doctest is built as a subproject (using add_subdirectory) or if it is the main project.
set(MAIN_PROJECT OFF) set(MAIN_PROJECT OFF)


if(DOCTEST_USE_STD_HEADERS) if(DOCTEST_USE_STD_HEADERS)
target_compile_definitions(${PROJECT_NAME} INTERFACE DOCTEST_CONFIG_USE_STD_HEADERS) target_compile_definitions(${PROJECT_NAME} INTERFACE DOCTEST_CONFIG_USE_STD_HEADERS)
endif()
endif()

+ 120
- 47
contrib/doctest/doctest/doctest.h View File



#define DOCTEST_VERSION_MAJOR 2 #define DOCTEST_VERSION_MAJOR 2
#define DOCTEST_VERSION_MINOR 4 #define DOCTEST_VERSION_MINOR 4
#define DOCTEST_VERSION_PATCH 5
#define DOCTEST_VERSION_STR "2.4.5"
#define DOCTEST_VERSION_PATCH 6
#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)
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
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) { \
bool res = op_macro(lhs, rhs); \
DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& 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) \
L lhs; L lhs;
assertType::Enum m_at; assertType::Enum m_at;


explicit Expression_lhs(L in, assertType::Enum at)
: lhs(in)
explicit Expression_lhs(L&& in, assertType::Enum at)
: lhs(doctest::detail::forward<L>(in))
, m_at(at) {} , 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;


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


#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;
// 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) {
return Expression_lhs<const DOCTEST_REF_WRAP(L)>(operand, m_at);
Expression_lhs<L> operator<<(L &&operand) {
return Expression_lhs<L>(doctest::detail::forward<L>(operand), m_at);
} }
}; };




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) {}
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; \
// 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, ...) \
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \
auto lambda_name = [&](std::ostream* s_name) { \
#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \
auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \
[&](std::ostream* s_name) { \
doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ 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)


#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;
"guarantee one atomic takes exactly one cache line"); "guarantee one atomic takes exactly one cache line");


public: public:
T operator++() noexcept { return fetch_add(1) + 1; }
T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; }


T operator++(int) noexcept { return fetch_add(1); }
T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); }


T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
return myAtomic().fetch_add(arg, order); return myAtomic().fetch_add(arg, order);
} }


T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
return myAtomic().fetch_sub(arg, order); return myAtomic().fetch_sub(arg, order);
} }


operator T() const noexcept { return load(); }
operator T() const DOCTEST_NOEXCEPT { return load(); }


T load(std::memory_order order = std::memory_order_seq_cst) const noexcept {
T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT {
auto result = T(); auto result = T();
for(auto const& c : m_atomics) { for(auto const& c : m_atomics) {
result += c.atomic.load(order); result += c.atomic.load(order);
return result; return result;
} }


T operator=(T desired) noexcept {
T operator=(T desired) DOCTEST_NOEXCEPT {
store(desired); store(desired);
return desired; return desired;
} }


void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
// first value becomes desired", all others become 0. // first value becomes desired", all others become 0.
for(auto& c : m_atomics) { for(auto& c : m_atomics) {
c.atomic.store(desired, order); c.atomic.store(desired, order);
// assigned in a round-robin fashion. // assigned in a round-robin fashion.
// 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with
// little overhead. // little overhead.
std::atomic<T>& myAtomic() noexcept {
std::atomic<T>& myAtomic() DOCTEST_NOEXCEPT {
static std::atomic<size_t> laneCounter; static std::atomic<size_t> laneCounter;
DOCTEST_THREAD_LOCAL size_t tlsLaneIdx = DOCTEST_THREAD_LOCAL size_t tlsLaneIdx =
laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES; laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES;
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
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()
return 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;
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;
// 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()) {
#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


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,
// - 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();
// - 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)
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>";
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 = {};
} }
}; };


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 = {};
char FatalConditionHandler::altStackMem[] = {};
stack_t FatalConditionHandler::oldSigStack = {};
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
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()); \
oss.str(""); \
if(oss.tellp() != std::streampos{}) { \
DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \
oss.str(""); \
} \
g_no_colors = with_col; \ g_no_colors = with_col; \
} }


#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; \
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();


#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;

+ 57
- 29
contrib/doctest/doctest/parts/doctest.cpp View File

#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;
"guarantee one atomic takes exactly one cache line"); "guarantee one atomic takes exactly one cache line");


public: public:
T operator++() noexcept { return fetch_add(1) + 1; }
T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; }


T operator++(int) noexcept { return fetch_add(1); }
T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); }


T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
return myAtomic().fetch_add(arg, order); return myAtomic().fetch_add(arg, order);
} }


T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
return myAtomic().fetch_sub(arg, order); return myAtomic().fetch_sub(arg, order);
} }


operator T() const noexcept { return load(); }
operator T() const DOCTEST_NOEXCEPT { return load(); }


T load(std::memory_order order = std::memory_order_seq_cst) const noexcept {
T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT {
auto result = T(); auto result = T();
for(auto const& c : m_atomics) { for(auto const& c : m_atomics) {
result += c.atomic.load(order); result += c.atomic.load(order);
return result; return result;
} }


T operator=(T desired) noexcept {
T operator=(T desired) DOCTEST_NOEXCEPT {
store(desired); store(desired);
return desired; return desired;
} }


void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
// first value becomes desired", all others become 0. // first value becomes desired", all others become 0.
for(auto& c : m_atomics) { for(auto& c : m_atomics) {
c.atomic.store(desired, order); c.atomic.store(desired, order);
// assigned in a round-robin fashion. // assigned in a round-robin fashion.
// 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with
// little overhead. // little overhead.
std::atomic<T>& myAtomic() noexcept {
std::atomic<T>& myAtomic() DOCTEST_NOEXCEPT {
static std::atomic<size_t> laneCounter; static std::atomic<size_t> laneCounter;
DOCTEST_THREAD_LOCAL size_t tlsLaneIdx = DOCTEST_THREAD_LOCAL size_t tlsLaneIdx =
laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES; laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES;
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
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()
return 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;
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;
// 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()) {
#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


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,
// - 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();
// - 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)
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>";
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 = {};
} }
}; };


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 = {};
char FatalConditionHandler::altStackMem[] = {};
stack_t FatalConditionHandler::oldSigStack = {};
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
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()); \
oss.str(""); \
if(oss.tellp() != std::streampos{}) { \
DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \
oss.str(""); \
} \
g_no_colors = with_col; \ g_no_colors = with_col; \
} }


#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; \
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();


#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;

+ 63
- 18
contrib/doctest/doctest/parts/doctest_fwd.h View File



#define DOCTEST_VERSION_MAJOR 2 #define DOCTEST_VERSION_MAJOR 2
#define DOCTEST_VERSION_MINOR 4 #define DOCTEST_VERSION_MINOR 4
#define DOCTEST_VERSION_PATCH 5
#define DOCTEST_VERSION_STR "2.4.5"
#define DOCTEST_VERSION_PATCH 6
#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)
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
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) { \
bool res = op_macro(lhs, rhs); \
DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& 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) \
L lhs; L lhs;
assertType::Enum m_at; assertType::Enum m_at;


explicit Expression_lhs(L in, assertType::Enum at)
: lhs(in)
explicit Expression_lhs(L&& in, assertType::Enum at)
: lhs(doctest::detail::forward<L>(in))
, m_at(at) {} , 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;


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


#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;
// 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) {
return Expression_lhs<const DOCTEST_REF_WRAP(L)>(operand, m_at);
Expression_lhs<L> operator<<(L &&operand) {
return Expression_lhs<L>(doctest::detail::forward<L>(operand), m_at);
} }
}; };




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) {}
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; \
// 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, ...) \
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \
auto lambda_name = [&](std::ostream* s_name) { \
#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \
auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \
[&](std::ostream* s_name) { \
doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ 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)



Loading…
Cancel
Save