Config no multithreading (#625)
* Add DOCTEST_CONFIG_NO_ATOMICS
* Fix
* Fix cmake stuff and ambiguity issue
* No mutices when multithreading is disabled
* Add WASI platform
* Fix various warnings
* No `thread_local`s when multithreading is disabled
* Fix tests
* Add docs
* Fix docs
* Various fixes, simplifications and additional tests
* Small docs amendment
* Tiny style fix
diff --git a/doc/markdown/configuration.md b/doc/markdown/configuration.md
index 73b4291..de1c4b3 100644
--- a/doc/markdown/configuration.md
+++ b/doc/markdown/configuration.md
@@ -30,6 +30,7 @@
- [**```DOCTEST_CONFIG_POSIX_SIGNALS```**](#doctest_config_posix_signals)
- [**```DOCTEST_CONFIG_NO_POSIX_SIGNALS```**](#doctest_config_no_posix_signals)
- [**```DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS```**](#doctest_config_include_type_traits)
+- [**```DOCTEST_CONFIG_NO_MULTITHREADING```**](#doctest_config_no_multithreading)
- [**```DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS```**](#doctest_config_no_multi_lane_atomics)
- [**```DOCTEST_CONFIG_ASSERTS_RETURN_VALUES```**](#doctest_config_asserts_return_values)
- [**```DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED```**](#doctest_config_evaluate_asserts_even_when_disabled)
@@ -237,6 +238,16 @@
This can be defined both globally and in specific source files only.
+### **```DOCTEST_CONFIG_NO_MULTITHREADING```**
+
+This can be used to disable all multithreading support.
+
+Speeds up single threaded applications.
+
+Includes [**```DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS```**](#doctest_config_no_multi_lane_atomics).
+
+This should be defined only in the source file where the library is implemented (it's relevant only there).
+
### **```DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS```**
This can be used to disable multi lane atomics. Multi lane atomics can speed up highly parallel use of assert statements, but have a small overhead for single threaded applications.
diff --git a/doctest/doctest.h b/doctest/doctest.h
index 3b6e965..fbafdf1 100644
--- a/doctest/doctest.h
+++ b/doctest/doctest.h
@@ -267,7 +267,7 @@
#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH
#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && \
- !defined(__EMSCRIPTEN__)
+ !defined(__EMSCRIPTEN__) && !defined(__wasi__)
#define DOCTEST_CONFIG_POSIX_SIGNALS
#endif // _WIN32
#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS)
@@ -275,7 +275,8 @@
#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
-#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)
+#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) \
+ || defined(__wasi__)
#define DOCTEST_CONFIG_NO_EXCEPTIONS
#endif // no exceptions
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
@@ -290,6 +291,10 @@
#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
+#ifdef __wasi__
+#define DOCTEST_CONFIG_NO_MULTITHREADING
+#endif
+
#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT)
#define DOCTEST_CONFIG_IMPLEMENT
#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
@@ -393,6 +398,8 @@
#define DOCTEST_PLATFORM_IPHONE
#elif defined(_WIN32)
#define DOCTEST_PLATFORM_WINDOWS
+#elif defined(__wasi__)
+#define DOCTEST_PLATFORM_WASI
#else // DOCTEST_PLATFORM
#define DOCTEST_PLATFORM_LINUX
#endif // DOCTEST_PLATFORM
@@ -3082,8 +3089,17 @@
#include <algorithm>
#include <iomanip>
#include <vector>
+#ifndef DOCTEST_CONFIG_NO_MULTITHREADING
#include <atomic>
#include <mutex>
+#define DOCTEST_DECLARE_MUTEX(name) std::mutex name;
+#define DOCTEST_DECLARE_STATIC_MUTEX(name) static DOCTEST_DECLARE_MUTEX(name)
+#define DOCTEST_LOCK_MUTEX(name) std::lock_guard<std::mutex> DOCTEST_ANONYMOUS(DOCTEST_ANON_LOCK_)(name);
+#else // DOCTEST_CONFIG_NO_MULTITHREADING
+#define DOCTEST_DECLARE_MUTEX(name)
+#define DOCTEST_DECLARE_STATIC_MUTEX(name)
+#define DOCTEST_LOCK_MUTEX(name)
+#endif // DOCTEST_CONFIG_NO_MULTITHREADING
#include <set>
#include <map>
#include <exception>
@@ -3146,7 +3162,7 @@
#endif
#ifndef DOCTEST_THREAD_LOCAL
-#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
+#if defined(DOCTEST_CONFIG_NO_MULTITHREADING) || DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
#define DOCTEST_THREAD_LOCAL
#else // DOCTEST_MSVC
#define DOCTEST_THREAD_LOCAL thread_local
@@ -3339,9 +3355,17 @@
ticks_t m_ticks = 0;
};
-#ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+#ifdef DOCTEST_CONFIG_NO_MULTITHREADING
template <typename T>
- using AtomicOrMultiLaneAtomic = std::atomic<T>;
+ using Atomic = T;
+#else // DOCTEST_CONFIG_NO_MULTITHREADING
+ template <typename T>
+ using Atomic = std::atomic<T>;
+#endif // DOCTEST_CONFIG_NO_MULTITHREADING
+
+#if defined(DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS) || defined(DOCTEST_CONFIG_NO_MULTITHREADING)
+ template <typename T>
+ using MultiLaneAtomic = 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,
@@ -3358,8 +3382,8 @@
{
struct CacheLineAlignedAtomic
{
- std::atomic<T> atomic{};
- char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)];
+ Atomic<T> atomic{};
+ char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(Atomic<T>)];
};
CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES];
@@ -3415,24 +3439,21 @@
// 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;
+ Atomic<T>& myAtomic() DOCTEST_NOEXCEPT {
+ static 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
struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats
{
- AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic;
- AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
+ MultiLaneAtomic<int> numAssertsCurrentTest_atomic;
+ MultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters
@@ -3449,7 +3470,7 @@
std::set<decltype(subcasesStack)> subcasesPassed;
int subcasesCurrentMaxLevel;
bool should_reenter;
- std::atomic<bool> shouldLogCurrentException;
+ Atomic<bool> shouldLogCurrentException;
void resetRunData() {
numTestCases = 0;
@@ -4509,10 +4530,10 @@
static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) {
// Multiple threads may enter this filter/handler at once. We want the error message to be printed on the
// console just once no matter how many threads have crashed.
- static std::mutex mutex;
+ DOCTEST_DECLARE_STATIC_MUTEX(mutex)
static bool execute = true;
{
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
if(execute) {
bool reported = false;
for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
@@ -5271,7 +5292,7 @@
struct XmlReporter : public IReporter
{
XmlWriter xml;
- std::mutex mutex;
+ DOCTEST_DECLARE_MUTEX(mutex)
// caching pointers/references to objects of these types - safe to do
const ContextOptions& opt;
@@ -5431,7 +5452,7 @@
}
void test_case_exception(const TestCaseException& e) override {
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
xml.scopedElement("Exception")
.writeAttribute("crash", e.is_crash)
@@ -5452,7 +5473,7 @@
if(!rb.m_failed && !opt.success)
return;
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
xml.startElement("Expression")
.writeAttribute("success", !rb.m_failed)
@@ -5478,7 +5499,7 @@
}
void log_message(const MessageData& mb) override {
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
xml.startElement("Message")
.writeAttribute("type", failureString(mb.m_severity))
@@ -5563,7 +5584,7 @@
struct JUnitReporter : public IReporter
{
XmlWriter xml;
- std::mutex mutex;
+ DOCTEST_DECLARE_MUTEX(mutex)
Timer timer;
std::vector<String> deepestSubcaseStackNames;
@@ -5731,7 +5752,7 @@
}
void test_case_exception(const TestCaseException& e) override {
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
testCaseData.addError("exception", e.error_string.c_str());
}
@@ -5745,7 +5766,7 @@
if(!rb.m_failed) // report only failures & ignore the `success` option
return;
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
std::ostringstream os;
os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(")
@@ -5796,7 +5817,7 @@
bool hasLoggedCurrentTestStart;
std::vector<SubcaseSignature> subcasesStack;
size_t currentSubcaseLevel;
- std::mutex mutex;
+ DOCTEST_DECLARE_MUTEX(mutex)
// caching pointers/references to objects of these types - safe to do
const ContextOptions& opt;
@@ -6173,7 +6194,7 @@
}
void test_case_exception(const TestCaseException& e) override {
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
if(tc->m_no_output)
return;
@@ -6212,7 +6233,7 @@
if((!rb.m_failed && !opt.success) || tc->m_no_output)
return;
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
logTestStart();
@@ -6228,7 +6249,7 @@
if(tc->m_no_output)
return;
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
logTestStart();
diff --git a/doctest/parts/doctest.cpp b/doctest/parts/doctest.cpp
index 7b8670a..f134127 100644
--- a/doctest/parts/doctest.cpp
+++ b/doctest/parts/doctest.cpp
@@ -75,8 +75,17 @@
#include <algorithm>
#include <iomanip>
#include <vector>
+#ifndef DOCTEST_CONFIG_NO_MULTITHREADING
#include <atomic>
#include <mutex>
+#define DOCTEST_DECLARE_MUTEX(name) std::mutex name;
+#define DOCTEST_DECLARE_STATIC_MUTEX(name) static DOCTEST_DECLARE_MUTEX(name)
+#define DOCTEST_LOCK_MUTEX(name) std::lock_guard<std::mutex> DOCTEST_ANONYMOUS(DOCTEST_ANON_LOCK_)(name);
+#else // DOCTEST_CONFIG_NO_MULTITHREADING
+#define DOCTEST_DECLARE_MUTEX(name)
+#define DOCTEST_DECLARE_STATIC_MUTEX(name)
+#define DOCTEST_LOCK_MUTEX(name)
+#endif // DOCTEST_CONFIG_NO_MULTITHREADING
#include <set>
#include <map>
#include <exception>
@@ -139,7 +148,7 @@
#endif
#ifndef DOCTEST_THREAD_LOCAL
-#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
+#if defined(DOCTEST_CONFIG_NO_MULTITHREADING) || DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
#define DOCTEST_THREAD_LOCAL
#else // DOCTEST_MSVC
#define DOCTEST_THREAD_LOCAL thread_local
@@ -332,9 +341,17 @@
ticks_t m_ticks = 0;
};
-#ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+#ifdef DOCTEST_CONFIG_NO_MULTITHREADING
template <typename T>
- using AtomicOrMultiLaneAtomic = std::atomic<T>;
+ using Atomic = T;
+#else // DOCTEST_CONFIG_NO_MULTITHREADING
+ template <typename T>
+ using Atomic = std::atomic<T>;
+#endif // DOCTEST_CONFIG_NO_MULTITHREADING
+
+#if defined(DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS) || defined(DOCTEST_CONFIG_NO_MULTITHREADING)
+ template <typename T>
+ using MultiLaneAtomic = 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,
@@ -351,8 +368,8 @@
{
struct CacheLineAlignedAtomic
{
- std::atomic<T> atomic{};
- char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)];
+ Atomic<T> atomic{};
+ char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(Atomic<T>)];
};
CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES];
@@ -408,24 +425,21 @@
// 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;
+ Atomic<T>& myAtomic() DOCTEST_NOEXCEPT {
+ static 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
struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats
{
- AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic;
- AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
+ MultiLaneAtomic<int> numAssertsCurrentTest_atomic;
+ MultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters
@@ -442,7 +456,7 @@
std::set<decltype(subcasesStack)> subcasesPassed;
int subcasesCurrentMaxLevel;
bool should_reenter;
- std::atomic<bool> shouldLogCurrentException;
+ Atomic<bool> shouldLogCurrentException;
void resetRunData() {
numTestCases = 0;
@@ -1502,10 +1516,10 @@
static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) {
// Multiple threads may enter this filter/handler at once. We want the error message to be printed on the
// console just once no matter how many threads have crashed.
- static std::mutex mutex;
+ DOCTEST_DECLARE_STATIC_MUTEX(mutex)
static bool execute = true;
{
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
if(execute) {
bool reported = false;
for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
@@ -2264,7 +2278,7 @@
struct XmlReporter : public IReporter
{
XmlWriter xml;
- std::mutex mutex;
+ DOCTEST_DECLARE_MUTEX(mutex)
// caching pointers/references to objects of these types - safe to do
const ContextOptions& opt;
@@ -2424,7 +2438,7 @@
}
void test_case_exception(const TestCaseException& e) override {
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
xml.scopedElement("Exception")
.writeAttribute("crash", e.is_crash)
@@ -2445,7 +2459,7 @@
if(!rb.m_failed && !opt.success)
return;
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
xml.startElement("Expression")
.writeAttribute("success", !rb.m_failed)
@@ -2471,7 +2485,7 @@
}
void log_message(const MessageData& mb) override {
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
xml.startElement("Message")
.writeAttribute("type", failureString(mb.m_severity))
@@ -2556,7 +2570,7 @@
struct JUnitReporter : public IReporter
{
XmlWriter xml;
- std::mutex mutex;
+ DOCTEST_DECLARE_MUTEX(mutex)
Timer timer;
std::vector<String> deepestSubcaseStackNames;
@@ -2724,7 +2738,7 @@
}
void test_case_exception(const TestCaseException& e) override {
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
testCaseData.addError("exception", e.error_string.c_str());
}
@@ -2738,7 +2752,7 @@
if(!rb.m_failed) // report only failures & ignore the `success` option
return;
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
std::ostringstream os;
os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(")
@@ -2789,7 +2803,7 @@
bool hasLoggedCurrentTestStart;
std::vector<SubcaseSignature> subcasesStack;
size_t currentSubcaseLevel;
- std::mutex mutex;
+ DOCTEST_DECLARE_MUTEX(mutex)
// caching pointers/references to objects of these types - safe to do
const ContextOptions& opt;
@@ -3166,7 +3180,7 @@
}
void test_case_exception(const TestCaseException& e) override {
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
if(tc->m_no_output)
return;
@@ -3205,7 +3219,7 @@
if((!rb.m_failed && !opt.success) || tc->m_no_output)
return;
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
logTestStart();
@@ -3221,7 +3235,7 @@
if(tc->m_no_output)
return;
- std::lock_guard<std::mutex> lock(mutex);
+ DOCTEST_LOCK_MUTEX(mutex)
logTestStart();
diff --git a/doctest/parts/doctest_fwd.h b/doctest/parts/doctest_fwd.h
index 5f381b1..597bbad 100644
--- a/doctest/parts/doctest_fwd.h
+++ b/doctest/parts/doctest_fwd.h
@@ -264,7 +264,7 @@
#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH
#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && \
- !defined(__EMSCRIPTEN__)
+ !defined(__EMSCRIPTEN__) && !defined(__wasi__)
#define DOCTEST_CONFIG_POSIX_SIGNALS
#endif // _WIN32
#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS)
@@ -272,7 +272,8 @@
#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
-#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)
+#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) \
+ || defined(__wasi__)
#define DOCTEST_CONFIG_NO_EXCEPTIONS
#endif // no exceptions
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
@@ -287,6 +288,10 @@
#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
+#ifdef __wasi__
+#define DOCTEST_CONFIG_NO_MULTITHREADING
+#endif
+
#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT)
#define DOCTEST_CONFIG_IMPLEMENT
#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
@@ -390,6 +395,8 @@
#define DOCTEST_PLATFORM_IPHONE
#elif defined(_WIN32)
#define DOCTEST_PLATFORM_WINDOWS
+#elif defined(__wasi__)
+#define DOCTEST_PLATFORM_WASI
#else // DOCTEST_PLATFORM
#define DOCTEST_PLATFORM_LINUX
#endif // DOCTEST_PLATFORM
diff --git a/examples/all_features/CMakeLists.txt b/examples/all_features/CMakeLists.txt
index 4d2fe1b..3d6b342 100644
--- a/examples/all_features/CMakeLists.txt
+++ b/examples/all_features/CMakeLists.txt
@@ -97,15 +97,11 @@
doctest_add_test(NAME minimal ${common_args} -m -sf=*test_cases_and_suites*) # minimal with summary
doctest_add_test(NAME minimal_no_fail ${common_args} -m -sf=*no_failures.cpp) # minimal
-################################################################################
-## DOCTEST DISABLED - EXPRESSIONS STILL EVALUATE TO RETURN PROPER VALUES
-################################################################################
-
add_executable(disabled_but_evaluated assert_returns_disabled.cpp assert_returns_disabled_evaluate.cpp)
target_compile_definitions(disabled_but_evaluated PRIVATE DOCTEST_CONFIG_DISABLE)
target_link_libraries(disabled_but_evaluated doctest ${CMAKE_THREAD_LIBS_INIT})
-doctest_add_test_impl(NAME disabled_but_evaluated COMMAND $<TARGET_FILE:disabled_but_evaluated>)
+doctest_add_test_impl(NO_OUTPUT NAME disabled_but_evaluated COMMAND $<TARGET_FILE:disabled_but_evaluated>)
if(MSVC)
target_compile_options(disabled_but_evaluated PRIVATE /wd4702) # unreachable code
@@ -119,14 +115,20 @@
endif()
################################################################################
-## VARIATION OF THE BUILD WITH DOCTEST DISABLED - SHOULD STILL COMPILE
+## CONFIG TESTS - TESTS WITH VARIOUS CONFIGURATION OPTIONS
################################################################################
-add_executable(disabled ${files_all})
-target_compile_definitions(disabled PRIVATE DOCTEST_CONFIG_DISABLE)
-target_link_libraries(disabled doctest ${CMAKE_THREAD_LIBS_INIT})
+function(add_test_all_features test_name flags)
+ add_executable(${test_name} ${files_with_output})
+ target_compile_definitions(${test_name} PRIVATE ${flags})
+ target_link_libraries(${test_name} doctest ${CMAKE_THREAD_LIBS_INIT})
-doctest_add_test_impl(NAME disabled COMMAND $<TARGET_FILE:disabled>)
+ doctest_add_test_impl(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}> --no-skipped-summary --no-version -ob=name)
+endfunction()
+
+add_test_all_features(no_multithreading DOCTEST_CONFIG_NO_MULTITHREADING)
+add_test_all_features(no_multi_lane_atomics DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS)
+add_test_all_features(disabled DOCTEST_CONFIG_DISABLE)
# TODO: think about fixing these in a different way! - see issue #61 or commit 6b61e8aa3818c5ea100cedc1bb48a60ea10df6e8
if(MSVC)
diff --git a/examples/all_features/test_output/no_multi_lane_atomics.txt b/examples/all_features/test_output/no_multi_lane_atomics.txt
new file mode 100644
index 0000000..1d3a309
--- /dev/null
+++ b/examples/all_features/test_output/no_multi_lane_atomics.txt
@@ -0,0 +1,813 @@
+[doctest] run with "--help" for options
+===============================================================================
+subcases.cpp(0):
+ Scenario: vectors can be sized and resized
+ Given: A vector with some items
+ When: the size is increased
+ Then: the size and capacity change
+
+subcases.cpp(0): ERROR: CHECK( v.size() == 20 ) is NOT correct!
+ values: CHECK( 10 == 20 )
+
+===============================================================================
+subcases.cpp(0):
+ Scenario: vectors can be sized and resized
+ Given: A vector with some items
+ When: less capacity is reserved
+ Then: neither size nor capacity are changed
+
+subcases.cpp(0): ERROR: CHECK( v.size() == 10 ) is NOT correct!
+ values: CHECK( 5 == 10 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: CHECK level of asserts fail the test case but don't abort it
+
+assertion_macros.cpp(0): ERROR: CHECK( 0 ) is NOT correct!
+ values: CHECK( 0 )
+
+assertion_macros.cpp(0): ERROR: CHECK_FALSE( 1 ) is NOT correct!
+ values: CHECK_FALSE( 1 )
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(false, 0), bool ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(true, 0), bool ) threw a DIFFERENT exception: "0"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(true, 0), "unrecognized" ) threw a DIFFERENT exception: "0"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, 0), "unrecognized", int ) threw a DIFFERENT exception! (contents: "0")
+
+assertion_macros.cpp(0): ERROR: CHECK_NOTHROW( throw_if(true, 0) ) THREW exception: "0"
+
+assertion_macros.cpp(0): ERROR: CHECK_EQ( 1, 0 ) is NOT correct!
+ values: CHECK_EQ( 1, 0 )
+
+assertion_macros.cpp(0): ERROR: CHECK_UNARY( 0 ) is NOT correct!
+ values: CHECK_UNARY( 0 )
+
+assertion_macros.cpp(0): ERROR: CHECK_UNARY_FALSE( 1 ) is NOT correct!
+ values: CHECK_UNARY_FALSE( 1 )
+
+assertion_macros.cpp(0): MESSAGE: reached!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 1
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE( 0 ) is NOT correct!
+ values: REQUIRE( 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 10
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_NOTHROW( throw_if(true, 0) ) THREW exception: "0"
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 11
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_EQ( 1, 0 ) is NOT correct!
+ values: REQUIRE_EQ( 1, 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 12
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_UNARY( 0 ) is NOT correct!
+ values: REQUIRE_UNARY( 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 13
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_UNARY_FALSE( 1 ) is NOT correct!
+ values: REQUIRE_UNARY_FALSE( 1 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 2
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_FALSE( 1 ) is NOT correct!
+ values: REQUIRE_FALSE( 1 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 3
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 4
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_AS( throw_if(false, 0), bool ) did NOT throw at all!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 5
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_AS( throw_if(true, 0), bool ) threw a DIFFERENT exception: "0"
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 6
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_WITH( throw_if(false, ""), "whops!" ) did NOT throw at all!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 7
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_WITH( throw_if(true, ""), "whops!" ) threw a DIFFERENT exception:
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 8
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_WITH_AS( throw_if(false, ""), "whops!", bool ) did NOT throw at all!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 9
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_WITH_AS( throw_if(true, ""), "whops!", bool ) threw a DIFFERENT exception! (contents: )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: WARN level of asserts don't fail the test case
+
+assertion_macros.cpp(0): WARNING: WARN( 0 ) is NOT correct!
+ values: WARN( 0 )
+
+assertion_macros.cpp(0): WARNING: WARN_FALSE( 1 ) is NOT correct!
+ values: WARN_FALSE( 1 )
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_WITH( throw_if(true, ""), "whops!" ) threw a DIFFERENT exception:
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_WITH( throw_if(false, ""), "whops!" ) did NOT throw at all!
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_AS( throw_if(false, 0), bool ) did NOT throw at all!
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_AS( throw_if(true, 0), bool ) threw a DIFFERENT exception: "0"
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_WITH_AS( throw_if(false, ""), "whops!", int ) did NOT throw at all!
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_WITH_AS( throw_if(true, ""), "whops!", int ) threw a DIFFERENT exception! (contents: )
+
+assertion_macros.cpp(0): WARNING: WARN_NOTHROW( throw_if(true, 0) ) THREW exception: "0"
+
+assertion_macros.cpp(0): WARNING: WARN_EQ( 1, 0 ) is NOT correct!
+ values: WARN_EQ( 1, 0 )
+
+assertion_macros.cpp(0): WARNING: WARN_UNARY( 0 ) is NOT correct!
+ values: WARN_UNARY( 0 )
+
+assertion_macros.cpp(0): WARNING: WARN_UNARY_FALSE( 1 ) is NOT correct!
+ values: WARN_UNARY_FALSE( 1 )
+
+===============================================================================
+stringification.cpp(0):
+TEST CASE: a test case that registers an exception translator for int and then throws one
+
+stringification.cpp(0): ERROR: test case THREW exception: 5
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: a test case that will end from an exception
+
+logging.cpp(0): ERROR: forcing the many captures to be stringified
+ logged: lots of captures: 42 42 42;
+ old way of capturing - using the streaming operator: 42 42
+
+logging.cpp(0): ERROR: CHECK( some_var == 666 ) is NOT correct!
+ values: CHECK( 42 == 666 )
+ logged: someTests() returned: 42
+ this should be printed if an exception is thrown even if no assert has failed: 42
+ in a nested scope this should be printed as well: 42
+ why is this not 666 ?!
+
+logging.cpp(0): ERROR: test case THREW exception: 0
+ logged: someTests() returned: 42
+ this should be printed if an exception is thrown even if no assert has failed: 42
+ in a nested scope this should be printed as well: 42
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: a test case that will end from an exception and should print the unprinted context
+
+logging.cpp(0): ERROR: test case THREW exception: 0
+ logged: should be printed even if an exception is thrown and no assert fails before that
+
+===============================================================================
+stringification.cpp(0):
+TEST CASE: all asserts should fail and show how the objects get stringified
+
+stringification.cpp(0): ERROR: CHECK( f1 == f2 ) is NOT correct!
+ values: CHECK( Foo{} == Foo{} )
+
+stringification.cpp(0): ERROR: CHECK( dummy == "tralala" ) is NOT correct!
+ values: CHECK( omg == tralala )
+
+stringification.cpp(0): ERROR: CHECK( "tralala" == dummy ) is NOT correct!
+ values: CHECK( tralala == omg )
+
+stringification.cpp(0): ERROR: CHECK( vec1 == vec2 ) is NOT correct!
+ values: CHECK( [1, 2, 3] == [1, 2, 4] )
+
+stringification.cpp(0): ERROR: CHECK( lst_1 == lst_2 ) is NOT correct!
+ values: CHECK( [1, 42, 3, ] == [1, 2, 666, ] )
+
+stringification.cpp(0): ERROR: CHECK( s1 == s2 ) is NOT correct!
+ values: CHECK( MyOtherType: 42 == MyOtherType: 666 )
+ logged: s1=MyOtherType: 42 s2=MyOtherType: 666
+
+stringification.cpp(0): ERROR: CHECK( s1 == s2 ) is NOT correct!
+ values: CHECK( MyOtherType: 42 == MyOtherType: 666 )
+ logged: s1=MyOtherType: 42 s2=MyOtherType: 666
+ MyOtherType: 42 is not really MyOtherType: 666
+
+stringification.cpp(0): ERROR: CHECK( doctest::IsNaN<double>(0.5) ) is NOT correct!
+ values: CHECK( 0.5 )
+
+stringification.cpp(0): ERROR: CHECK( doctest::IsNaN<float>(std::numeric_limits<float>::infinity()) ) is NOT correct!
+ values: CHECK( inf )
+
+stringification.cpp(0): ERROR: CHECK( "a" == doctest::Contains("aaa") ) is NOT correct!
+ values: CHECK( a == Contains( aaa ) )
+
+stringification.cpp(0): ERROR: test case THREW exception: MyTypeInherited<int>(5, 4)
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: bad stringification of type pair<int_pair>
+
+templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
+ values: CHECK( 0 != 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: check return values
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: check return values no print
+
+assertion_macros.cpp(0): ERROR: CHECK( a == b ) is NOT correct!
+ values: CHECK( 4 == 2 )
+
+assertion_macros.cpp(0): ERROR: CHECK_FALSE( a != b ) is NOT correct!
+ values: CHECK_FALSE( 4 != 2 )
+
+assertion_macros.cpp(0): ERROR: CHECK_EQ( a, b ) is NOT correct!
+ values: CHECK_EQ( 4, 2 )
+
+assertion_macros.cpp(0): ERROR: CHECK_UNARY( a == b ) is NOT correct!
+ values: CHECK_UNARY( false )
+
+assertion_macros.cpp(0): ERROR: CHECK_UNARY_FALSE( a != b ) is NOT correct!
+ values: CHECK_UNARY_FALSE( true )
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS( throw_if(false, false) ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(true, 2), doctest::Approx ) threw a DIFFERENT exception: "2"
+
+assertion_macros.cpp(0): ERROR: CHECK_NOTHROW( throw_if(true, 2) ) THREW exception: "2"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(true, 2), "1" ) threw a DIFFERENT exception: "2"
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: doesn't fail but it should have
+
+Should have failed but didn't! Marking it as failed!
+===============================================================================
+enums.cpp(0):
+TEST CASE: enum 2
+
+enums.cpp(0): ERROR: CHECK_EQ( Zero, 1 ) is NOT correct!
+ values: CHECK_EQ( 0, 1 )
+
+enums.cpp(0): ERROR: CHECK_EQ( One, 2 ) is NOT correct!
+ values: CHECK_EQ( 1, 2 )
+
+enums.cpp(0): ERROR: CHECK_EQ( Two, 3 ) is NOT correct!
+ values: CHECK_EQ( 2, 3 )
+
+enums.cpp(0): ERROR: CHECK_EQ( TypedZero, 1 ) is NOT correct!
+ values: CHECK_EQ( 0, 1 )
+
+enums.cpp(0): ERROR: CHECK_EQ( TypedOne, 2 ) is NOT correct!
+ values: CHECK_EQ( 1, 2 )
+
+enums.cpp(0): ERROR: CHECK_EQ( TypedTwo, 3 ) is NOT correct!
+ values: CHECK_EQ( 2, 3 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassC::Zero, EnumClassC::One ) is NOT correct!
+ values: CHECK_EQ( 48, 49 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassC::One, EnumClassC::Two ) is NOT correct!
+ values: CHECK_EQ( 49, 50 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassC::Two, EnumClassC::Zero ) is NOT correct!
+ values: CHECK_EQ( 50, 48 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassSC::Zero, EnumClassSC::One ) is NOT correct!
+ values: CHECK_EQ( 48, 49 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassSC::One, EnumClassSC::Two ) is NOT correct!
+ values: CHECK_EQ( 49, 50 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassSC::Two, EnumClassSC::Zero ) is NOT correct!
+ values: CHECK_EQ( 50, 48 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassUC::Zero, EnumClassUC::One ) is NOT correct!
+ values: CHECK_EQ( 48, 49 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassUC::One, EnumClassUC::Two ) is NOT correct!
+ values: CHECK_EQ( 49, 50 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassUC::Two, EnumClassUC::Zero ) is NOT correct!
+ values: CHECK_EQ( 50, 48 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassU8::Zero, EnumClassU8::One ) is NOT correct!
+ values: CHECK_EQ( 0, 1 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassU8::One, EnumClassU8::Two ) is NOT correct!
+ values: CHECK_EQ( 1, 2 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassU8::Two, EnumClassU8::Zero ) is NOT correct!
+ values: CHECK_EQ( 2, 0 )
+
+Failed as expected so marking it as not failed
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: exceptions-related macros
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(true, 0), char ) threw a DIFFERENT exception: "0"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(false, 0), int ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(true, "whops!"), "whops! no match!" ) threw a DIFFERENT exception: "whops!"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(true, "whops! does it match?"), "whops! no match!" ) threw a DIFFERENT exception: "whops! does it match?"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, "whops!"), "whops! no match!", bool ) threw a DIFFERENT exception! (contents: "whops!")
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, "whops!"), "whops!", int ) threw a DIFFERENT exception! (contents: "whops!")
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, "whops! does it match?"), "whops! no match!", int ) threw a DIFFERENT exception! (contents: "whops! does it match?")
+
+assertion_macros.cpp(0): ERROR: CHECK_NOTHROW( throw_if(true, 0) ) THREW exception: "0"
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: exceptions-related macros for std::exception
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(false, std::runtime_error("whops!")), std::exception ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(true, std::runtime_error("whops!")), int ) threw a DIFFERENT exception: "whops!"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(false, ""), "whops!" ) did NOT throw at all!
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_NOTHROW( throw_if(true, std::runtime_error("whops!")) ) THREW exception: "whops!"
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: explicit failures 1
+
+logging.cpp(0): ERROR: this should not end the test case, but mark it as failing
+
+logging.cpp(0): MESSAGE: reached!
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: explicit failures 2
+
+logging.cpp(0): FATAL ERROR: fail the test case and also end it
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: fails - and its allowed
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+Allowed to fail so marking it as not failed
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: fails 1 time as it should
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+Failed exactly 1 times as expected so marking it as not failed!
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: fails as it should
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+Failed as expected so marking it as not failed
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+ level zero
+ one
+
+subcases.cpp(0): ERROR: CHECK( false ) is NOT correct!
+ values: CHECK( false )
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+ level zero
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ level zero
+ one
+
+subcases.cpp(0): ERROR: test case THREW exception: exception thrown in subcase - will translate later when the whole test case has been exited (cannot translate while there is an active exception)
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ level zero
+ one
+
+subcases.cpp(0): ERROR: test case THREW exception: failure... but the show must go on!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+ level zero
+ two
+
+subcases.cpp(0): ERROR: CHECK( false ) is NOT correct!
+ values: CHECK( false )
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+ level zero
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ level zero
+ two
+
+subcases.cpp(0): ERROR: test case THREW exception: exception thrown in subcase - will translate later when the whole test case has been exited (cannot translate while there is an active exception)
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ level zero
+ two
+
+subcases.cpp(0): ERROR: test case THREW exception: failure... but the show must go on!
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: fails more times than it should
+
+test_cases_and_suites.cpp(0): ERROR:
+
+test_cases_and_suites.cpp(0): ERROR:
+
+Didn't fail exactly 1 times so marking it as failed!
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST CASE: fixtured test - not part of a test suite
+
+test_cases_and_suites.cpp(0): ERROR: CHECK( data == 85 ) is NOT correct!
+ values: CHECK( 21 == 85 )
+
+===============================================================================
+header.h(0):
+TEST SUITE: some TS
+TEST CASE: in TS
+
+header.h(0): FATAL ERROR:
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: logging the counter of a loop
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 1 != 1 )
+ logged: current iteration of loop:
+ i := 0
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 2 != 2 )
+ logged: current iteration of loop:
+ i := 1
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 4 != 4 )
+ logged: current iteration of loop:
+ i := 2
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 8 != 8 )
+ logged: current iteration of loop:
+ i := 3
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 16 != 16 )
+ logged: current iteration of loop:
+ i := 4
+
+
+root
+1
+1.1
+
+root
+2
+2.1
+
+root
+2
+===============================================================================
+subcases.cpp(0):
+TEST CASE: lots of nested subcases
+
+subcases.cpp(0): FATAL ERROR:
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: multiple types<>
+
+templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
+ values: CHECK( 0 != 0 )
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: multiple types<>
+
+templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
+ values: CHECK( 0 != 0 )
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: multiple types<>
+
+templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
+ values: CHECK( 0 != 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: normal macros
+
+assertion_macros.cpp(0): ERROR: CHECK( throw_if(true, std::runtime_error("whops!")) == 42 ) THREW exception: "whops!"
+
+assertion_macros.cpp(0): ERROR: CHECK( doctest::Approx(0.502) == 0.501 ) is NOT correct!
+ values: CHECK( Approx( 0.502 ) == 0.501 )
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST SUITE: ts1
+TEST CASE: normal test in a test suite from a decorator
+
+test_cases_and_suites.cpp(0): MESSAGE: failing because of the timeout decorator!
+
+Test case exceeded time limit of 0.000001!
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST SUITE: scoped test suite
+TEST CASE: part of scoped
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST SUITE: scoped test suite
+TEST CASE: part of scoped 2
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST SUITE: some TS
+TEST CASE: part of some TS
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST CASE: should fail because of an exception
+
+test_cases_and_suites.cpp(0): ERROR: test case THREW exception: 0
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: some asserts used in a function called by a test case
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, false), "unknown exception", int ) threw a DIFFERENT exception! (contents: "unknown exception")
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+ from function...
+
+subcases.cpp(0): MESSAGE: print me twice
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+ from function...
+ sc1
+
+subcases.cpp(0): MESSAGE: hello! from sc1
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ from function...
+ sc1
+
+subcases.cpp(0): MESSAGE: lala
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+ from function...
+
+subcases.cpp(0): MESSAGE: print me twice
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+ from function...
+ sc2
+
+subcases.cpp(0): MESSAGE: hello! from sc2
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ from function...
+ sc2
+
+subcases.cpp(0): MESSAGE: lala
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ outer 0
+ inner 0
+
+subcases.cpp(0): MESSAGE: msg!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ outer 0
+ inner 1
+
+subcases.cpp(0): MESSAGE: msg!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ outer 1
+ inner 0
+
+subcases.cpp(0): MESSAGE: msg!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ outer 1
+ inner 1
+
+subcases.cpp(0): MESSAGE: msg!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ separate
+
+subcases.cpp(0): MESSAGE: separate msg!
+
+===============================================================================
+header.h(0):
+TEST CASE: template 1<char>
+
+header.h(0): FATAL ERROR:
+
+===============================================================================
+header.h(0):
+TEST CASE: template 2<doctest::String>
+
+header.h(0): FATAL ERROR:
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: test case should fail even though the last subcase passes
+ one
+
+subcases.cpp(0): ERROR: CHECK( false ) is NOT correct!
+ values: CHECK( false )
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: third party asserts can report failures to doctest
+
+logging.cpp(0): ERROR: MY_ASSERT(false)
+
+logging.cpp(0): FATAL ERROR: MY_ASSERT_FATAL(false)
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: this test has overridden its skip decorator
+TEST SUITE: skipped test cases
+TEST CASE: unskipped
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: vector stuff<std::vector<int>>
+
+templated_test_cases.cpp(0): ERROR: CHECK( vec.size() == 20 ) is NOT correct!
+ values: CHECK( 10 == 20 )
+
+===============================================================================
+subcases.cpp(0):
+TEST SUITE: with a funny name,
+TEST CASE: with a funnier name\:
+ with the funniest name\,
+
+subcases.cpp(0): MESSAGE: Yes!
+
+===============================================================================
+subcases.cpp(0):
+TEST SUITE: with a funny name,
+TEST CASE: with a funnier name\:
+ with a slightly funny name :
+
+subcases.cpp(0): MESSAGE: Yep!
+
+===============================================================================
+subcases.cpp(0):
+TEST SUITE: with a funny name,
+TEST CASE: with a funnier name\:
+ without a funny name
+
+subcases.cpp(0): MESSAGE: NO!
+
+===============================================================================
+subcases.cpp(0):
+TEST SUITE: with a funny name,
+TEST CASE: without a funny name:
+
+subcases.cpp(0): MESSAGE: Nooo
+
+===============================================================================
+[doctest] test cases: 78 | 30 passed | 48 failed |
+[doctest] assertions: 213 | 99 passed | 114 failed |
+[doctest] Status: FAILURE!
+Program code.
diff --git a/examples/all_features/test_output/no_multithreading.txt b/examples/all_features/test_output/no_multithreading.txt
new file mode 100644
index 0000000..1d3a309
--- /dev/null
+++ b/examples/all_features/test_output/no_multithreading.txt
@@ -0,0 +1,813 @@
+[doctest] run with "--help" for options
+===============================================================================
+subcases.cpp(0):
+ Scenario: vectors can be sized and resized
+ Given: A vector with some items
+ When: the size is increased
+ Then: the size and capacity change
+
+subcases.cpp(0): ERROR: CHECK( v.size() == 20 ) is NOT correct!
+ values: CHECK( 10 == 20 )
+
+===============================================================================
+subcases.cpp(0):
+ Scenario: vectors can be sized and resized
+ Given: A vector with some items
+ When: less capacity is reserved
+ Then: neither size nor capacity are changed
+
+subcases.cpp(0): ERROR: CHECK( v.size() == 10 ) is NOT correct!
+ values: CHECK( 5 == 10 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: CHECK level of asserts fail the test case but don't abort it
+
+assertion_macros.cpp(0): ERROR: CHECK( 0 ) is NOT correct!
+ values: CHECK( 0 )
+
+assertion_macros.cpp(0): ERROR: CHECK_FALSE( 1 ) is NOT correct!
+ values: CHECK_FALSE( 1 )
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(false, 0), bool ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(true, 0), bool ) threw a DIFFERENT exception: "0"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(true, 0), "unrecognized" ) threw a DIFFERENT exception: "0"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, 0), "unrecognized", int ) threw a DIFFERENT exception! (contents: "0")
+
+assertion_macros.cpp(0): ERROR: CHECK_NOTHROW( throw_if(true, 0) ) THREW exception: "0"
+
+assertion_macros.cpp(0): ERROR: CHECK_EQ( 1, 0 ) is NOT correct!
+ values: CHECK_EQ( 1, 0 )
+
+assertion_macros.cpp(0): ERROR: CHECK_UNARY( 0 ) is NOT correct!
+ values: CHECK_UNARY( 0 )
+
+assertion_macros.cpp(0): ERROR: CHECK_UNARY_FALSE( 1 ) is NOT correct!
+ values: CHECK_UNARY_FALSE( 1 )
+
+assertion_macros.cpp(0): MESSAGE: reached!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 1
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE( 0 ) is NOT correct!
+ values: REQUIRE( 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 10
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_NOTHROW( throw_if(true, 0) ) THREW exception: "0"
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 11
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_EQ( 1, 0 ) is NOT correct!
+ values: REQUIRE_EQ( 1, 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 12
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_UNARY( 0 ) is NOT correct!
+ values: REQUIRE_UNARY( 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 13
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_UNARY_FALSE( 1 ) is NOT correct!
+ values: REQUIRE_UNARY_FALSE( 1 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 2
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_FALSE( 1 ) is NOT correct!
+ values: REQUIRE_FALSE( 1 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 3
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 4
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_AS( throw_if(false, 0), bool ) did NOT throw at all!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 5
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_AS( throw_if(true, 0), bool ) threw a DIFFERENT exception: "0"
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 6
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_WITH( throw_if(false, ""), "whops!" ) did NOT throw at all!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 7
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_WITH( throw_if(true, ""), "whops!" ) threw a DIFFERENT exception:
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 8
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_WITH_AS( throw_if(false, ""), "whops!", bool ) did NOT throw at all!
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: REQUIRE level of asserts fail and abort the test case - 9
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_THROWS_WITH_AS( throw_if(true, ""), "whops!", bool ) threw a DIFFERENT exception! (contents: )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: WARN level of asserts don't fail the test case
+
+assertion_macros.cpp(0): WARNING: WARN( 0 ) is NOT correct!
+ values: WARN( 0 )
+
+assertion_macros.cpp(0): WARNING: WARN_FALSE( 1 ) is NOT correct!
+ values: WARN_FALSE( 1 )
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_WITH( throw_if(true, ""), "whops!" ) threw a DIFFERENT exception:
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_WITH( throw_if(false, ""), "whops!" ) did NOT throw at all!
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_AS( throw_if(false, 0), bool ) did NOT throw at all!
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_AS( throw_if(true, 0), bool ) threw a DIFFERENT exception: "0"
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_WITH_AS( throw_if(false, ""), "whops!", int ) did NOT throw at all!
+
+assertion_macros.cpp(0): WARNING: WARN_THROWS_WITH_AS( throw_if(true, ""), "whops!", int ) threw a DIFFERENT exception! (contents: )
+
+assertion_macros.cpp(0): WARNING: WARN_NOTHROW( throw_if(true, 0) ) THREW exception: "0"
+
+assertion_macros.cpp(0): WARNING: WARN_EQ( 1, 0 ) is NOT correct!
+ values: WARN_EQ( 1, 0 )
+
+assertion_macros.cpp(0): WARNING: WARN_UNARY( 0 ) is NOT correct!
+ values: WARN_UNARY( 0 )
+
+assertion_macros.cpp(0): WARNING: WARN_UNARY_FALSE( 1 ) is NOT correct!
+ values: WARN_UNARY_FALSE( 1 )
+
+===============================================================================
+stringification.cpp(0):
+TEST CASE: a test case that registers an exception translator for int and then throws one
+
+stringification.cpp(0): ERROR: test case THREW exception: 5
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: a test case that will end from an exception
+
+logging.cpp(0): ERROR: forcing the many captures to be stringified
+ logged: lots of captures: 42 42 42;
+ old way of capturing - using the streaming operator: 42 42
+
+logging.cpp(0): ERROR: CHECK( some_var == 666 ) is NOT correct!
+ values: CHECK( 42 == 666 )
+ logged: someTests() returned: 42
+ this should be printed if an exception is thrown even if no assert has failed: 42
+ in a nested scope this should be printed as well: 42
+ why is this not 666 ?!
+
+logging.cpp(0): ERROR: test case THREW exception: 0
+ logged: someTests() returned: 42
+ this should be printed if an exception is thrown even if no assert has failed: 42
+ in a nested scope this should be printed as well: 42
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: a test case that will end from an exception and should print the unprinted context
+
+logging.cpp(0): ERROR: test case THREW exception: 0
+ logged: should be printed even if an exception is thrown and no assert fails before that
+
+===============================================================================
+stringification.cpp(0):
+TEST CASE: all asserts should fail and show how the objects get stringified
+
+stringification.cpp(0): ERROR: CHECK( f1 == f2 ) is NOT correct!
+ values: CHECK( Foo{} == Foo{} )
+
+stringification.cpp(0): ERROR: CHECK( dummy == "tralala" ) is NOT correct!
+ values: CHECK( omg == tralala )
+
+stringification.cpp(0): ERROR: CHECK( "tralala" == dummy ) is NOT correct!
+ values: CHECK( tralala == omg )
+
+stringification.cpp(0): ERROR: CHECK( vec1 == vec2 ) is NOT correct!
+ values: CHECK( [1, 2, 3] == [1, 2, 4] )
+
+stringification.cpp(0): ERROR: CHECK( lst_1 == lst_2 ) is NOT correct!
+ values: CHECK( [1, 42, 3, ] == [1, 2, 666, ] )
+
+stringification.cpp(0): ERROR: CHECK( s1 == s2 ) is NOT correct!
+ values: CHECK( MyOtherType: 42 == MyOtherType: 666 )
+ logged: s1=MyOtherType: 42 s2=MyOtherType: 666
+
+stringification.cpp(0): ERROR: CHECK( s1 == s2 ) is NOT correct!
+ values: CHECK( MyOtherType: 42 == MyOtherType: 666 )
+ logged: s1=MyOtherType: 42 s2=MyOtherType: 666
+ MyOtherType: 42 is not really MyOtherType: 666
+
+stringification.cpp(0): ERROR: CHECK( doctest::IsNaN<double>(0.5) ) is NOT correct!
+ values: CHECK( 0.5 )
+
+stringification.cpp(0): ERROR: CHECK( doctest::IsNaN<float>(std::numeric_limits<float>::infinity()) ) is NOT correct!
+ values: CHECK( inf )
+
+stringification.cpp(0): ERROR: CHECK( "a" == doctest::Contains("aaa") ) is NOT correct!
+ values: CHECK( a == Contains( aaa ) )
+
+stringification.cpp(0): ERROR: test case THREW exception: MyTypeInherited<int>(5, 4)
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: bad stringification of type pair<int_pair>
+
+templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
+ values: CHECK( 0 != 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: check return values
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+assertion_macros.cpp(0): MESSAGE: :D
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: check return values no print
+
+assertion_macros.cpp(0): ERROR: CHECK( a == b ) is NOT correct!
+ values: CHECK( 4 == 2 )
+
+assertion_macros.cpp(0): ERROR: CHECK_FALSE( a != b ) is NOT correct!
+ values: CHECK_FALSE( 4 != 2 )
+
+assertion_macros.cpp(0): ERROR: CHECK_EQ( a, b ) is NOT correct!
+ values: CHECK_EQ( 4, 2 )
+
+assertion_macros.cpp(0): ERROR: CHECK_UNARY( a == b ) is NOT correct!
+ values: CHECK_UNARY( false )
+
+assertion_macros.cpp(0): ERROR: CHECK_UNARY_FALSE( a != b ) is NOT correct!
+ values: CHECK_UNARY_FALSE( true )
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS( throw_if(false, false) ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(true, 2), doctest::Approx ) threw a DIFFERENT exception: "2"
+
+assertion_macros.cpp(0): ERROR: CHECK_NOTHROW( throw_if(true, 2) ) THREW exception: "2"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(true, 2), "1" ) threw a DIFFERENT exception: "2"
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: doesn't fail but it should have
+
+Should have failed but didn't! Marking it as failed!
+===============================================================================
+enums.cpp(0):
+TEST CASE: enum 2
+
+enums.cpp(0): ERROR: CHECK_EQ( Zero, 1 ) is NOT correct!
+ values: CHECK_EQ( 0, 1 )
+
+enums.cpp(0): ERROR: CHECK_EQ( One, 2 ) is NOT correct!
+ values: CHECK_EQ( 1, 2 )
+
+enums.cpp(0): ERROR: CHECK_EQ( Two, 3 ) is NOT correct!
+ values: CHECK_EQ( 2, 3 )
+
+enums.cpp(0): ERROR: CHECK_EQ( TypedZero, 1 ) is NOT correct!
+ values: CHECK_EQ( 0, 1 )
+
+enums.cpp(0): ERROR: CHECK_EQ( TypedOne, 2 ) is NOT correct!
+ values: CHECK_EQ( 1, 2 )
+
+enums.cpp(0): ERROR: CHECK_EQ( TypedTwo, 3 ) is NOT correct!
+ values: CHECK_EQ( 2, 3 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassC::Zero, EnumClassC::One ) is NOT correct!
+ values: CHECK_EQ( 48, 49 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassC::One, EnumClassC::Two ) is NOT correct!
+ values: CHECK_EQ( 49, 50 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassC::Two, EnumClassC::Zero ) is NOT correct!
+ values: CHECK_EQ( 50, 48 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassSC::Zero, EnumClassSC::One ) is NOT correct!
+ values: CHECK_EQ( 48, 49 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassSC::One, EnumClassSC::Two ) is NOT correct!
+ values: CHECK_EQ( 49, 50 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassSC::Two, EnumClassSC::Zero ) is NOT correct!
+ values: CHECK_EQ( 50, 48 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassUC::Zero, EnumClassUC::One ) is NOT correct!
+ values: CHECK_EQ( 48, 49 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassUC::One, EnumClassUC::Two ) is NOT correct!
+ values: CHECK_EQ( 49, 50 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassUC::Two, EnumClassUC::Zero ) is NOT correct!
+ values: CHECK_EQ( 50, 48 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassU8::Zero, EnumClassU8::One ) is NOT correct!
+ values: CHECK_EQ( 0, 1 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassU8::One, EnumClassU8::Two ) is NOT correct!
+ values: CHECK_EQ( 1, 2 )
+
+enums.cpp(0): ERROR: CHECK_EQ( EnumClassU8::Two, EnumClassU8::Zero ) is NOT correct!
+ values: CHECK_EQ( 2, 0 )
+
+Failed as expected so marking it as not failed
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: exceptions-related macros
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(true, 0), char ) threw a DIFFERENT exception: "0"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(false, 0), int ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(true, "whops!"), "whops! no match!" ) threw a DIFFERENT exception: "whops!"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(true, "whops! does it match?"), "whops! no match!" ) threw a DIFFERENT exception: "whops! does it match?"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, "whops!"), "whops! no match!", bool ) threw a DIFFERENT exception! (contents: "whops!")
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, "whops!"), "whops!", int ) threw a DIFFERENT exception! (contents: "whops!")
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, "whops! does it match?"), "whops! no match!", int ) threw a DIFFERENT exception! (contents: "whops! does it match?")
+
+assertion_macros.cpp(0): ERROR: CHECK_NOTHROW( throw_if(true, 0) ) THREW exception: "0"
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: exceptions-related macros for std::exception
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS( throw_if(false, 0) ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(false, std::runtime_error("whops!")), std::exception ) did NOT throw at all!
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_AS( throw_if(true, std::runtime_error("whops!")), int ) threw a DIFFERENT exception: "whops!"
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH( throw_if(false, ""), "whops!" ) did NOT throw at all!
+
+assertion_macros.cpp(0): FATAL ERROR: REQUIRE_NOTHROW( throw_if(true, std::runtime_error("whops!")) ) THREW exception: "whops!"
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: explicit failures 1
+
+logging.cpp(0): ERROR: this should not end the test case, but mark it as failing
+
+logging.cpp(0): MESSAGE: reached!
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: explicit failures 2
+
+logging.cpp(0): FATAL ERROR: fail the test case and also end it
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: fails - and its allowed
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+Allowed to fail so marking it as not failed
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: fails 1 time as it should
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+Failed exactly 1 times as expected so marking it as not failed!
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: fails as it should
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+Failed as expected so marking it as not failed
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+ level zero
+ one
+
+subcases.cpp(0): ERROR: CHECK( false ) is NOT correct!
+ values: CHECK( false )
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+ level zero
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ level zero
+ one
+
+subcases.cpp(0): ERROR: test case THREW exception: exception thrown in subcase - will translate later when the whole test case has been exited (cannot translate while there is an active exception)
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ level zero
+ one
+
+subcases.cpp(0): ERROR: test case THREW exception: failure... but the show must go on!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+ level zero
+ two
+
+subcases.cpp(0): ERROR: CHECK( false ) is NOT correct!
+ values: CHECK( false )
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+ level zero
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ level zero
+ two
+
+subcases.cpp(0): ERROR: test case THREW exception: exception thrown in subcase - will translate later when the whole test case has been exited (cannot translate while there is an active exception)
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: fails from an exception but gets re-entered to traverse all subcases
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ level zero
+ two
+
+subcases.cpp(0): ERROR: test case THREW exception: failure... but the show must go on!
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: regarding failures
+TEST SUITE: test suite with a description
+TEST CASE: fails more times than it should
+
+test_cases_and_suites.cpp(0): ERROR:
+
+test_cases_and_suites.cpp(0): ERROR:
+
+Didn't fail exactly 1 times so marking it as failed!
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST CASE: fixtured test - not part of a test suite
+
+test_cases_and_suites.cpp(0): ERROR: CHECK( data == 85 ) is NOT correct!
+ values: CHECK( 21 == 85 )
+
+===============================================================================
+header.h(0):
+TEST SUITE: some TS
+TEST CASE: in TS
+
+header.h(0): FATAL ERROR:
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: logging the counter of a loop
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 1 != 1 )
+ logged: current iteration of loop:
+ i := 0
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 2 != 2 )
+ logged: current iteration of loop:
+ i := 1
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 4 != 4 )
+ logged: current iteration of loop:
+ i := 2
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 8 != 8 )
+ logged: current iteration of loop:
+ i := 3
+
+logging.cpp(0): ERROR: CHECK( vec[i] != (1 << i) ) is NOT correct!
+ values: CHECK( 16 != 16 )
+ logged: current iteration of loop:
+ i := 4
+
+
+root
+1
+1.1
+
+root
+2
+2.1
+
+root
+2
+===============================================================================
+subcases.cpp(0):
+TEST CASE: lots of nested subcases
+
+subcases.cpp(0): FATAL ERROR:
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: multiple types<>
+
+templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
+ values: CHECK( 0 != 0 )
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: multiple types<>
+
+templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
+ values: CHECK( 0 != 0 )
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: multiple types<>
+
+templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
+ values: CHECK( 0 != 0 )
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: normal macros
+
+assertion_macros.cpp(0): ERROR: CHECK( throw_if(true, std::runtime_error("whops!")) == 42 ) THREW exception: "whops!"
+
+assertion_macros.cpp(0): ERROR: CHECK( doctest::Approx(0.502) == 0.501 ) is NOT correct!
+ values: CHECK( Approx( 0.502 ) == 0.501 )
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST SUITE: ts1
+TEST CASE: normal test in a test suite from a decorator
+
+test_cases_and_suites.cpp(0): MESSAGE: failing because of the timeout decorator!
+
+Test case exceeded time limit of 0.000001!
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST SUITE: scoped test suite
+TEST CASE: part of scoped
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST SUITE: scoped test suite
+TEST CASE: part of scoped 2
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST SUITE: some TS
+TEST CASE: part of some TS
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+TEST CASE: should fail because of an exception
+
+test_cases_and_suites.cpp(0): ERROR: test case THREW exception: 0
+
+===============================================================================
+assertion_macros.cpp(0):
+TEST CASE: some asserts used in a function called by a test case
+
+assertion_macros.cpp(0): ERROR: CHECK_THROWS_WITH_AS( throw_if(true, false), "unknown exception", int ) threw a DIFFERENT exception! (contents: "unknown exception")
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+ from function...
+
+subcases.cpp(0): MESSAGE: print me twice
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+ from function...
+ sc1
+
+subcases.cpp(0): MESSAGE: hello! from sc1
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ from function...
+ sc1
+
+subcases.cpp(0): MESSAGE: lala
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+ from function...
+
+subcases.cpp(0): MESSAGE: print me twice
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+ from function...
+ sc2
+
+subcases.cpp(0): MESSAGE: hello! from sc2
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases can be used in a separate function as well
+
+DEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):
+ from function...
+ sc2
+
+subcases.cpp(0): MESSAGE: lala
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ outer 0
+ inner 0
+
+subcases.cpp(0): MESSAGE: msg!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ outer 0
+ inner 1
+
+subcases.cpp(0): MESSAGE: msg!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ outer 1
+ inner 0
+
+subcases.cpp(0): MESSAGE: msg!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ outer 1
+ inner 1
+
+subcases.cpp(0): MESSAGE: msg!
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: subcases with changing names
+ separate
+
+subcases.cpp(0): MESSAGE: separate msg!
+
+===============================================================================
+header.h(0):
+TEST CASE: template 1<char>
+
+header.h(0): FATAL ERROR:
+
+===============================================================================
+header.h(0):
+TEST CASE: template 2<doctest::String>
+
+header.h(0): FATAL ERROR:
+
+===============================================================================
+subcases.cpp(0):
+TEST CASE: test case should fail even though the last subcase passes
+ one
+
+subcases.cpp(0): ERROR: CHECK( false ) is NOT correct!
+ values: CHECK( false )
+
+===============================================================================
+logging.cpp(0):
+TEST CASE: third party asserts can report failures to doctest
+
+logging.cpp(0): ERROR: MY_ASSERT(false)
+
+logging.cpp(0): FATAL ERROR: MY_ASSERT_FATAL(false)
+
+===============================================================================
+test_cases_and_suites.cpp(0):
+DESCRIPTION: this test has overridden its skip decorator
+TEST SUITE: skipped test cases
+TEST CASE: unskipped
+
+test_cases_and_suites.cpp(0): FATAL ERROR:
+
+===============================================================================
+templated_test_cases.cpp(0):
+TEST CASE: vector stuff<std::vector<int>>
+
+templated_test_cases.cpp(0): ERROR: CHECK( vec.size() == 20 ) is NOT correct!
+ values: CHECK( 10 == 20 )
+
+===============================================================================
+subcases.cpp(0):
+TEST SUITE: with a funny name,
+TEST CASE: with a funnier name\:
+ with the funniest name\,
+
+subcases.cpp(0): MESSAGE: Yes!
+
+===============================================================================
+subcases.cpp(0):
+TEST SUITE: with a funny name,
+TEST CASE: with a funnier name\:
+ with a slightly funny name :
+
+subcases.cpp(0): MESSAGE: Yep!
+
+===============================================================================
+subcases.cpp(0):
+TEST SUITE: with a funny name,
+TEST CASE: with a funnier name\:
+ without a funny name
+
+subcases.cpp(0): MESSAGE: NO!
+
+===============================================================================
+subcases.cpp(0):
+TEST SUITE: with a funny name,
+TEST CASE: without a funny name:
+
+subcases.cpp(0): MESSAGE: Nooo
+
+===============================================================================
+[doctest] test cases: 78 | 30 passed | 48 failed |
+[doctest] assertions: 213 | 99 passed | 114 failed |
+[doctest] Status: FAILURE!
+Program code.