This is an automated email from the ASF dual-hosted git repository.

jdanek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/main by this push:
     new 6cb1fd4  NO-JIRA upgrade doctest.h from 2.4.6 to 2.4.7
6cb1fd4 is described below

commit 6cb1fd4d783dcdb2841d81545cce421a1773ad81
Author: Jiri DanÄ›k <[email protected]>
AuthorDate: Wed Jan 5 12:41:06 2022 +0100

    NO-JIRA upgrade doctest.h from 2.4.6 to 2.4.7
---
 tests/c_unittests/doctest.h | 508 +++++++++++++++++++++++++++++---------------
 1 file changed, 339 insertions(+), 169 deletions(-)

diff --git a/tests/c_unittests/doctest.h b/tests/c_unittests/doctest.h
index 42eb039..cd5b44d 100644
--- a/tests/c_unittests/doctest.h
+++ b/tests/c_unittests/doctest.h
@@ -48,8 +48,8 @@
 
 #define DOCTEST_VERSION_MAJOR 2
 #define DOCTEST_VERSION_MINOR 4
-#define DOCTEST_VERSION_PATCH 6
-#define DOCTEST_VERSION_STR "2.4.6"
+#define DOCTEST_VERSION_PATCH 7
+#define DOCTEST_VERSION_STR "2.4.7"
 
 #define DOCTEST_VERSION                                                        
                    \
     (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + 
DOCTEST_VERSION_PATCH)
@@ -176,6 +176,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment 
operator was implicitly d
 DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined 
as deleted
 DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly 
defined as deleted
 DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is 
not thread-safe
+DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation for memory load
 // static analysis
 DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. 
Declare it 'noexcept'
 DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable
@@ -312,13 +313,29 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum 
class' over 'enum'
 #endif
 
 #ifndef DOCTEST_NORETURN
+#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
+#define DOCTEST_NORETURN
+#else // DOCTEST_MSVC
 #define DOCTEST_NORETURN [[noreturn]]
+#endif // DOCTEST_MSVC
 #endif // DOCTEST_NORETURN
 
 #ifndef DOCTEST_NOEXCEPT
+#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
+#define DOCTEST_NOEXCEPT
+#else // DOCTEST_MSVC
 #define DOCTEST_NOEXCEPT noexcept
+#endif // DOCTEST_MSVC
 #endif // DOCTEST_NOEXCEPT
 
+#ifndef DOCTEST_CONSTEXPR
+#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
+#define DOCTEST_CONSTEXPR const
+#else // DOCTEST_MSVC
+#define DOCTEST_CONSTEXPR constexpr
+#endif // DOCTEST_MSVC
+#endif // DOCTEST_CONSTEXPR
+
 // 
=================================================================================================
 // == FEATURE DETECTION END 
========================================================================
 // 
=================================================================================================
@@ -427,12 +444,14 @@ typedef basic_ostream<char, char_traits<char>> ostream;
 template <class... Types>
 class tuple;
 #if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
+DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wreserved-identifier")
 // see this issue on why this is needed: 
https://github.com/onqtam/doctest/issues/183
 template <class _Ty>
 class allocator;
 template <class _Elem, class _Traits, class _Alloc>
 class basic_string;
 using string = basic_string<char, char_traits<char>, allocator<char>>;
+DOCTEST_CLANG_SUPPRESS_WARNING_POP
 #endif // VS 2019
 DOCTEST_STD_NAMESPACE_END
 
@@ -504,7 +523,6 @@ public:
     String& operator=(const String& other);
 
     String& operator+=(const String& other);
-    String  operator+(const String& other) const;
 
     String(String&& other);
     String& operator=(String&& other);
@@ -527,6 +545,8 @@ public:
     int compare(const String& other, bool no_case = false) const;
 };
 
+DOCTEST_INTERFACE String operator+(const String& lhs, const String& rhs);
+
 DOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs);
 DOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs);
 DOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs);
@@ -723,9 +743,8 @@ namespace detail {
 
 struct ContextOptions //!OCLINT too many fields
 {
-    std::ostream* cout;        // stdout stream - std::cout by default
-    std::ostream* cerr;        // stderr stream - std::cerr by default
-    String        binary_name; // the test binary name
+    std::ostream* cout = nullptr; // stdout stream
+    String        binary_name;    // the test binary name
 
     const detail::TestCase* currentTest = nullptr;
 
@@ -744,9 +763,12 @@ struct ContextOptions //!OCLINT too many fields
     bool case_sensitive;       // if filtering should be case sensitive
     bool exit;                 // if the program should be exited after the 
tests are ran/whatever
     bool duration;             // print the time duration of each test case
+    bool minimal;              // minimal console output (only test failures)
+    bool quiet;                // no console output
     bool no_throw;             // to skip exceptions-related assertion macros
     bool no_exitcode;          // if the framework should return 0 as the 
exitcode
     bool no_run;               // to not run the tests at all (can be done 
with an "*" exclude)
+    bool no_intro;             // to not print the intro of the framework
     bool no_version;           // to not print the version of the framework
     bool no_colors;            // if output to the console should be colorized
     bool force_colors;         // forces the use of colors even when a tty 
cannot be detected
@@ -790,6 +812,9 @@ namespace detail {
     template<class T> struct is_lvalue_reference { const static bool 
value=false; };
     template<class T> struct is_lvalue_reference<T&> { const static bool 
value=true; };
 
+    template<class T> struct is_rvalue_reference { const static bool 
value=false; };
+    template<class T> struct is_rvalue_reference<T&&> { const static bool 
value=true; };
+
     template <class T>
     inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT
     {
@@ -811,7 +836,7 @@ namespace detail {
     template<class T> struct underlying_type : public std::underlying_type<T> 
{};
 #else
     // Use compiler intrinsics
-    template<class T> struct is_enum { constexpr static bool value = 
__is_enum(T); };
+    template<class T> struct is_enum { DOCTEST_CONSTEXPR static bool value = 
__is_enum(T); };
     template<class T> struct underlying_type { typedef __underlying_type(T) 
type; };
 #endif
     // clang-format on
@@ -828,12 +853,12 @@ namespace detail {
 
         template<class, class = void>
         struct check {
-            static constexpr bool value = false;
+            static DOCTEST_CONSTEXPR bool value = false;
         };
 
         template<class T>
         struct check<T, decltype(os() << val<T>(), void())> {
-            static constexpr bool value = true;
+            static DOCTEST_CONSTEXPR bool value = true;
         };
     } // namespace has_insertion_operator_impl
 
@@ -842,9 +867,10 @@ namespace detail {
 
     DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned 
num);
 
-    DOCTEST_INTERFACE std::ostream* getTlsOss(); // returns a thread-local 
ostringstream
+    DOCTEST_INTERFACE std::ostream* getTlsOss(bool reset=true); // returns a 
thread-local ostringstream
     DOCTEST_INTERFACE String getTlsOssResult();
 
+
     template <bool C>
     struct StringMakerBase
     {
@@ -854,12 +880,57 @@ namespace detail {
         }
     };
 
+    // Vector<int> and various type other than pointer or array.
+    template<typename T>
+    struct filldata
+    {
+        static void fill(const  T &in) {
+          *getTlsOss() << in;
+        }
+    };
+
+    /* This method can be chained */
+    template<typename T,unsigned long N>
+    void fillstream(const T (&in)[N] ) {
+        for(unsigned long i = 0; i < N; i++) {
+            *getTlsOss(false) << in[i];
+        }
+    }
+
+    template<typename T,unsigned long N>
+    struct filldata<T[N]>
+    {
+        static void fill(const T (&in)[N]) {
+                    fillstream(in);
+                    *getTlsOss(false)<<"";
+        }
+    };
+
+    template<typename T>
+    void filloss(const T& in){
+       filldata<T>::fill(in);
+    }
+
+    template<typename T,unsigned long N>
+    void filloss(const T (&in)[N]) {
+       // T[N], T(&)[N], T(&&)[N] have same behaviour.
+        // Hence remove reference.
+       filldata<typename remove_reference <decltype(in)>::type >::fill(in);
+    }
+
     template <>
     struct StringMakerBase<true>
     {
         template <typename T>
         static String convert(const DOCTEST_REF_WRAP(T) in) {
-            *getTlsOss() << in;
+            /* When parameter "in" is a null terminated const char* it works.
+            * When parameter "in" is a T arr[N] without '\0' we can fill the
+             * stringstream with N objects (T=char).If in is char pointer *
+             * without '\0' , it would cause segfault
+            * stepping over unaccessible memory.
+             */
+
+            filloss(in);
             return getTlsOssResult();
         }
     };
@@ -1079,12 +1150,21 @@ 
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
 // If not it doesn't find the operator or if the operator at global scope is 
defined after
 // this template, the template won't be instantiated due to SFINAE. Once the 
template is not
 // instantiated it can look for global operator using normal conversions.
-#define SFINAE_OP(ret,op) decltype(doctest::detail::declval<L>() op 
doctest::detail::declval<R>(),static_cast<ret>(0))
+#define SFINAE_OP(ret,op) decltype((void)(doctest::detail::declval<L>() op 
doctest::detail::declval<R>()),ret{})
 
 #define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro)          
                    \
     template <typename R>                                                      
                    \
-    DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& rhs) {             \
-           bool res = op_macro(doctest::detail::forward<L>(lhs), 
doctest::detail::forward<R>(rhs));                                              
               \
+    DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(const R&& rhs) {         
    \
+    bool res = op_macro(doctest::detail::forward<const L>(lhs), 
doctest::detail::forward<const R>(rhs));                                        
                     \
+        if(m_at & assertType::is_false)                                        
                    \
+            res = !res;                                                        
                    \
+        if(!res || doctest::getContextOptions()->success)                      
                    \
+            return Result(res, stringifyBinaryExpr(lhs, op_str, rhs));         
                    \
+        return Result(res);                                                    
                    \
+    }                                                                          
                   \
+    template <typename R ,typename enable_if<  
!doctest::detail::is_rvalue_reference<R>::value   , void >::type* = nullptr>    
                                     \
+    DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(const R& rhs) {          
   \
+    bool res = op_macro(doctest::detail::forward<const L>(lhs), 
doctest::detail::forward<const R>(rhs));                                        
                     \
         if(m_at & assertType::is_false)                                        
                    \
             res = !res;                                                        
                    \
         if(!res || doctest::getContextOptions()->success)                      
                    \
@@ -1092,6 +1172,7 @@ 
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
         return Result(res);                                                    
                    \
     }
 
+
     // more checks could be added - like in Catch:
     // https://github.com/catchorg/Catch2/pull/1480/files
     // https://github.com/catchorg/Catch2/pull/1481/files
@@ -1108,6 +1189,7 @@ 
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
         bool   m_passed;
         String m_decomp;
 
+        Result() = default;
         Result(bool passed, const String& decomposition = String());
 
         // forbidding some expressions based on this table: 
https://en.cppreference.com/w/cpp/language/operator_precedence
@@ -1217,7 +1299,7 @@ 
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
                 , m_at(at) {}
 
         DOCTEST_NOINLINE operator Result() {
-// this is needed only foc MSVC 2015:
+// this is needed only for MSVC 2015:
 // https://ci.appveyor.com/project/onqtam/doctest/builds/38181202
 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool
             bool res = static_cast<bool>(lhs);
@@ -1289,22 +1371,27 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
         // https://github.com/catchorg/Catch2/issues/870
         // https://github.com/catchorg/Catch2/issues/565
         template <typename L>
-       Expression_lhs<L> operator<<(L &&operand) {
-            return Expression_lhs<L>(doctest::detail::forward<L>(operand), 
m_at);
+       Expression_lhs<const L> operator<<(const L &&operand) {
+            return Expression_lhs<const L>(doctest::detail::forward<const 
L>(operand), m_at);
+        }
+
+        template <typename L,typename 
enable_if<!doctest::detail::is_rvalue_reference<L>::value,void >::type* = 
nullptr>
+       Expression_lhs<const L&> operator<<(const L &operand) {
+            return Expression_lhs<const L&>(operand, m_at);
         }
     };
 
     struct DOCTEST_INTERFACE TestSuite
     {
-        const char* m_test_suite;
-        const char* m_description;
-        bool        m_skip;
-        bool        m_no_breaks;
-        bool        m_no_output;
-        bool        m_may_fail;
-        bool        m_should_fail;
-        int         m_expected_failures;
-        double      m_timeout;
+        const char* m_test_suite = nullptr;
+        const char* m_description = nullptr;
+        bool        m_skip = false;
+        bool        m_no_breaks = false;
+        bool        m_no_output = false;
+        bool        m_may_fail = false;
+        bool        m_should_fail = false;
+        int         m_expected_failures = 0;
+        double      m_timeout = 0;
 
         TestSuite& operator*(const char* in);
 
@@ -1573,8 +1660,10 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
     class DOCTEST_INTERFACE ContextScopeBase : public IContextScope {
     protected:
         ContextScopeBase();
+        ContextScopeBase(ContextScopeBase&& other);
 
         void destroy();
+        bool need_to_destroy{true};
     };
 
     template <typename L> class ContextScope : public ContextScopeBase
@@ -1584,11 +1673,15 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
     public:
         explicit ContextScope(const L &lambda) : lambda_(lambda) {}
 
-        ContextScope(ContextScope &&other) : lambda_(other.lambda_) {}
+        ContextScope(ContextScope &&other) : 
ContextScopeBase(static_cast<ContextScopeBase&&>(other)), 
lambda_(other.lambda_) {}
 
         void stringify(std::ostream* s) const override { lambda_(s); }
 
-        ~ContextScope() override { destroy(); }
+        ~ContextScope() override {
+            if (need_to_destroy) {
+                destroy();
+            }
+        }
     };
 
     struct DOCTEST_INTERFACE MessageBuilder : public MessageData
@@ -1692,6 +1785,7 @@ public:
 
     void addFilter(const char* filter, const char* value);
     void clearFilters();
+    void setOption(const char* option, bool value);
     void setOption(const char* option, int value);
     void setOption(const char* option, const char* value);
 
@@ -1701,6 +1795,8 @@ public:
 
     void setAssertHandler(detail::assert_handler ah);
 
+    void setCout(std::ostream* out);
+
     int run();
 };
 
@@ -1727,6 +1823,7 @@ struct DOCTEST_INTERFACE CurrentTestCaseStats
     int    numAssertsFailedCurrentTest;
     double seconds;
     int    failure_flags; // use TestCaseFailureReason::Enum
+    bool   testCaseSuccess;
 };
 
 struct DOCTEST_INTERFACE TestCaseException
@@ -1835,7 +1932,7 @@ int registerReporter(const char* name, int priority, bool 
isReporter) {
 #define DOCTEST_WRAP_IN_TRY(x)                                                 
                    \
     try {                                                                      
                    \
         x;                                                                     
                    \
-    } catch(...) { _DOCTEST_RB.translateException(); }
+    } catch(...) { DOCTEST_RB.translateException(); }
 #endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
 
 #ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS
@@ -1849,7 +1946,7 @@ int registerReporter(const char* name, int priority, bool 
isReporter) {
 
 // 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_)) =             
 \
+    global_prefix 
DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_)) =              
 \
             doctest::detail::regTest(                                          
                    \
                     doctest::detail::TestCase(                                 
                    \
                             f, __FILE__, __LINE__,                             
                    \
@@ -1878,18 +1975,18 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
 
 #define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators)    
                    \
     static doctest::detail::funcType proxy() { return f; }                     
                    \
-    DOCTEST_REGISTER_FUNCTION(inline const, proxy(), decorators)               
                    \
+    DOCTEST_REGISTER_FUNCTION(inline, proxy(), decorators)                     
              \
     static void f()
 
 // for registering tests
 #define DOCTEST_TEST_CASE(decorators)                                          
                    \
-    
DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), 
decorators)
+    
DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), 
decorators)
 
 // for registering tests in classes - requires C++17 for inline variables!
 #if __cplusplus >= 201703L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 12, 0) && 
_MSVC_LANG >= 201703L)
 #define DOCTEST_TEST_CASE_CLASS(decorators)                                    
                    \
-    
DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_),
          \
-                                                  
DOCTEST_ANONYMOUS(_DOCTEST_ANON_PROXY_),         \
+    
DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_),
           \
+                                                  
DOCTEST_ANONYMOUS(DOCTEST_ANON_PROXY_),          \
                                                   decorators)
 #else // DOCTEST_TEST_CASE_CLASS
 #define DOCTEST_TEST_CASE_CLASS(...)                                           
                    \
@@ -1898,8 +1995,8 @@ int registerReporter(const char* name, int priority, bool 
isReporter) {
 
 // for registering tests with a fixture
 #define DOCTEST_TEST_CASE_FIXTURE(c, decorators)                               
                    \
-    DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c,      
                    \
-                              DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), 
decorators)
+    DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), c,       
                    \
+                              DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), 
decorators)
 
 // for converting types to strings without the <typeinfo> header and demangling
 #define DOCTEST_TYPE_TO_STRING_IMPL(...)                                       
                    \
@@ -1912,7 +2009,7 @@ int registerReporter(const char* name, int priority, bool 
isReporter) {
             DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__)                           
                    \
         }                                                                      
                    \
     }                                                                          
                    \
-    typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 
 #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func)             
                    \
     template <typename T>                                                      
                    \
@@ -1943,7 +2040,7 @@ int registerReporter(const char* name, int priority, bool 
isReporter) {
 
 #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_))
+                                           
DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_))
 
 #define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...)             
                    \
     DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) =                     
                    \
@@ -1951,12 +2048,12 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
     DOCTEST_GLOBAL_NO_WARNINGS_END()
 
 #define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...)                             
                    \
-    DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \
-    typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    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(id, ...)                              
                    \
-    DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \
-    typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    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);             \
@@ -1965,11 +2062,11 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
     static void anon()
 
 #define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...)                                
                    \
-    DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__)
+    DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, 
DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__)
 
 // for subcases
 #define DOCTEST_SUBCASE(name)                                                  
                    \
-    if(const doctest::detail::Subcase & 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \
+    if(const doctest::detail::Subcase & 
DOCTEST_ANONYMOUS(DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED =  \
                doctest::detail::Subcase(name, __FILE__, __LINE__))
 
 // for grouping tests in test suites by using code blocks
@@ -1995,53 +2092,56 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
     namespace ns_name
 
 #define DOCTEST_TEST_SUITE(decorators)                                         
                    \
-    DOCTEST_TEST_SUITE_IMPL(decorators, 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_))
+    DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(DOCTEST_ANON_SUITE_))
 
 // for starting a testsuite block
 #define DOCTEST_TEST_SUITE_BEGIN(decorators)                                   
                    \
-    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) =        
                    \
+    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_)) =         
                    \
             doctest::detail::setTestSuite(doctest::detail::TestSuite() * 
decorators);              \
     DOCTEST_GLOBAL_NO_WARNINGS_END()                                           
                    \
-    typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 
 // for ending a testsuite block
 #define DOCTEST_TEST_SUITE_END                                                 
                    \
-    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) =        
                    \
+    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_)) =         
                    \
             doctest::detail::setTestSuite(doctest::detail::TestSuite() * "");  
                    \
     DOCTEST_GLOBAL_NO_WARNINGS_END()                                           
                    \
-    typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 
 // for registering exception translators
 #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature)  
                    \
     inline doctest::String translatorName(signature);                          
                    \
-    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)) = 
                    \
+    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_)) =  
                    \
             doctest::registerExceptionTranslator(translatorName);              
                    \
     DOCTEST_GLOBAL_NO_WARNINGS_END()                                           
                    \
     doctest::String translatorName(signature)
 
 #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)                       
                    \
-    
DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_),
       \
+    
DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_),
        \
                                                signature)
 
 // for registering reporters
 #define DOCTEST_REGISTER_REPORTER(name, priority, reporter)                    
                    \
-    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) =   
                    \
+    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_)) =    
                    \
             doctest::registerReporter<reporter>(name, priority, true);         
                    \
-    DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    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_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_)) =    
                    \
             doctest::registerReporter<reporter>(name, priority, false);        
                    \
-    DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int 
DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 
-// for logging
+// clang-format off
+// for logging - disabling formatting because it's important to have these on 
2 separate lines - see PR #557
 #define DOCTEST_INFO(...)                                                      
                    \
-    DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), 
DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_),  \
+    DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_),                     
                    \
+                      DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_OTHER_),               
                    \
                       __VA_ARGS__)
+// clang-format on
 
 #define DOCTEST_INFO_IMPL(mb_name, s_name, ...)                                
       \
-    auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = 
doctest::detail::MakeContextScope(                 \
+    auto DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_) = 
doctest::detail::MakeContextScope(                  \
         [&](std::ostream* s_name) {                                            
                    \
         doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, 
doctest::assertType::is_warn); \
         mb_name.m_stream = s_name;                                             
                    \
@@ -2058,9 +2158,9 @@ int registerReporter(const char* name, int priority, bool 
isReporter) {
     } while(false)
 
 // clang-format off
-#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, 
file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__)
-#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) 
DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), 
__VA_ARGS__)
-#define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, 
file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__)
+#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, 
file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__)
+#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) 
DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), 
__VA_ARGS__)
+#define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, 
file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__)
 // clang-format on
 
 #define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, 
__VA_ARGS__)
@@ -2073,12 +2173,12 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
 
 #define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...)                           
                    \
     
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses")   
               \
-    doctest::detail::ResultBuilder 
_DOCTEST_RB(doctest::assertType::assert_type, __FILE__,         \
+    doctest::detail::ResultBuilder 
DOCTEST_RB(doctest::assertType::assert_type, __FILE__,          \
                                                __LINE__, #__VA_ARGS__);        
                    \
-    DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.setResult(                                 
                    \
+    DOCTEST_WRAP_IN_TRY(DOCTEST_RB.setResult(                                  
                    \
             
doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type)         
       \
             << __VA_ARGS__))                                                   
                    \
-    DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB)                                  
                    \
+    DOCTEST_ASSERT_LOG_AND_REACT(DOCTEST_RB)                                   
                    \
     DOCTEST_CLANG_SUPPRESS_WARNING_POP
 
 #define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...)                           
                    \
@@ -2119,39 +2219,39 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
 #define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...)              
                    \
     do {                                                                       
                    \
         if(!doctest::getContextOptions()->no_throw) {                          
                    \
-            doctest::detail::ResultBuilder 
_DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \
+            doctest::detail::ResultBuilder 
DOCTEST_RB(doctest::assertType::assert_type, __FILE__,  \
                                                        __LINE__, #expr, 
#__VA_ARGS__, message);    \
             try {                                                              
                    \
                 DOCTEST_CAST_TO_VOID(expr)                                     
                    \
             } catch(const typename doctest::detail::remove_const<              
                    \
                     typename 
doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) {       \
-                _DOCTEST_RB.translateException();                              
                    \
-                _DOCTEST_RB.m_threw_as = true;                                 
                    \
-            } catch(...) { _DOCTEST_RB.translateException(); }                 
                    \
-            DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                         
                    \
+                DOCTEST_RB.translateException();                               
                    \
+                DOCTEST_RB.m_threw_as = true;                                  
                    \
+            } catch(...) { DOCTEST_RB.translateException(); }                  
                    \
+            DOCTEST_ASSERT_LOG_AND_REACT(DOCTEST_RB);                          
                    \
         }                                                                      
                    \
     } while(false)
 
 #define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...)           
                    \
     do {                                                                       
                    \
         if(!doctest::getContextOptions()->no_throw) {                          
                    \
-            doctest::detail::ResultBuilder 
_DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \
+            doctest::detail::ResultBuilder 
DOCTEST_RB(doctest::assertType::assert_type, __FILE__,  \
                                                        __LINE__, expr_str, "", 
__VA_ARGS__);       \
             try {                                                              
                    \
                 DOCTEST_CAST_TO_VOID(expr)                                     
                    \
-            } catch(...) { _DOCTEST_RB.translateException(); }                 
                    \
-            DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                         
                    \
+            } catch(...) { DOCTEST_RB.translateException(); }                  
                    \
+            DOCTEST_ASSERT_LOG_AND_REACT(DOCTEST_RB);                          
                    \
         }                                                                      
                    \
     } while(false)
 
 #define DOCTEST_ASSERT_NOTHROW(assert_type, ...)                               
                    \
     do {                                                                       
                    \
-        doctest::detail::ResultBuilder 
_DOCTEST_RB(doctest::assertType::assert_type, __FILE__,     \
+        doctest::detail::ResultBuilder 
DOCTEST_RB(doctest::assertType::assert_type, __FILE__,      \
                                                    __LINE__, #__VA_ARGS__);    
                    \
         try {                                                                  
                    \
             DOCTEST_CAST_TO_VOID(__VA_ARGS__)                                  
                    \
-        } catch(...) { _DOCTEST_RB.translateException(); }                     
                    \
-        DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                             
                    \
+        } catch(...) { DOCTEST_RB.translateException(); }                      
                    \
+        DOCTEST_ASSERT_LOG_AND_REACT(DOCTEST_RB);                              
                    \
     } while(false)
 
 // clang-format off
@@ -2196,20 +2296,20 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
 
 #define DOCTEST_BINARY_ASSERT(assert_type, comp, ...)                          
                    \
     do {                                                                       
                    \
-        doctest::detail::ResultBuilder 
_DOCTEST_RB(doctest::assertType::assert_type, __FILE__,     \
+        doctest::detail::ResultBuilder 
DOCTEST_RB(doctest::assertType::assert_type, __FILE__,      \
                                                    __LINE__, #__VA_ARGS__);    
                    \
         DOCTEST_WRAP_IN_TRY(                                                   
                    \
-                
_DOCTEST_RB.binary_assert<doctest::detail::binaryAssertComparison::comp>(       
   \
+                
DOCTEST_RB.binary_assert<doctest::detail::binaryAssertComparison::comp>(        
   \
                         __VA_ARGS__))                                          
                    \
-        DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                             
                    \
+        DOCTEST_ASSERT_LOG_AND_REACT(DOCTEST_RB);                              
                    \
     } while(false)
 
 #define DOCTEST_UNARY_ASSERT(assert_type, ...)                                 
                    \
     do {                                                                       
                    \
-        doctest::detail::ResultBuilder 
_DOCTEST_RB(doctest::assertType::assert_type, __FILE__,     \
+        doctest::detail::ResultBuilder 
DOCTEST_RB(doctest::assertType::assert_type, __FILE__,      \
                                                    __LINE__, #__VA_ARGS__);    
                    \
-        DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(__VA_ARGS__))             
                    \
-        DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB);                             
                    \
+        DOCTEST_WRAP_IN_TRY(DOCTEST_RB.unary_assert(__VA_ARGS__))              
                    \
+        DOCTEST_ASSERT_LOG_AND_REACT(DOCTEST_RB);                              
                    \
     } while(false)
 
 #else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS
@@ -2358,35 +2458,35 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
 
 // for registering tests
 #define DOCTEST_TEST_CASE(name)                                                
                    \
-    
DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), 
name)
+    
DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), 
name)
 
 // for registering tests in classes
 #define DOCTEST_TEST_CASE_CLASS(name)                                          
                    \
-    
DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), 
name)
+    
DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), 
name)
 
 // for registering tests with a fixture
 #define DOCTEST_TEST_CASE_FIXTURE(x, name)                                     
                    \
-    DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x,      
                    \
-                              DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name)
+    DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), x,       
                    \
+                              DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name)
 
 // for converting types to strings without the <typeinfo> header and demangling
-#define DOCTEST_TYPE_TO_STRING(...) typedef int 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+#define DOCTEST_TYPE_TO_STRING(...) typedef int 
DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 #define DOCTEST_TYPE_TO_STRING_IMPL(...)
 
 // for typed tests
 #define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...)                            
                    \
     template <typename type>                                                   
                    \
-    inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)()
+    inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)()
 
 #define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id)                      
                    \
     template <typename type>                                                   
                    \
-    inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)()
+    inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)()
 
 #define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...)                             
                    \
-    typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 
 #define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...)                              
                    \
-    typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+    typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 
 // for subcases
 #define DOCTEST_SUBCASE(name)
@@ -2395,14 +2495,14 @@ int registerReporter(const char* name, int priority, 
bool isReporter) {
 #define DOCTEST_TEST_SUITE(name) namespace
 
 // for starting a testsuite block
-#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int 
DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 
 // for ending a testsuite block
-#define DOCTEST_TEST_SUITE_END typedef int 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
+#define DOCTEST_TEST_SUITE_END typedef int 
DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)
 
 #define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)                       
                    \
     template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                           
                    \
-    static inline doctest::String 
DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature)
+    static inline doctest::String 
DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_)(signature)
 
 #define DOCTEST_REGISTER_REPORTER(name, priority, reporter)
 #define DOCTEST_REGISTER_LISTENER(name, priority, reporter)
@@ -2792,6 +2892,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment 
operator was implicitly d
 DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined 
as deleted
 DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined 
as deleted
 DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' 
(performance warning)
+DOCTEST_MSVC_SUPPRESS_WARNING(5245) // unreferenced function with internal 
linkage has been removed
 // static analysis
 DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. 
Declare it 'noexcept'
 DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable
@@ -2885,8 +2986,12 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
 #endif
 
 #ifndef DOCTEST_THREAD_LOCAL
+#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
+#define DOCTEST_THREAD_LOCAL
+#else // DOCTEST_MSVC
 #define DOCTEST_THREAD_LOCAL thread_local
-#endif
+#endif // DOCTEST_MSVC
+#endif // DOCTEST_THREAD_LOCAL
 
 #ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES
 #define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32
@@ -2906,6 +3011,10 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
 #define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
 #endif
 
+#ifndef DOCTEST_CDECL
+#define DOCTEST_CDECL __cdecl
+#endif
+
 namespace doctest {
 
 bool is_running_in_test = false;
@@ -2975,10 +3084,13 @@ namespace detail {
 
     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
-        g_oss.str(""); // the slow way of resetting a string stream
-        //g_oss.seekp(0); // optimal reset - as seen here: 
https://stackoverflow.com/a/624291/3162383
+    //reset default value is true. getTlsOss(bool reset=true);
+    std::ostream* getTlsOss(bool reset) {
+        if(reset) {
+          g_oss.clear(); // there shouldn't be anything worth clearing in the 
flags
+          g_oss.str(""); // the slow way of resetting a string stream
+          //g_oss.seekp(0); // optimal reset - as seen here: 
https://stackoverflow.com/a/624291/3162383
+       }
         return &g_oss;
     }
 
@@ -3088,7 +3200,7 @@ typedef timer_large_integer::type ticks_t;
             return result;
         }
 
-        T operator=(T desired) DOCTEST_NOEXCEPT {
+        T operator=(T desired) DOCTEST_NOEXCEPT { // lgtm 
[cpp/assignment-does-not-return-this]
             store(desired);
             return desired;
         }
@@ -3103,7 +3215,7 @@ typedef timer_large_integer::type ticks_t;
 
     private:
         // Each thread has a different atomic that it operates on. If more 
than NumLanes threads
-        // use this, some will use the same atomic. So performance will 
degrate a bit, but still
+        // use this, some will use the same atomic. So performance will 
degrade a bit, but still
         // everything will work.
         //
         // The logic here is a bit tricky. The call should be as fast as 
possible, so that there
@@ -3198,7 +3310,8 @@ typedef timer_large_integer::type ticks_t;
                               (TestCaseFailureReason::FailedExactlyNumTimes & 
failure_flags);
 
             // if any subcase has failed - the whole test case has failed
-            if(failure_flags && !ok_to_fail)
+            testCaseSuccess = !(failure_flags && !ok_to_fail);
+            if(!testCaseSuccess)
                 numTestCasesFailed++;
         }
     };
@@ -3323,9 +3436,6 @@ String& String::operator+=(const String& other) {
     return *this;
 }
 
-// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
-String String::operator+(const String& other) const { return String(*this) += 
other; }
-
 String::String(String&& other) {
     using namespace std;
     memcpy(buf, other.buf, len);
@@ -3379,6 +3489,9 @@ int String::compare(const String& other, bool no_case) 
const {
     return compare(other.c_str(), no_case);
 }
 
+// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
+String operator+(const String& lhs, const String& rhs) { return  String(lhs) 
+= rhs; }
+
 // clang-format off
 bool operator==(const String& lhs, const String& rhs) { return 
lhs.compare(rhs) == 0; }
 bool operator!=(const String& lhs, const String& rhs) { return 
lhs.compare(rhs) != 0; }
@@ -3581,7 +3694,7 @@ bool operator>(const Approx& lhs, double rhs) { return 
lhs.m_value > rhs && lhs
 
 String toString(const Approx& in) {
     // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
-    return String("Approx( ") + doctest::toString(in.m_value) + " )";
+    return "Approx( " + doctest::toString(in.m_value) + " )";
 }
 const ContextOptions* getContextOptions() { return 
DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); }
 
@@ -3594,11 +3707,13 @@ Context::~Context() = default;
 void Context::applyCommandLine(int, const char* const*) {}
 void Context::addFilter(const char*, const char*) {}
 void Context::clearFilters() {}
+void Context::setOption(const char*, bool) {}
 void Context::setOption(const char*, int) {}
 void Context::setOption(const char*, const char*) {}
 bool Context::shouldExit() { return false; }
 void Context::setAsDefaultForAssertsOutOfTestCases() {}
 void Context::setAssertHandler(detail::assert_handler) {}
+void Context::setCout(std::ostream* out) {}
 int  Context::run() { return 0; }
 
 IReporter::~IReporter() = default;
@@ -3812,15 +3927,6 @@ namespace detail {
 
     TestSuite& TestSuite::operator*(const char* in) {
         m_test_suite = in;
-        // clear state
-        m_description       = nullptr;
-        m_skip              = false;
-        m_no_breaks         = false;
-        m_no_output         = false;
-        m_may_fail          = false;
-        m_should_fail       = false;
-        m_expected_failures = 0;
-        m_timeout           = 0;
         return *this;
     }
 
@@ -3929,12 +4035,12 @@ namespace {
     HANDLE g_stdoutHandle;
     WORD   g_origFgAttrs;
     WORD   g_origBgAttrs;
-    bool   g_attrsInitted = false;
+    bool   g_attrsInited = false;
 
     int colors_init() {
-        if(!g_attrsInitted) {
+        if(!g_attrsInited) {
             g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
-            g_attrsInitted = true;
+            g_attrsInited = true;
             CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
             GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo);
             g_origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | 
BACKGROUND_RED |
@@ -3945,7 +4051,7 @@ namespace {
         return 0;
     }
 
-    int dumy_init_console_colors = colors_init();
+    int dummy_init_console_colors = colors_init();
 #endif // DOCTEST_CONFIG_COLORS_WINDOWS
 
     DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
@@ -3981,7 +4087,7 @@ namespace {
 
 #ifdef DOCTEST_CONFIG_COLORS_WINDOWS
         if(g_no_colors ||
-           (isatty(fileno(stdout)) == false && 
getContextOptions()->force_colors == false))
+           (_isatty(_fileno(stdout)) == false && 
getContextOptions()->force_colors == false))
             return;
 
 #define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(g_stdoutHandle, x | 
g_origBgAttrs)
@@ -4145,6 +4251,14 @@ namespace detail {
         g_infoContexts.push_back(this);
     }
 
+    ContextScopeBase::ContextScopeBase(ContextScopeBase&& other) {
+        if (other.need_to_destroy) {
+            other.destroy();
+        }
+        other.need_to_destroy = false;
+        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")
@@ -4313,7 +4427,7 @@ namespace {
         static unsigned int prev_abort_behavior;
         static int          prev_report_mode;
         static _HFILE       prev_report_file;
-        static void (*prev_sigabrt_handler)(int);
+        static void (DOCTEST_CDECL *prev_sigabrt_handler)(int);
         static std::terminate_handler original_terminate_handler;
         static bool isSet;
         static ULONG guaranteeSize;
@@ -4325,7 +4439,7 @@ namespace {
     unsigned int FatalConditionHandler::prev_abort_behavior;
     int          FatalConditionHandler::prev_report_mode;
     _HFILE       FatalConditionHandler::prev_report_file;
-    void (*FatalConditionHandler::prev_sigabrt_handler)(int);
+    void (DOCTEST_CDECL *FatalConditionHandler::prev_sigabrt_handler)(int);
     std::terminate_handler FatalConditionHandler::original_terminate_handler;
     bool FatalConditionHandler::isSet = false;
     ULONG FatalConditionHandler::guaranteeSize = 0;
@@ -4498,7 +4612,7 @@ namespace detail {
         }
 
         if(m_exception.size())
-            m_exception = String("\"") + m_exception + "\"";
+            m_exception = "\"" + m_exception + "\"";
 
         if(is_running_in_test) {
             addAssert(m_at);
@@ -5054,7 +5168,8 @@ namespace {
                     xml.scopedElement("TestCase").writeAttribute("name", 
in.data[i]->m_name)
                         .writeAttribute("testsuite", in.data[i]->m_test_suite)
                         .writeAttribute("filename", 
skipPathFromFilename(in.data[i]->m_file.c_str()))
-                        .writeAttribute("line", line(in.data[i]->m_line));
+                        .writeAttribute("line", line(in.data[i]->m_line))
+                        .writeAttribute("skipped", in.data[i]->m_skip);
                 }
                 xml.scopedElement("OverallResultsTestCases")
                         .writeAttribute("unskipped", 
in.run_stats->numTestCasesPassingFilters);
@@ -5124,7 +5239,8 @@ namespace {
             xml.startElement("OverallResultsAsserts")
                     .writeAttribute("successes",
                                     st.numAssertsCurrentTest - 
st.numAssertsFailedCurrentTest)
-                    .writeAttribute("failures", 
st.numAssertsFailedCurrentTest);
+                    .writeAttribute("failures", st.numAssertsFailedCurrentTest)
+                    .writeAttribute("test_case_success", st.testCaseSuccess);
             if(opt.duration)
                 xml.writeAttribute("duration", st.seconds);
             if(tc->m_expected_failures)
@@ -5143,8 +5259,6 @@ namespace {
         }
 
         void subcase_start(const SubcaseSignature& in) override {
-            std::lock_guard<std::mutex> lock(mutex);
-
             xml.startElement("SubCase")
                     .writeAttribute("name", in.m_name)
                     .writeAttribute("filename", 
skipPathFromFilename(in.m_file))
@@ -5440,7 +5554,6 @@ namespace {
         }
 
         void subcase_start(const SubcaseSignature& in) override {
-            std::lock_guard<std::mutex> lock(mutex);
             deepestSubcaseStackNames.push_back(in.m_name);
         }
 
@@ -5606,9 +5719,11 @@ namespace {
         }
 
         void printIntro() {
-            printVersion();
-            s << Color::Cyan << "[doctest] " << Color::None
-              << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for 
options\n";
+            if(opt.no_intro == false) {
+                printVersion();
+                s << Color::Cyan << "[doctest] " << Color::None
+                  << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" 
for options\n";
+            }
         }
 
         void printHelp() {
@@ -5693,12 +5808,18 @@ namespace {
               << Whitespace(sizePrefixDisplay*1) << "exits after the tests 
finish\n";
             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d,   --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "duration=<bool>               "
               << Whitespace(sizePrefixDisplay*1) << "prints the time duration 
of each test\n";
+            s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "m,   --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "minimal=<bool>                "
+              << Whitespace(sizePrefixDisplay*1) << "minimal console output 
(only failures)\n";
+            s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "q,   --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "quiet=<bool>                  "
+              << Whitespace(sizePrefixDisplay*1) << "no console output\n";
             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt,  --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw=<bool>               "
               << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related 
assert checks\n";
             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne,  --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode=<bool>            "
               << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always 
with success\n";
             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr,  --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run=<bool>                 "
               << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest 
operations\n";
+            s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ni,  --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "no-intro=<bool>               "
+              << Whitespace(sizePrefixDisplay*1) << "omit the framework intro 
in the output\n";
             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv,  --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version=<bool>             "
               << Whitespace(sizePrefixDisplay*1) << "omit the framework 
version in the output\n";
             s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc,  --" 
DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors=<bool>              "
@@ -5736,22 +5857,6 @@ namespace {
             printReporters(getReporters(), "reporters");
         }
 
-        void list_query_results() {
-            separator_to_stream();
-            if(opt.count || opt.list_test_cases) {
-                s << Color::Cyan << "[doctest] " << Color::None
-                  << "unskipped test cases passing the current filters: "
-                  << g_cs->numTestCasesPassingFilters << "\n";
-            } else if(opt.list_test_suites) {
-                s << Color::Cyan << "[doctest] " << Color::None
-                  << "unskipped test cases passing the current filters: "
-                  << g_cs->numTestCasesPassingFilters << "\n";
-                s << Color::Cyan << "[doctest] " << Color::None
-                  << "test suites with unskipped test cases passing the 
current filters: "
-                  << g_cs->numTestSuitesPassingFilters << "\n";
-            }
-        }
-
         // 
=========================================================================================
         // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER 
INTERFACE
         // 
=========================================================================================
@@ -5797,9 +5902,15 @@ namespace {
             }
         }
 
-        void test_run_start() override { printIntro(); }
+        void test_run_start() override {
+            if(!opt.minimal)
+                printIntro();
+        }
 
         void test_run_end(const TestRunStats& p) override {
+            if(opt.minimal && p.numTestCasesFailed == 0)
+                return;
+
             separator_to_stream();
             s << std::dec;
 
@@ -5880,6 +5991,7 @@ namespace {
         }
 
         void test_case_exception(const TestCaseException& e) override {
+            std::lock_guard<std::mutex> lock(mutex);
             if(tc->m_no_output)
                 return;
 
@@ -5904,14 +6016,12 @@ namespace {
         }
 
         void subcase_start(const SubcaseSignature& subc) override {
-            std::lock_guard<std::mutex> lock(mutex);
             subcasesStack.push_back(subc);
             ++currentSubcaseLevel;
             hasLoggedCurrentTestStart = false;
         }
 
         void subcase_end() override {
-            std::lock_guard<std::mutex> lock(mutex);
             --currentSubcaseLevel;
             hasLoggedCurrentTestStart = false;
         }
@@ -6047,18 +6157,42 @@ namespace {
                            std::vector<String>& res) {
         String filtersString;
         if(parseOption(argc, argv, pattern, &filtersString)) {
-            // tokenize with "," as a separator
-            // cppcheck-suppress strtokCalled
-            
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
-            auto pch = std::strtok(filtersString.c_str(), ","); // modifies 
the string
-            while(pch != nullptr) {
-                if(strlen(pch))
-                    res.push_back(pch);
-                // uses the strtok() internal state to go to the next token
-                // cppcheck-suppress strtokCalled
-                pch = std::strtok(nullptr, ",");
+            // tokenize with "," as a separator, unless escaped with backslash
+            std::ostringstream s;
+            auto flush = [&s, &res]() {
+                auto string = s.str();
+                if(string.size() > 0) {
+                    res.push_back(string.c_str());
+                }
+                s.str("");
+            };
+
+            bool seenBackslash = false;
+            const char* current = filtersString.c_str();
+            const char* end = current + strlen(current);
+            while(current != end) {
+                char character = *current++;
+                if(seenBackslash) {
+                    seenBackslash = false;
+                    if(character == ',') {
+                        s.put(',');
+                        continue;
+                    }
+                    s.put('\\');
+                }
+                if(character == '\\') {
+                    seenBackslash = true;
+                } else if(character == ',') {
+                    flush();
+                } else {
+                    s.put(character);
+                }
+            }
+
+            if(seenBackslash) {
+                s.put('\\');
             }
-            DOCTEST_CLANG_SUPPRESS_WARNING_POP
+            flush();
             return true;
         }
         return false;
@@ -6191,9 +6325,12 @@ void Context::parseArgs(int argc, const char* const* 
argv, bool withDefaults) {
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, 
false);
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false);
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false);
+    DOCTEST_PARSE_AS_BOOL_OR_FLAG("minimal", "m", minimal, false);
+    DOCTEST_PARSE_AS_BOOL_OR_FLAG("quiet", "q", quiet, false);
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false);
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false);
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false);
+    DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-intro", "ni", no_intro, false);
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false);
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false);
     DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false);
@@ -6257,7 +6394,12 @@ void Context::clearFilters() {
         curr.clear();
 }
 
-// allows the user to override procedurally the int/bool options from the 
command line
+// allows the user to override procedurally the bool options from the command 
line
+void Context::setOption(const char* option, bool value) {
+    setOption(option, value ? "true" : "false");
+}
+
+// allows the user to override procedurally the int options from the command 
line
 void Context::setOption(const char* option, int value) {
     setOption(option, toString(value).c_str());
     // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
@@ -6277,6 +6419,31 @@ void Context::setAsDefaultForAssertsOutOfTestCases() { 
g_cs = p; }
 
 void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; }
 
+void Context::setCout(std::ostream* out) { p->cout = out; }
+
+static class DiscardOStream : public std::ostream
+{
+private:
+    class : public std::streambuf
+    {
+    private:
+        // allowing some buffering decreases the amount of calls to overflow
+        char buf[1024];
+
+    protected:
+        std::streamsize xsputn(const char_type*, std::streamsize count) 
override { return count; }
+
+        int_type overflow(int_type ch) override {
+            setp(std::begin(buf), std::end(buf));
+            return traits_type::not_eof(ch);
+        }
+    } discardBuf;
+
+public:
+    DiscardOStream()
+            : std::ostream(&discardBuf) {}
+} discardOut;
+
 // the main function that does all the filtering and test running
 int Context::run() {
     using namespace detail;
@@ -6290,15 +6457,18 @@ int Context::run() {
     g_no_colors = p->no_colors;
     p->resetRunData();
 
-    // stdout by default
-    p->cout = &std::cout;
-    p->cerr = &std::cerr;
-
-    // or to a file if specified
     std::fstream fstr;
-    if(p->out.size()) {
-        fstr.open(p->out.c_str(), std::fstream::out);
-        p->cout = &fstr;
+    if(p->cout == nullptr) {
+        if(p->quiet) {
+            p->cout = &discardOut;
+        } else if(p->out.size()) {
+            // to a file if specified
+            fstr.open(p->out.c_str(), std::fstream::out);
+            p->cout = &fstr;
+        } else {
+            // stdout by default
+            p->cout = &std::cout;
+        }
     }
 
     FatalConditionHandler::allocateAltStackMem();

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to