diff --git a/README.md b/README.md index 294a7f0..c0a70f8 100644 --- a/README.md +++ b/README.md @@ -52,18 +52,24 @@ caff_freeInstance(&instance); Prereqs: -* Visual Studio 2017 (and [LLVM Compiler Toolchain Extension](https://marketplace.visualstudio.com/items?itemName=LLVMExtensions.llvm-toolchain)) -* LLVM toolchain +* [CMake](https://cmake.org/download/) +* [OBS dependencies](https://obsproject.com/downloads/dependencies2017.zip) - **TODO** This is only used for libcurl. We should use something else +* [Pre-built WebRTC](https://github.com/caffeinetv/webrtc/releases/latest) +* [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/) + * Select "Desktop C++ development with C++" + * Add the "C++ Clang tools for Windows" component Steps: -* Download the latest version of webrtc-prebuilt-windows.7z from https://github.com/caffeinetv/webrtc/releases -* Extract the file somewhere convenient -* Set `WEBRTC_ROOT_DIR` environment variable to the directory you extracted the files to +* Extract the OBS dependencies and prebuilt webrtc somewhere convenient +* Set `DepsPath` environment variable to the `win64` directory inside the OBS dependencies + * E.g. `C:\Users\Cogwheel\Desktop\obs-dependencies2017\win64` +* Set `WEBRTC_ROOT_DIR` environment variable to the directory you extracted prebuilt webrtc + * E.g. `C: * In the libcaffeine root directory: * `mkdir build` * `cd build` - * `cmake .. -G "Visual Studio 15 2017 Win64" -T LLVM` + * `cmake .. -G "Visual Studio 16 2019" -T ClangCL` * `start libcaffeine.sln` * Build the solution in Visual Studio diff --git a/appveyor.yml b/appveyor.yml index 87a1561..4d89528 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,17 +6,18 @@ matrix: environment: global: - CMAKE_SYSTEM_VERSION: 10.0.17134.0 + CMAKE_SYSTEM_VERSION: 10.0 CURL_VERSION: 7.56.1 LLVM_VERSION: 8.0.0 LIBYUV_GIT: "https://chromium.googlesource.com/libyuv/libyuv" matrix: - - APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017" - CMAKE_GENERATOR: "Visual Studio 15 2017 Win64" - CMAKE_TOOLSET: "LLVM" + - APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2019" + CMAKE_GENERATOR: "Visual Studio 16 2019" + CMAKE_TOOLSET: "ClangCL" WEBRTC_URL: "https://github.com/caffeinetv/webrtc/releases/download/v70.2-libcaffeine/webrtc-prebuilt-windows.7z" WEBRTC_PATH: .cache\\webrtc + #LLVM_EXTENSION: "https://llvmextensions.gallerycdn.vsassets.io/extensions/llvmextensions/llvm-toolchain/1.0.363769/1560930595399/llvm.vsix" # Used for libcurl only, should be replaced in the future by a proper C++ library. OBS_DEPENDENCIES_URL: "https://obsproject.com/downloads/dependencies2017.zip" OBS_DEPENDENCIES_ARCH: "win64" @@ -28,6 +29,12 @@ cache: - .cache/obs_deps.zip # Scripts + +init: + #- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +- ps: | + & 'C:\Users\appveyor\AppData\Local\Temp\vs_Community.exe' --wait --norestart --add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset --quiet + install: - cmd: ci/win/install.cmd diff --git a/tests/third_party/doctest/doctest.h b/tests/third_party/doctest/doctest.h index 9f004da..3c12557 100644 --- a/tests/third_party/doctest/doctest.h +++ b/tests/third_party/doctest/doctest.h @@ -48,8 +48,8 @@ #define DOCTEST_VERSION_MAJOR 2 #define DOCTEST_VERSION_MINOR 3 -#define DOCTEST_VERSION_PATCH 1 -#define DOCTEST_VERSION_STR "2.3.1" +#define DOCTEST_VERSION_PATCH 4 +#define DOCTEST_VERSION_STR "2.3.4" #define DOCTEST_VERSION \ (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) @@ -160,6 +160,8 @@ DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") DOCTEST_GCC_SUPPRESS_WARNING("-Winline") DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") +DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning @@ -225,7 +227,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom constr // GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html // MSVC version table: // https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering -// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) << NOT YET RELEASED - April 2 2019 +// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) // MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017) // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) // MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) @@ -350,6 +352,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom constr #define DOCTEST_GLOBAL_NO_WARNINGS(var) \ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \ static int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp) #define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP @@ -359,7 +362,9 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom constr #elif DOCTEST_MSVC #define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() #elif defined(__MINGW32__) +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wredundant-decls") extern "C" __declspec(dllimport) void __stdcall DebugBreak(); +DOCTEST_GCC_SUPPRESS_WARNING_POP #define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() #else // linux #define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0) @@ -373,6 +378,10 @@ extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #ifdef DOCTEST_CONFIG_USE_STD_HEADERS #include #include +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 +#include +#endif // VS 2019 #else // DOCTEST_CONFIG_USE_STD_HEADERS #if DOCTEST_CLANG @@ -391,7 +400,7 @@ extern "C" __declspec(dllimport) void __stdcall DebugBreak(); // Forward declaring 'X' in namespace std is not permitted by the C++ Standard. DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) -DOCTEST_STD_NAMESPACE_BEGIN +DOCTEST_STD_NAMESPACE_BEGIN // NOLINT (cert-dcl58-cpp) typedef decltype(nullptr) nullptr_t; template struct char_traits; @@ -402,6 +411,14 @@ class basic_ostream; typedef basic_ostream> ostream; template class tuple; +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 +template +class allocator; +template +class basic_string; +using string = basic_string, allocator>; +#endif // VS 2019 DOCTEST_STD_NAMESPACE_END DOCTEST_MSVC_SUPPRESS_WARNING_POP @@ -882,6 +899,11 @@ DOCTEST_INTERFACE String toString(int long long in); DOCTEST_INTERFACE String toString(int long long unsigned in); DOCTEST_INTERFACE String toString(std::nullptr_t in); +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 +DOCTEST_INTERFACE String toString(const std::string& in); +#endif // VS 2019 + class DOCTEST_INTERFACE Approx { public: @@ -993,6 +1015,10 @@ namespace detail { }; DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + [[noreturn]] +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS DOCTEST_INTERFACE void throwException(); struct DOCTEST_INTERFACE Subcase @@ -1279,6 +1305,9 @@ namespace detail { DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); DOCTEST_INTERFACE bool isDebuggerActive(); + template + int instantiationHelper(const T&) { return 0; } + namespace binaryAssertComparison { enum Enum { @@ -1293,7 +1322,7 @@ namespace detail { // clang-format off template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; - + #define DOCTEST_BINARY_RELATIONAL_OP(n, op) \ template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } }; // clang-format on @@ -1499,107 +1528,27 @@ namespace detail { DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in); DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in); - class DOCTEST_INTERFACE ContextBuilder - { - friend class ContextScope; - - struct DOCTEST_INTERFACE ICapture - { - DOCTEST_DELETE_COPIES(ICapture); - ICapture(); - virtual ~ICapture(); - virtual void toStream(std::ostream*) const = 0; - }; - - template - struct Capture : public ICapture //!OCLINT destructor of virtual class - { - const T* capture; - - explicit Capture(const T* in) - : capture(in) {} - void toStream(std::ostream* s) const override { detail::toStream(s, *capture); } - }; - - struct DOCTEST_INTERFACE Chunk - { - char buf[sizeof(Capture)] DOCTEST_ALIGNMENT( - 2 * sizeof(void*)); // place to construct a Capture - - DOCTEST_DECLARE_DEFAULTS(Chunk); - DOCTEST_DELETE_COPIES(Chunk); - }; - - struct DOCTEST_INTERFACE Node - { - Chunk chunk; - Node* next; - - DOCTEST_DECLARE_DEFAULTS(Node); - DOCTEST_DELETE_COPIES(Node); - }; - - Chunk stackChunks[DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK]; - int numCaptures = 0; - Node* head = nullptr; - Node* tail = nullptr; + // ContextScope base class used to allow implementing methods of ContextScope + // that don't depend on the template parameter in doctest.cpp. + class DOCTEST_INTERFACE ContextScopeBase : public IContextScope { + protected: + ContextScopeBase(); - ContextBuilder(ContextBuilder& other); - - ContextBuilder& operator=(const ContextBuilder&) = delete; - - void stringify(std::ostream* s) const; - - public: - ContextBuilder(); - ~ContextBuilder(); - - template - DOCTEST_NOINLINE ContextBuilder& operator<<(T& in) { - Capture temp(&in); - - // construct either on stack or on heap - // copy the bytes for the whole object - including the vtable because we cant construct - // the object directly in the buffer using placement new - need the header... - if(numCaptures < DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK) { - my_memcpy(stackChunks[numCaptures].buf, &temp, sizeof(Chunk)); - } else { - auto curr = new Node; - curr->next = nullptr; - if(tail) { - tail->next = curr; - tail = curr; - } else { - head = tail = curr; - } - - my_memcpy(tail->chunk.buf, &temp, sizeof(Chunk)); - } - ++numCaptures; - return *this; - } - - template - ContextBuilder& operator<<(const T&&) { - static_assert(deferred_false::value, - "Cannot pass temporaries or rvalues to the streaming operator because it " - "caches pointers to the passed objects for lazy evaluation!"); - return *this; - } + void destroy(); }; - class DOCTEST_INTERFACE ContextScope : public IContextScope + template class DOCTEST_INTERFACE ContextScope : public ContextScopeBase { - ContextBuilder contextBuilder; + const L &lambda_; public: - explicit ContextScope(ContextBuilder& temp); + explicit ContextScope(const L &lambda) : lambda_(lambda) {} - DOCTEST_DELETE_COPIES(ContextScope); + ContextScope(ContextScope &&other) : lambda_(other.lambda_) {} - ~ContextScope(); + void stringify(std::ostream* s) const override { lambda_(s); } - void stringify(std::ostream* s) const; + ~ContextScope() override { destroy(); } }; struct DOCTEST_INTERFACE MessageBuilder : public MessageData @@ -1621,6 +1570,11 @@ namespace detail { bool log(); void react(); }; + + template + ContextScope MakeContextScope(const L &lambda) { + return ContextScope(lambda); + } } // namespace detail #define DOCTEST_DEFINE_DECORATOR(name, type, def) \ @@ -1805,7 +1759,7 @@ struct DOCTEST_INTERFACE IReporter namespace detail { typedef IReporter* (*reporterCreatorFunc)(const ContextOptions&); - DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c); + DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c, bool isReporter); template IReporter* reporterCreator(const ContextOptions& o) { @@ -1814,8 +1768,8 @@ namespace detail { } // namespace detail template -int registerReporter(const char* name, int priority) { - detail::registerReporterImpl(name, priority, detail::reporterCreator); +int registerReporter(const char* name, int priority, bool isReporter) { + detail::registerReporterImpl(name, priority, detail::reporterCreator, isReporter); return 0; } } // namespace doctest @@ -1838,6 +1792,15 @@ int registerReporter(const char* name, int priority) { } catch(...) { _DOCTEST_RB.translateException(); } #endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(x) \ + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \ + static_cast(x); \ + DOCTEST_GCC_SUPPRESS_WARNING_POP +#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(x) x; +#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS + // registers the test by initializing a dummy var with a function #define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators) \ global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ @@ -1905,68 +1868,55 @@ int registerReporter(const char* name, int priority) { } \ typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -// for typed tests -#define DOCTEST_REGISTER_TYPED_TEST_CASE_IMPL(func, type, decorators, idx) \ - doctest::detail::regTest( \ - doctest::detail::TestCase(func, __FILE__, __LINE__, \ - doctest_detail_test_suite_ns::getCurrentTestSuite(), \ - doctest::detail::type_to_string(), idx) * \ - decorators) - #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \ template \ - inline void func(); \ - template \ - struct iter; \ - template \ - struct iter> \ - { \ - iter(int line, int index) { \ - DOCTEST_REGISTER_TYPED_TEST_CASE_IMPL(func, Type, dec, line * 1000 + index); \ - iter>(line, index + 1); \ - } \ - }; \ - template <> \ - struct iter> \ - { \ - iter(int, int) {} \ - }; \ + static void func(); \ + namespace { \ + template \ + struct iter; \ + template \ + struct iter> \ + { \ + iter(const char* file, unsigned line, int index) { \ + doctest::detail::regTest(doctest::detail::TestCase(func, file, line, \ + doctest_detail_test_suite_ns::getCurrentTestSuite(), \ + doctest::detail::type_to_string(), \ + int(line) * 1000 + index) \ + * dec); \ + iter>(file, line, index + 1); \ + } \ + }; \ + template <> \ + struct iter> \ + { \ + iter(const char*, unsigned, int) {} \ + }; \ + } \ template \ - inline void func() + static void func() #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id) \ DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR), \ DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) -#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE_IMPL(id, anon, ...) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = [] { \ - DOCTEST_CAT(id, ITERATOR)> DOCTEST_UNUSED DOCTEST_CAT( \ - anon, inner_dummy)(__LINE__, 0); \ - return 0; \ - }(); \ +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = \ + doctest::detail::instantiationHelper(DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0));\ DOCTEST_GLOBAL_NO_WARNINGS_END() #define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_INVOKE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -#define DOCTEST_TEST_CASE_TEMPLATE_APPLY_IMPL(id, anon, ...) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = [] { \ - DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__> DOCTEST_UNUSED DOCTEST_CAT(anon, inner_dummy)( \ - __LINE__, 0); \ - return 0; \ - }(); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() - #define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_APPLY_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \ typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) #define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...) \ DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon); \ - DOCTEST_TEST_CASE_TEMPLATE_INVOKE_IMPL(anon, anon, __VA_ARGS__) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>) \ template \ - inline void anon() + static void anon() #define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...) \ DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) @@ -2025,16 +1975,33 @@ int registerReporter(const char* name, int priority) { DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_), \ signature) -// for registering +// for registering reporters #define DOCTEST_REGISTER_REPORTER(name, priority, reporter) \ DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ - doctest::registerReporter(name, priority); \ + doctest::registerReporter(name, priority, true); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for registering listeners +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ + doctest::registerReporter(name, priority, false); \ DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) // for logging -#define DOCTEST_INFO(x) \ - doctest::detail::ContextScope DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_)( \ - doctest::detail::ContextBuilder() << x) +#define DOCTEST_INFO(expression) \ + DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \ + DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), expression) + +#define DOCTEST_INFO_IMPL(lambda_name, mb_name, s_name, expression) \ + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \ + auto lambda_name = [&](std::ostream* s_name) { \ + doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ + mb_name.m_stream = s_name; \ + mb_name << expression; \ + }; \ + 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_ADD_AT_IMPL(type, file, line, mb, x) \ @@ -2054,14 +2021,7 @@ int registerReporter(const char* name, int priority) { #define DOCTEST_FAIL_CHECK(x) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, x) #define DOCTEST_FAIL(x) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, x) -// hack for macros like INFO() that require lvalues -#if __cplusplus >= 201402L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 10, 0)) -template -constexpr T to_lvalue = x; -#define DOCTEST_TO_LVALUE(...) to_lvalue -#else // TO_LVALUE -#define DOCTEST_TO_LVALUE(...) TO_LVALUE_CAN_BE_USED_ONLY_IN_CPP14_MODE_OR_WITH_VS_2017_OR_NEWER -#endif // TO_LVALUE +#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility. #ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS @@ -2107,15 +2067,13 @@ constexpr T to_lvalue = x; #define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } while((void)0, 0) // clang-format on -#define DOCTEST_ASSERT_THROWS(expr, assert_type) DOCTEST_ASSERT_THROWS_WITH(expr, assert_type, "") - #define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, ...) \ do { \ if(!doctest::getContextOptions()->no_throw) { \ doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ __LINE__, #expr, #__VA_ARGS__); \ try { \ - expr; \ + DOCTEST_CAST_TO_VOID(expr) \ } catch(const doctest::detail::remove_const< \ doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) { \ _DOCTEST_RB.translateException(); \ @@ -2131,7 +2089,7 @@ constexpr T to_lvalue = x; doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ __LINE__, #expr, __VA_ARGS__); \ try { \ - expr; \ + DOCTEST_CAST_TO_VOID(expr) \ } catch(...) { _DOCTEST_RB.translateException(); } \ DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ } \ @@ -2142,15 +2100,15 @@ constexpr T to_lvalue = x; doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ __LINE__, #expr); \ try { \ - expr; \ + DOCTEST_CAST_TO_VOID(expr) \ } catch(...) { _DOCTEST_RB.translateException(); } \ DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ } while((void)0, 0) // clang-format off -#define DOCTEST_WARN_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_WARN_THROWS) -#define DOCTEST_CHECK_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_CHECK_THROWS) -#define DOCTEST_REQUIRE_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_REQUIRE_THROWS) +#define DOCTEST_WARN_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_WARN_THROWS, "") +#define DOCTEST_CHECK_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_CHECK_THROWS, "") +#define DOCTEST_REQUIRE_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_REQUIRE_THROWS, "") #define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, __VA_ARGS__) #define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, __VA_ARGS__) @@ -2379,6 +2337,7 @@ constexpr T to_lvalue = x; static inline doctest::String DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature) #define DOCTEST_REGISTER_REPORTER(name, priority, reporter) +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) #define DOCTEST_INFO(x) ((void)0) #define DOCTEST_CAPTURE(x) ((void)0) @@ -2495,11 +2454,11 @@ constexpr T to_lvalue = x; #define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) #define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(" Scenario: " name, T, id) -#define DOCTEST_GIVEN(name) SUBCASE(" Given: " name) -#define DOCTEST_WHEN(name) SUBCASE(" When: " name) -#define DOCTEST_AND_WHEN(name) SUBCASE("And when: " name) -#define DOCTEST_THEN(name) SUBCASE(" Then: " name) -#define DOCTEST_AND_THEN(name) SUBCASE(" And: " name) +#define DOCTEST_GIVEN(name) DOCTEST_SUBCASE(" Given: " name) +#define DOCTEST_WHEN(name) DOCTEST_SUBCASE(" When: " name) +#define DOCTEST_AND_WHEN(name) DOCTEST_SUBCASE("And when: " name) +#define DOCTEST_THEN(name) DOCTEST_SUBCASE(" Then: " name) +#define DOCTEST_AND_THEN(name) DOCTEST_SUBCASE(" And: " name) // clang-format on // == SHORT VERSIONS OF THE MACROS @@ -2519,6 +2478,7 @@ constexpr T to_lvalue = x; #define TEST_SUITE_END DOCTEST_TEST_SUITE_END #define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR #define REGISTER_REPORTER DOCTEST_REGISTER_REPORTER +#define REGISTER_LISTENER DOCTEST_REGISTER_LISTENER #define INFO DOCTEST_INFO #define CAPTURE DOCTEST_CAPTURE #define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT @@ -2673,13 +2633,18 @@ DOCTEST_GCC_SUPPRESS_WARNING_POP #endif // DOCTEST_SINGLE_HEADER #if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER) -#ifndef DOCTEST_LIBRARY_IMPLEMENTATION -#define DOCTEST_LIBRARY_IMPLEMENTATION #ifndef DOCTEST_SINGLE_HEADER #include "doctest_fwd.h" #endif // DOCTEST_SINGLE_HEADER +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros") + +#ifndef DOCTEST_LIBRARY_IMPLEMENTATION +#define DOCTEST_LIBRARY_IMPLEMENTATION + +DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") @@ -2722,6 +2687,9 @@ DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance") +DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute") DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning @@ -2797,9 +2765,6 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif // WIN32_LEAN_AND_MEAN -#ifndef VC_EXTRA_LEAN -#define VC_EXTRA_LEAN -#endif // VC_EXTRA_LEAN #ifndef NOMINMAX #define NOMINMAX #endif // NOMINMAX @@ -2911,7 +2876,7 @@ namespace detail { return oss.str().c_str(); } - DOCTEST_THREAD_LOCAL std::ostringstream g_oss; + DOCTEST_THREAD_LOCAL std::ostringstream g_oss; // NOLINT(cert-err58-cpp) std::ostream* getTlsOss() { g_oss.clear(); // there shouldn't be anything worth clearing in the flags @@ -3375,6 +3340,11 @@ DOCTEST_TO_STRING_OVERLOAD(int long long unsigned, "%llu") String toString(std::nullptr_t) { return "NULL"; } +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 +String toString(const std::string& in) { return in.c_str(); } +#endif // VS 2019 + Approx::Approx(double value) : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) , m_scale(1.0) @@ -3401,7 +3371,7 @@ Approx& Approx::scale(double newScale) { bool operator==(double lhs, const Approx& rhs) { // Thanks to Richard Harris for his help refining this formula return std::fabs(lhs - rhs.m_value) < - rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); + rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); } bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); } bool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); } @@ -3475,7 +3445,12 @@ namespace { // the int (priority) is part of the key for automatic sorting - sadly one can register a // reporter with a duplicate name and a different priority but hopefully that won't happen often :| typedef std::map, reporterCreatorFunc> reporterMap; - reporterMap& getReporters() { + + reporterMap& getReporters() { + static reporterMap data; + return data; + } + reporterMap& getListeners() { static reporterMap data; return data; } @@ -3500,11 +3475,11 @@ namespace detail { return false; } - void throwException() { #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - throw TestFailureException(); + [[noreturn]] void throwException() { throw TestFailureException(); } // NOLINT(cert-err60-cpp) +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + void throwException() {} #endif // DOCTEST_CONFIG_NO_EXCEPTIONS - } } // namespace detail namespace { @@ -3643,7 +3618,7 @@ namespace detail { const char* type, int template_id) { m_file = file; m_line = line; - m_name = nullptr; + m_name = nullptr; // will be later overridden in operator* m_test_suite = test_suite.m_test_suite; m_description = test_suite.m_description; m_skip = test_suite.m_skip; @@ -3836,6 +3811,7 @@ namespace { if(curr->translate(res)) return res; // clang-format off + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value") try { throw; } catch(std::exception& ex) { @@ -3847,6 +3823,7 @@ namespace { } catch(...) { return "unknown exception"; } + DOCTEST_GCC_SUPPRESS_WARNING_POP // clang-format on #else // DOCTEST_CONFIG_NO_EXCEPTIONS return ""; @@ -3929,64 +3906,17 @@ namespace detail { DOCTEST_THREAD_LOCAL std::vector g_infoContexts; // for logging with INFO() - ContextBuilder::ICapture::ICapture() = default; - ContextBuilder::ICapture::~ICapture() = default; - - ContextBuilder::Chunk::Chunk() = default; - ContextBuilder::Chunk::~Chunk() = default; - - ContextBuilder::Node::Node() = default; - ContextBuilder::Node::~Node() = default; - - // steal the contents of the other - acting as a move constructor... - ContextBuilder::ContextBuilder(ContextBuilder& other) - : numCaptures(other.numCaptures) - , head(other.head) - , tail(other.tail) { - other.numCaptures = 0; - other.head = nullptr; - other.tail = nullptr; - memcpy(stackChunks, other.stackChunks, - unsigned(int(sizeof(Chunk)) * DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK)); - } - - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcast-align") - void ContextBuilder::stringify(std::ostream* s) const { - int curr = 0; - // iterate over small buffer - while(curr < numCaptures && curr < DOCTEST_CONFIG_NUM_CAPTURES_ON_STACK) - reinterpret_cast(stackChunks[curr++].buf)->toStream(s); - // iterate over list - auto curr_elem = head; - while(curr < numCaptures) { - reinterpret_cast(curr_elem->chunk.buf)->toStream(s); - curr_elem = curr_elem->next; - ++curr; - } - } - DOCTEST_GCC_SUPPRESS_WARNING_POP - - ContextBuilder::ContextBuilder() = default; - - ContextBuilder::~ContextBuilder() { - // free the linked list - the ones on the stack are left as-is - // no destructors are called at all - there is no need - while(head) { - auto next = head->next; - delete head; - head = next; - } - } - - ContextScope::ContextScope(ContextBuilder& temp) - : contextBuilder(temp) { + ContextScopeBase::ContextScopeBase() { g_infoContexts.push_back(this); } DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - ContextScope::~ContextScope() { + // destroy cannot be inlined into the destructor because that would mean calling stringify after + // ContextScope has been destroyed (base class destructors run after derived class destructors). + // Instead, ContextScope calls this method directly from its destructor. + void ContextScopeBase::destroy() { if(std::uncaught_exception()) { std::ostringstream s; this->stringify(&s); @@ -3998,7 +3928,6 @@ namespace detail { DOCTEST_GCC_SUPPRESS_WARNING_POP DOCTEST_MSVC_SUPPRESS_WARNING_POP - void ContextScope::stringify(std::ostream* s) const { contextBuilder.stringify(s); } } // namespace detail namespace { using namespace detail; @@ -4166,7 +4095,7 @@ namespace { #define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text) #else // TODO: integration with XCode and other IDEs -#define DOCTEST_OUTPUT_DEBUG_STRING(text) +#define DOCTEST_OUTPUT_DEBUG_STRING(text) // NOLINT(clang-diagnostic-unused-macros) #endif // Platform void addAssert(assertType::Enum at) { @@ -4778,6 +4707,10 @@ namespace { void report_query(const QueryData& in) override { test_run_start(); if(opt.list_reporters) { + for(auto& curr : getListeners()) + xml.scopedElement("Listener") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); for(auto& curr : getReporters()) xml.scopedElement("Reporter") .writeAttribute("priority", curr.first.first) @@ -4862,16 +4795,21 @@ namespace { } void test_case_exception(const TestCaseException& e) override { + std::lock_guard lock(mutex); + xml.scopedElement("Exception") .writeAttribute("crash", e.is_crash) .writeText(e.error_string.c_str()); } void subcase_start(const SubcaseSignature& in) override { + std::lock_guard lock(mutex); + xml.startElement("SubCase") .writeAttribute("name", in.m_name) .writeAttribute("filename", skipPathFromFilename(in.m_file)) .writeAttribute("line", line(in.m_line)); + xml.ensureTagClosed(); } void subcase_end() override { xml.endElement(); } @@ -5154,10 +5092,16 @@ namespace { void printRegisteredReporters() { printVersion(); - s << Color::Cyan << "[doctest] " << Color::None << "listing all registered reporters\n"; - for(auto& curr : getReporters()) - s << "priority: " << std::setw(5) << curr.first.first - << " name: " << curr.first.second << "\n"; + auto printReporters = [this] (const reporterMap& reporters, const char* type) { + if(reporters.size()) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n"; + for(auto& curr : reporters) + s << "priority: " << std::setw(5) << curr.first.first + << " name: " << curr.first.second << "\n"; + } + }; + printReporters(getListeners(), "listeners"); + printReporters(getReporters(), "reporters"); } void list_query_results() { @@ -5287,7 +5231,7 @@ namespace { if(st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) { s << Color::Red << "Aborting - too many failed asserts!\n"; } - s << Color::None; + s << Color::None; // lgtm [cpp/useless-expression] } void test_case_exception(const TestCaseException& e) override { @@ -5303,20 +5247,22 @@ namespace { if(num_stringified_contexts) { auto stringified_contexts = get_stringified_contexts(); s << Color::None << " logged: "; - for(int i = num_stringified_contexts - 1; i >= 0; --i) { - s << (i == num_stringified_contexts - 1 ? "" : " ") - << stringified_contexts[i] << "\n"; + for(int i = num_stringified_contexts; i > 0; --i) { + s << (i == num_stringified_contexts ? "" : " ") + << stringified_contexts[i - 1] << "\n"; } } s << "\n" << Color::None; } void subcase_start(const SubcaseSignature& subc) override { + std::lock_guard lock(mutex); subcasesStack.push_back(subc); hasLoggedCurrentTestStart = false; } void subcase_end() override { + std::lock_guard lock(mutex); subcasesStack.pop_back(); hasLoggedCurrentTestStart = false; } @@ -5420,55 +5366,33 @@ namespace { DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss; #endif // DOCTEST_PLATFORM_WINDOWS - // the implementation of parseFlag() - bool parseFlagImpl(int argc, const char* const* argv, const char* pattern) { - for(int i = argc - 1; i >= 0; --i) { - auto temp = std::strstr(argv[i], pattern); - if(temp && strlen(temp) == strlen(pattern)) { - // eliminate strings in which the chars before the option are not '-' - bool noBadCharsFound = true; //!OCLINT prefer early exits and continue - while(temp != argv[i]) { - if(*--temp != '-') { - noBadCharsFound = false; - break; - } - } - if(noBadCharsFound && argv[i][0] == '-') - return true; - } - } - return false; - } - - // locates a flag on the command line - bool parseFlag(int argc, const char* const* argv, const char* pattern) { -#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - // offset (normally 3 for "dt-") to skip prefix - if(parseFlagImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX))) - return true; -#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - return parseFlagImpl(argc, argv, pattern); - } - // the implementation of parseOption() - bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String& res) { - for(int i = argc - 1; i >= 0; --i) { - auto temp = std::strstr(argv[i], pattern); - if(temp) { //!OCLINT prefer early exits and continue + bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) { + // going from the end to the begining and stopping on the first occurance from the end + for(int i = argc; i > 0; --i) { + auto index = i - 1; + auto temp = std::strstr(argv[index], pattern); + if(temp && (value || strlen(temp) == strlen(pattern))) { //!OCLINT prefer early exits and continue // eliminate matches in which the chars before the option are not '-' bool noBadCharsFound = true; - auto curr = argv[i]; + auto curr = argv[index]; while(curr != temp) { if(*curr++ != '-') { noBadCharsFound = false; break; } } - if(noBadCharsFound && argv[i][0] == '-') { - temp += strlen(pattern); - const unsigned len = strlen(temp); - if(len) { - res = temp; + if(noBadCharsFound && argv[index][0] == '-') { + if(value) { + // parsing the value of an option + temp += strlen(pattern); + const unsigned len = strlen(temp); + if(len) { + *value = temp; + return true; + } + } else { + // just a flag - no value return true; } } @@ -5478,22 +5402,28 @@ namespace { } // parses an option and returns the string after the '=' character - bool parseOption(int argc, const char* const* argv, const char* pattern, String& res, + bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr, const String& defaultVal = String()) { - res = defaultVal; + if(value) + *value = defaultVal; #ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS // offset (normally 3 for "dt-") to skip prefix - if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), res)) + if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value)) return true; #endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - return parseOptionImpl(argc, argv, pattern, res); + return parseOptionImpl(argc, argv, pattern, value); + } + + // locates a flag on the command line + bool parseFlag(int argc, const char* const* argv, const char* pattern) { + return parseOption(argc, argv, pattern); } // parses a comma separated list of words after a pattern in one of the arguments in argv bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, std::vector& res) { String filtersString; - if(parseOption(argc, argv, pattern, filtersString)) { + if(parseOption(argc, argv, pattern, &filtersString)) { // tokenize with "," as a separator // cppcheck-suppress strtokCalled DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") @@ -5521,7 +5451,7 @@ namespace { bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, int& res) { String parsedValue; - if(!parseOption(argc, argv, pattern, parsedValue)) + if(!parseOption(argc, argv, pattern, &parsedValue)) return false; if(type == 0) { @@ -5618,8 +5548,8 @@ void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { p->var = default #define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ - if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", strRes, default) || \ - parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", strRes, default) || \ + if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) || \ + parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) || \ withDefaults) \ p->var = strRes @@ -5763,8 +5693,6 @@ int Context::run() { return EXIT_SUCCESS; }; - DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter); - // setup default reporter if none is given through the command line if(p->filters[8].empty()) p->filters[8].push_back("console"); @@ -5775,6 +5703,12 @@ int Context::run() { p->reporters_currently_used.push_back(curr.second(*g_cs)); } + // TODO: check if there is nothing in reporters_currently_used + + // prepend all listeners + for(auto& curr : getListeners()) + p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs)); + #ifdef DOCTEST_PLATFORM_WINDOWS if(isDebuggerActive()) p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs)); @@ -5952,6 +5886,13 @@ int Context::run() { DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); } + // see these issues on the reasoning for this: + // - https://github.com/onqtam/doctest/issues/143#issuecomment-414418903 + // - https://github.com/onqtam/doctest/issues/126 + auto DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS = []() DOCTEST_NOINLINE + { std::cout << std::string(); }; + DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS(); + return cleanup_and_return(); } @@ -5972,16 +5913,14 @@ const String* IReporter::get_stringified_contexts() { } namespace detail { - void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c) { - getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) { + if(isReporter) + getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + else + getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); } } // namespace detail -// see these issues on the reasoning for this: -// - https://github.com/onqtam/doctest/issues/143#issuecomment-414418903 -// - https://github.com/onqtam/doctest/issues/126 -void DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS() { std::cout << std::string(); } - } // namespace doctest #endif // DOCTEST_CONFIG_DISABLE