Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/onqtam/doctest.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan <29021710+Saalvage@users.noreply.github.com>2022-04-28 03:47:24 +0300
committerGitHub <noreply@github.com>2022-04-28 03:47:24 +0300
commite8ba771d4b4cf90cb99e011ef01059dd6533d39c (patch)
treef035dbd7d8e6f6e918a4da3182f5cb44f2890ac7
parenteb8b04a2b1db23ea5665cd8b5cbe859beb0ef80d (diff)
Refactor stringification (#585)
* matcher-like nan check * Remove superfluous extern template declarations * Add explicit template parameters * Correct template instantiation * Fix test includes * class -> struct * Correctly instantiate * Oops * Try fix interface * Add MinGW exception * Add info regarding interface decl and def * Adjust docs * Remove accidental paste in comment * First draft * operator<< => StringStream (for now) * Forward declare cstr output operator * Remove unnecessary String constructor * Port more stuff to streams * Remove std::string stringification (it was broken anyways) * Remove anonymous namespace for the time being * Revert "Remove anonymous namespace for the time being" This reverts commit ec2819c44bdb647546108d29b135720083ded48c. * Move toStream to prevent disabling * Restore customization points * Remove superfluous const char* catcher * Merge branch 'dev' into fix-string * Better IsNaN stringification * Reset doctest * We're getting somewhere! * size_t -> unsigned long * Fix nullptr handling * Why is it selecting the template over the overload?? * Reduce template count * Forward declare cstr output operator (again) * Fix pointer stringification * Add flag that forces custom stringification methods to be provided (#595) * Add flag that forces custom stringification methods to be provided * Add docs * Add IsNaN operator! (#603) * Add IsNaN operator! * Docs * More concise impl * Optimized floating point stringification * Remove float stringification override * unsigned long -> size_t where appropriate * Automatic type stringification with optional overrides * Fix type stringification * Add manual short override to fix tests * Add tests * insertion fix? * Make operator<< static * Clean up fake type traits * Try fix stl warnings * Reintroduce deferred_false * Work around dumb VS15 shit * Oops * Yet another MSVS2015 workaround * Fix #618 * Doing ungodly things to make MSVS2015 work * Oops * rerun tests * Rerun tests * Fix #618 by removing string_view * Remove incorrect restrictions on <string> inclusion * Add String::EMPTY * Replace String::EMPTY with static EMPTY_STRING in order to avoid SIOF * Revert "Add String::EMPTY" This reverts commit 8856a220596398f27e11a031cedda352f067cbf8. Revert "Replace String::EMPTY with static EMPTY_STRING in order to avoid SIOF" This reverts commit 83d3c4f45dde09038d13e77379ea3b40843ce37f.
-rw-r--r--doc/markdown/assertions.md2
-rw-r--r--doc/markdown/configuration.md7
-rw-r--r--doctest/doctest.h704
-rw-r--r--doctest/parts/doctest.cpp192
-rw-r--r--doctest/parts/doctest_fwd.h509
-rw-r--r--examples/all_features/header.h1
-rw-r--r--examples/all_features/stringification.cpp100
-rw-r--r--examples/all_features/templated_test_cases.cpp6
-rw-r--r--examples/all_features/test_output/coverage_maxout.cpp.txt24
-rw-r--r--examples/all_features/test_output/coverage_maxout.cpp_junit.txt44
-rw-r--r--examples/all_features/test_output/coverage_maxout.cpp_xml.txt58
-rw-r--r--examples/all_features/test_output/filter_2_xml.txt14
-rw-r--r--examples/all_features/test_output/stringification.cpp.txt63
-rw-r--r--examples/all_features/test_output/stringification.cpp_junit.txt51
-rw-r--r--examples/all_features/test_output/stringification.cpp_xml.txt140
-rw-r--r--examples/all_features/test_output/templated_test_cases.cpp.txt6
-rw-r--r--examples/all_features/test_output/templated_test_cases.cpp_junit.txt10
-rw-r--r--examples/all_features/test_output/templated_test_cases.cpp_xml.txt10
-rw-r--r--examples/executable_dll_and_plugin/dll.cpp1
-rw-r--r--examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin.txt11
-rw-r--r--examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_junit.txt11
-rw-r--r--examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_xml.txt14
-rw-r--r--scripts/coverage_maxout.cpp55
23 files changed, 1030 insertions, 1003 deletions
diff --git a/doc/markdown/assertions.md b/doc/markdown/assertions.md
index ef908fb8..41d90a46 100644
--- a/doc/markdown/assertions.md
+++ b/doc/markdown/assertions.md
@@ -176,6 +176,8 @@ CHECK(std::isnan(performComputation()); // does not capture the result of the ca
CHECK(doctest::IsNaN(performComputation()); // captures the result!
```
+`IsNaN` is able to capture the value, even if negated via `!`.
+
--------
- Check out the [**example**](../../examples/all_features/assertion_macros.cpp) which shows many of these macros
diff --git a/doc/markdown/configuration.md b/doc/markdown/configuration.md
index de1c4b3e..6b340f2c 100644
--- a/doc/markdown/configuration.md
+++ b/doc/markdown/configuration.md
@@ -12,6 +12,7 @@ Defining something ```globally``` means for every source file of the binary (exe
- [**```DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL```**](#doctest_config_implementation_in_dll)
- [**```DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES```**](#doctest_config_no_short_macro_names)
- [**```DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING```**](#doctest_config_treat_char_star_as_string)
+- [**```DOCTEST_CONFIG_REQUIRE_STRINGIFICATION_FOR_ALL_USED_TYPES```**](#doctest_config_require_stringification_for_all_used_types)
- [**```DOCTEST_CONFIG_SUPER_FAST_ASSERTS```**](#doctest_config_super_fast_asserts)
- [**```DOCTEST_CONFIG_USE_STD_HEADERS```**](#doctest_config_use_std_headers)
- [**```DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS```**](#doctest_config_void_cast_expressions)
@@ -82,6 +83,12 @@ By default ```char*``` is being treated as a pointer. With this option comparing
This should be defined globally.
+### **```DOCTEST_CONFIG_REQUIRE_STRINGIFICATION_FOR_ALL_USED_TYPES```**
+
+By default if stringification is not available for a type, it is simply printed as `{?}`. By enabling this flag, whenever a type is used in an assert that does not provide stringification, the compilation is stopped.
+
+This can be defined both globally and in specific source files only.
+
### **```DOCTEST_CONFIG_SUPER_FAST_ASSERTS```**
This config option makes the assert macros (except for those dealing with exceptions) compile [**much faster**](benchmarks.md#cost-of-an-assertion-macro)! (31-91% - depending on the type - [**normal**](assertions.md#expression-decomposing-asserts) or [**binary**](assertions.md#binary-and-unary-asserts))
diff --git a/doctest/doctest.h b/doctest/doctest.h
index efe5877f..7a756876 100644
--- a/doctest/doctest.h
+++ b/doctest/doctest.h
@@ -68,6 +68,12 @@
// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect
+#ifdef _MSC_VER
+#define DOCTEST_CPLUSPLUS _MSVC_LANG
+#else
+#define DOCTEST_CPLUSPLUS __cplusplus
+#endif
+
#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH))
// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl...
@@ -367,8 +373,10 @@ DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly define
#ifndef DOCTEST_CONSTEXPR
#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
#define DOCTEST_CONSTEXPR const
+#define DOCTEST_CONSTEXPR_FUNC inline
#else // DOCTEST_MSVC
#define DOCTEST_CONSTEXPR constexpr
+#define DOCTEST_CONSTEXPR_FUNC constexpr
#endif // DOCTEST_MSVC
#endif // DOCTEST_CONSTEXPR
@@ -475,6 +483,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643)
namespace std { // NOLINT (cert-dcl58-cpp)
typedef decltype(nullptr) nullptr_t;
+typedef decltype(sizeof(void*)) size_t;
template <class charT>
struct char_traits;
template <>
@@ -482,6 +491,8 @@ struct char_traits<char>;
template <class charT, class traits>
class basic_ostream;
typedef basic_ostream<char, char_traits<char>> ostream;
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, const char*);
template <class charT, class traits>
class basic_istream;
typedef basic_istream<char, char_traits<char>> istream;
@@ -507,8 +518,14 @@ DOCTEST_MSVC_SUPPRESS_WARNING_POP
namespace doctest {
+using std::size_t;
+
DOCTEST_INTERFACE extern bool is_running_in_test;
+#ifndef DOCTEST_CONFIG_STRING_SIZE_TYPE
+#define DOCTEST_CONFIG_STRING_SIZE_TYPE unsigned
+#endif
+
// A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length
// of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for:
// - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128)
@@ -521,7 +538,6 @@ DOCTEST_INTERFACE extern bool is_running_in_test;
// TODO:
// - optimizations - like not deleting memory unnecessarily in operator= and etc.
// - resize/reserve/clear
-// - substr
// - replace
// - back/front
// - iterator stuff
@@ -531,14 +547,18 @@ DOCTEST_INTERFACE extern bool is_running_in_test;
// - relational operators as free functions - taking const char* as one of the params
class DOCTEST_INTERFACE String
{
- static const unsigned len = 24; //!OCLINT avoid private static members
- static const unsigned last = len - 1; //!OCLINT avoid private static members
+public:
+ using size_type = DOCTEST_CONFIG_STRING_SIZE_TYPE;
+
+private:
+ static DOCTEST_CONSTEXPR size_type len = 24; //!OCLINT avoid private static members
+ static DOCTEST_CONSTEXPR size_type last = len - 1; //!OCLINT avoid private static members
struct view // len should be more than sizeof(view) - because of the final byte for flags
{
char* ptr;
- unsigned size;
- unsigned capacity;
+ size_type size;
+ size_type capacity;
};
union
@@ -547,23 +567,26 @@ class DOCTEST_INTERFACE String
view data;
};
- char* allocate(unsigned sz);
+ char* allocate(size_type sz);
bool isOnStack() const { return (buf[last] & 128) == 0; }
void setOnHeap();
- void setLast(unsigned in = last);
+ void setLast(size_type in = last);
+ void setSize(size_type sz);
void copy(const String& other);
public:
+ static DOCTEST_CONSTEXPR size_type npos = static_cast<size_type>(-1);
+
String();
~String();
// cppcheck-suppress noExplicitConstructor
String(const char* in);
- String(const char* in, unsigned in_size);
+ String(const char* in, size_type in_size);
- String(std::istream& in, unsigned in_size);
+ String(std::istream& in, size_type in_size);
String(const String& other);
String& operator=(const String& other);
@@ -573,8 +596,8 @@ public:
String(String&& other);
String& operator=(String&& other);
- char operator[](unsigned i) const;
- char& operator[](unsigned i);
+ char operator[](size_type i) const;
+ char& operator[](size_type i);
// the only functions I'm willing to leave in the interface - available for inlining
const char* c_str() const { return const_cast<String*>(this)->c_str(); } // NOLINT
@@ -584,11 +607,19 @@ public:
return data.ptr;
}
- unsigned size() const;
- unsigned capacity() const;
+ size_type size() const;
+ size_type capacity() const;
+
+ String substr(size_type pos, size_type len = npos) &&;
+ String substr(size_type pos, size_type len = npos) const &;
+
+ size_type find(char ch, size_type pos = 0) const;
+ size_type rfind(char ch, size_type pos = npos) const;
int compare(const char* other, bool no_case = false) const;
int compare(const String& other, bool no_case = false) const;
+
+friend DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in);
};
DOCTEST_INTERFACE String operator+(const String& lhs, const String& rhs);
@@ -600,8 +631,6 @@ 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);
-DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in);
-
class DOCTEST_INTERFACE Contains {
public:
explicit Contains(const String& string);
@@ -871,200 +900,173 @@ struct ContextOptions //!OCLINT too many fields
};
namespace detail {
- template <bool CONDITION, typename TYPE = void>
- struct enable_if
- {};
+ namespace types {
+#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
+ using namespace std;
+#else
+ template <bool COND, typename T = void>
+ struct enable_if { };
- template <typename TYPE>
- struct enable_if<true, TYPE>
- { typedef TYPE type; };
+ template <typename T>
+ struct enable_if<true, T> { using type = T; };
- // clang-format off
- template<class T> struct remove_reference { typedef T type; };
- template<class T> struct remove_reference<T&> { typedef T type; };
- template<class T> struct remove_reference<T&&> { typedef T type; };
+ struct true_type { static DOCTEST_CONSTEXPR bool value = true; };
+ struct false_type { static DOCTEST_CONSTEXPR bool value = false; };
+
+ template <typename T> struct remove_reference { using type = T; };
+ template <typename T> struct remove_reference<T&> { using type = T; };
+ template <typename T> struct remove_reference<T&&> { using type = T; };
- template<typename T, typename U = T&&> U declval(int);
+ template <typename T> struct is_rvalue_reference : false_type { };
+ template <typename T> struct is_rvalue_reference<T&&> : true_type { };
- template<typename T> T declval(long);
+ template<typename T> struct remove_const { using type = T; };
+ template <typename T> struct remove_const<const T> { using type = T; };
- template<typename T> auto declval() DOCTEST_NOEXCEPT -> decltype(declval<T>(0)) ;
+ // Compiler intrinsics
+ template <typename T> struct is_enum { DOCTEST_CONSTEXPR static bool value = __is_enum(T); };
+ template <typename T> struct underlying_type { using type = __underlying_type(T); };
- 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 <typename T> struct is_pointer : false_type { };
+ template <typename T> struct is_pointer<T*> : true_type { };
- 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 <typename T> struct is_array : false_type { };
+ template <typename T, size_t SIZE> struct is_array<T[SIZE]> : true_type { };
+#endif
+ }
+
+ // <utility>
+ template <typename T>
+ T&& declval();
template <class T>
- inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT
- {
+ DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference<T>::type& t) DOCTEST_NOEXCEPT {
return static_cast<T&&>(t);
}
template <class T>
- inline T&& forward(typename remove_reference<T>::type&& t) DOCTEST_NOEXCEPT
- {
- static_assert(!is_lvalue_reference<T>::value,
- "Can not forward an rvalue as an lvalue.");
+ DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference<T>::type&& t) DOCTEST_NOEXCEPT {
return static_cast<T&&>(t);
}
- template<class T> struct remove_const { typedef T type; };
- template<class T> struct remove_const<const T> { typedef T type; };
-#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
- template<class T> struct is_enum : public std::is_enum<T> {};
- template<class T> struct underlying_type : public std::underlying_type<T> {};
-#else
- // Use compiler intrinsics
- 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
+ template <typename T>
+ struct deferred_false : types::false_type { };
+
+// MSVS 2015 :(
+#if defined(_MSC_VER) && _MSC_VER <= 1900
+ template <typename T, typename = void>
+ struct has_global_insertion_operator : types::false_type { };
template <typename T>
- struct deferred_false
- // cppcheck-suppress unusedStructMember
- { static const bool value = false; };
-
- namespace has_insertion_operator_impl {
- std::ostream &os();
- template<class T>
- DOCTEST_REF_WRAP(T) val();
-
- template<class, class = void>
- struct check {
- static DOCTEST_CONSTEXPR bool value = false;
- };
+ struct has_global_insertion_operator<T, decltype(::operator<<(declval<std::ostream&>(), declval<const T&>()), void())> : types::true_type { };
- template<class T>
- struct check<T, decltype(os() << val<T>(), void())> {
- static DOCTEST_CONSTEXPR bool value = true;
- };
- } // namespace has_insertion_operator_impl
+ template <typename T, typename = void>
+ struct has_insertion_operator { static DOCTEST_CONSTEXPR bool value = has_global_insertion_operator<T>::value; };
+
+ template <typename T, bool global>
+ struct insert_hack;
+
+ template <typename T>
+ struct insert_hack<T, true> {
+ static void insert(std::ostream& os, const T& t) { ::operator<<(os, t); }
+ };
- template<class T>
- using has_insertion_operator = has_insertion_operator_impl::check<const T>;
+ template <typename T>
+ struct insert_hack<T, false> {
+ static void insert(std::ostream& os, const T& t) { operator<<(os, t); }
+ };
+
+ template <typename T>
+ using insert_hack_t = insert_hack<T, has_global_insertion_operator<T>::value>;
+#else
+ template <typename T, typename = void>
+ struct has_insertion_operator : types::false_type { };
+#endif
+
+template <typename T>
+struct has_insertion_operator<T, decltype(operator<<(declval<std::ostream&>(), declval<const T&>()), void())> : types::true_type { };
DOCTEST_INTERFACE std::ostream* tlssPush();
DOCTEST_INTERFACE String tlssPop();
-
template <bool C>
- struct StringMakerBase
- {
+ struct StringMakerBase {
template <typename T>
static String convert(const DOCTEST_REF_WRAP(T)) {
+#ifdef DOCTEST_CONFIG_REQUIRE_STRINGIFICATION_FOR_ALL_USED_TYPES
+ static_assert(deferred_false<T>::value, "No stringification detected for type T. See string conversion manual");
+#endif
return "{?}";
}
};
- // Vector<int> and various type other than pointer or array.
- template<typename T>
- struct filldata
- {
- static void fill(std::ostream* stream, const T &in) {
- *stream << in;
- }
- };
-
- template<typename T,unsigned long N>
- struct filldata<T[N]>
- {
- static void fill(std::ostream* stream, const T (&in)[N]) {
- for (unsigned long i = 0; i < N; i++) {
- *stream << in[i];
- }
- }
- };
-
- // Specialized since we don't want the terminating null byte!
- template<unsigned long N>
- struct filldata<const char[N]>
- {
- static void fill(std::ostream* stream, const char(&in)[N]) {
- *stream << in;
- }
- };
+ template <typename T>
+ struct filldata;
- template<typename T>
+ template <typename T>
void filloss(std::ostream* stream, const T& in) {
filldata<T>::fill(stream, in);
}
- template<typename T,unsigned long N>
+ template <typename T, size_t N>
void filloss(std::ostream* stream, const T (&in)[N]) {
// T[N], T(&)[N], T(&&)[N] have same behaviour.
// Hence remove reference.
- filldata<typename remove_reference<decltype(in)>::type>::fill(stream, in);
+ filloss<typename types::remove_reference<decltype(in)>::type>(stream, in);
+ }
+
+ template <typename T>
+ String toStream(const T& in) {
+ std::ostream* stream = tlssPush();
+ filloss(stream, in);
+ return tlssPop();
}
template <>
- struct StringMakerBase<true>
- {
+ struct StringMakerBase<true> {
template <typename T>
static String convert(const DOCTEST_REF_WRAP(T) 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.
- */
-
- std::ostream* stream = tlssPush();
- filloss(stream, in);
- return tlssPop();
+ return toStream(in);
}
};
-
- DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size);
-
- template <typename T>
- String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) {
- return rawMemoryToString(&object, sizeof(object));
- }
-
- template <typename T>
- const char* type_to_string() {
- return "<>";
- }
} // namespace detail
template <typename T>
-struct StringMaker : public detail::StringMakerBase<detail::has_insertion_operator<T>::value>
+struct StringMaker : public detail::StringMakerBase<
+ detail::has_insertion_operator<T>::value || detail::types::is_pointer<T>::value || detail::types::is_array<T>::value>
{};
template <typename T>
-struct StringMaker<T*>
-{
- template <typename U>
- static String convert(U* p) {
- if(p)
- return detail::rawMemoryToString(p);
- return "NULL";
- }
-};
-
-template <typename R, typename C>
-struct StringMaker<R C::*>
-{
- static String convert(R C::*p) {
- if(p)
- return detail::rawMemoryToString(p);
- return "NULL";
- }
-};
+String toString() {
+#if DOCTEST_MSVC >= 0 && DOCTEST_CLANG == 0 && DOCTEST_GCC == 0
+ String ret = __FUNCSIG__; // class doctest::String __cdecl doctest::toString<TYPE>(void)
+ String::size_type beginPos = ret.find('<');
+ return ret.substr(beginPos + 1, ret.size() - beginPos - static_cast<String::size_type>(sizeof(">(void)")));
+#else
+ String ret = __PRETTY_FUNCTION__; // doctest::String toString() [with T = TYPE]
+ String::size_type begin = ret.find('=') + 2;
+ return ret.substr(begin, ret.size() - begin - 1);
+#endif
+}
-template <typename T, typename detail::enable_if<!detail::is_enum<T>::value, bool>::type = true>
+template <typename T, typename detail::types::enable_if<!detail::types::is_enum<T>::value, bool>::type = true>
String toString(const DOCTEST_REF_WRAP(T) value) {
return StringMaker<T>::convert(value);
}
#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
-DOCTEST_INTERFACE String toString(char* in);
DOCTEST_INTERFACE String toString(const char* in);
#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
+
+#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
+// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183
+DOCTEST_INTERFACE String toString(const std::string& in);
+#endif // VS 2019
+
+DOCTEST_INTERFACE String toString(std::nullptr_t);
+
DOCTEST_INTERFACE String toString(bool in);
+
DOCTEST_INTERFACE String toString(float in);
DOCTEST_INTERFACE String toString(double in);
DOCTEST_INTERFACE String toString(double long in);
@@ -1072,38 +1074,77 @@ DOCTEST_INTERFACE String toString(double long in);
DOCTEST_INTERFACE String toString(char in);
DOCTEST_INTERFACE String toString(char signed in);
DOCTEST_INTERFACE String toString(char unsigned in);
-DOCTEST_INTERFACE String toString(int short in);
-DOCTEST_INTERFACE String toString(int short unsigned in);
-DOCTEST_INTERFACE String toString(int in);
-DOCTEST_INTERFACE String toString(int unsigned in);
-DOCTEST_INTERFACE String toString(int long in);
-DOCTEST_INTERFACE String toString(int long unsigned in);
-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);
-
-template <typename T, typename detail::enable_if<detail::is_enum<T>::value, bool>::type = true>
+DOCTEST_INTERFACE String toString(short in);
+DOCTEST_INTERFACE String toString(short unsigned in);
+DOCTEST_INTERFACE String toString(signed in);
+DOCTEST_INTERFACE String toString(unsigned in);
+DOCTEST_INTERFACE String toString(long in);
+DOCTEST_INTERFACE String toString(long unsigned in);
+DOCTEST_INTERFACE String toString(long long in);
+DOCTEST_INTERFACE String toString(long long unsigned in);
+
+template <typename T, typename detail::types::enable_if<detail::types::is_enum<T>::value, bool>::type = true>
String toString(const DOCTEST_REF_WRAP(T) value) {
- typedef typename detail::underlying_type<T>::type UT;
+ typedef typename detail::types::underlying_type<T>::type UT;
return toString(static_cast<UT>(value));
}
-#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
-// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183
-DOCTEST_INTERFACE String toString(const std::string& in);
-#endif // VS 2019
+namespace detail {
+ template <typename T>
+ struct filldata
+ {
+ static void fill(std::ostream* stream, const T& in) {
+#if defined(_MSC_VER) && _MSC_VER <= 1900
+ insert_hack_t<T>::insert(*stream, in);
+#else
+ operator<<(*stream, in);
+#endif
+ }
+ };
-class DOCTEST_INTERFACE Approx
+ template <typename T, size_t N>
+ struct filldata<T[N]> {
+ static void fill(std::ostream* stream, const T(&in)[N]) {
+ *stream << "[";
+ for (size_t i = 0; i < N; i++) {
+ if (i != 0) { *stream << ", "; }
+ *stream << toString(in[i]);
+ }
+ *stream << "]";
+ }
+ };
+
+ // Specialized since we don't want the terminating null byte!
+ template <size_t N>
+ struct filldata<const char[N]> {
+ static void fill(std::ostream* stream, const char (&in)[N]) {
+ *stream << String(in, in[N - 1] ? N : N - 1);
+ }
+ };
+
+ template <>
+ struct filldata<const void*> {
+ static void fill(std::ostream* stream, const void* in);
+ };
+
+ template <typename T>
+ struct filldata<T*> {
+ static void fill(std::ostream* stream, const T* in) {
+ filldata<const void*>::fill(stream, in);
+ }
+ };
+}
+
+struct DOCTEST_INTERFACE Approx
{
-public:
- explicit Approx(double value);
+ Approx(double value);
Approx operator()(double value) const;
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
template <typename T>
explicit Approx(const T& value,
- typename detail::enable_if<std::is_constructible<double, T>::value>::type* =
+ typename detail::types::enable_if<std::is_constructible<double, T>::value>::type* =
static_cast<T*>(nullptr)) {
*this = Approx(static_cast<double>(value));
}
@@ -1113,7 +1154,7 @@ public:
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
template <typename T>
- typename detail::enable_if<std::is_constructible<double, T>::value, Approx&>::type epsilon(
+ typename std::enable_if<std::is_constructible<double, T>::value, Approx&>::type epsilon(
const T& newEpsilon) {
m_epsilon = static_cast<double>(newEpsilon);
return *this;
@@ -1124,7 +1165,7 @@ public:
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
template <typename T>
- typename detail::enable_if<std::is_constructible<double, T>::value, Approx&>::type scale(
+ typename std::enable_if<std::is_constructible<double, T>::value, Approx&>::type scale(
const T& newScale) {
m_scale = static_cast<double>(newScale);
return *this;
@@ -1145,11 +1186,9 @@ public:
DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs);
DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs);
- DOCTEST_INTERFACE friend String toString(const Approx& in);
-
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
#define DOCTEST_APPROX_PREFIX \
- template <typename T> friend typename detail::enable_if<std::is_constructible<double, T>::value, bool>::type
+ template <typename T> friend typename std::enable_if<std::is_constructible<double, T>::value, bool>::type
DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); }
DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); }
@@ -1168,7 +1207,6 @@ public:
// clang-format on
-private:
double m_epsilon;
double m_scale;
double m_value;
@@ -1181,8 +1219,9 @@ DOCTEST_INTERFACE const ContextOptions* getContextOptions();
template <typename F>
struct DOCTEST_INTERFACE_DECL IsNaN
{
- F val;
- IsNaN(F f) : val(f) { }
+ F value; bool flipped;
+ IsNaN(F f, bool flip = false) : value(f), flipped(flip) { }
+ IsNaN<F> operator!() const { return { value, !flipped }; }
operator bool() const;
};
#ifndef __MINGW32__
@@ -1190,9 +1229,9 @@ extern template struct DOCTEST_INTERFACE_DECL IsNaN<float>;
extern template struct DOCTEST_INTERFACE_DECL IsNaN<double>;
extern template struct DOCTEST_INTERFACE_DECL IsNaN<long double>;
#endif
-DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& out, IsNaN<float> nanCheck);
-DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& out, IsNaN<double> nanCheck);
-DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& out, IsNaN<long double> nanCheck);
+DOCTEST_INTERFACE String toString(IsNaN<float> in);
+DOCTEST_INTERFACE String toString(IsNaN<double> in);
+DOCTEST_INTERFACE String toString(IsNaN<double long> in);
#ifndef DOCTEST_CONFIG_DISABLE
@@ -1263,7 +1302,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
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> \
+ template <typename R ,typename types::enable_if<!doctest::detail::types::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), rhs); \
if(m_at & assertType::is_false) \
@@ -1346,7 +1385,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
#define DOCTEST_COMPARISON_RETURN_TYPE bool
#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
-#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type
+#define DOCTEST_COMPARISON_RETURN_TYPE typename types::enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); }
inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); }
@@ -1473,7 +1512,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
return Expression_lhs<L>(static_cast<L&&>(operand), m_at);
}
- template <typename L,typename enable_if<!doctest::detail::is_rvalue_reference<L>::value,void >::type* = nullptr>
+ template <typename L,typename types::enable_if<!doctest::detail::types::is_rvalue_reference<L>::value,void >::type* = nullptr>
Expression_lhs<const L&> operator<<(const L &operand) {
return Expression_lhs<const L&>(operand, m_at);
}
@@ -1506,12 +1545,12 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
{
funcType m_test; // a function pointer to the test case
- const char* m_type; // for templated test cases - gets appended to the real name
+ String m_type; // for templated test cases - gets appended to the real name
int m_template_id; // an ID used to distinguish between the different versions of a templated test case
String m_full_name; // contains the name (only for templated test cases!) + the template type
TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,
- const char* type = "", int template_id = -1);
+ const String& type = String(), int template_id = -1);
TestCase(const TestCase& other);
@@ -1709,58 +1748,6 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et);
- template <bool C>
- struct StringStreamBase
- {
- template <typename T>
- static void convert(std::ostream* s, const T& in) {
- *s << toString(in);
- }
-
- // always treat char* as a string in this context - no matter
- // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined
- static void convert(std::ostream* s, const char* in) { *s << String(in); }
- };
-
- template <>
- struct StringStreamBase<true>
- {
- template <typename T>
- static void convert(std::ostream* s, const T& in) {
- *s << in;
- }
- };
-
- template <typename T>
- struct StringStream : public StringStreamBase<has_insertion_operator<T>::value>
- {};
-
- template <typename T>
- void toStream(std::ostream* s, const T& value) {
- StringStream<T>::convert(s, value);
- }
-
-#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
- DOCTEST_INTERFACE void toStream(std::ostream* s, char* in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in);
-#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
- DOCTEST_INTERFACE void toStream(std::ostream* s, bool in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, float in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, double in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, double long in);
-
- DOCTEST_INTERFACE void toStream(std::ostream* s, char in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int short in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int long in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in);
-
// 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 {
@@ -1802,7 +1789,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
// the preferred way of chaining parameters for stringification
template <typename T>
MessageBuilder& operator,(const T& in) {
- toStream(m_stream, in);
+ *m_stream << toString(in);
return *this;
}
@@ -2105,7 +2092,7 @@ int registerReporter(const char* name, int priority, bool isReporter) {
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)
+#if DOCTEST_CPLUSPLUS >= 201703L
#define DOCTEST_TEST_CASE_CLASS(decorators) \
DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), \
DOCTEST_ANONYMOUS(DOCTEST_ANON_PROXY_), \
@@ -2121,18 +2108,17 @@ int registerReporter(const char* name, int priority, bool isReporter) {
DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators)
// for converting types to strings without the <typeinfo> header and demangling
-#define DOCTEST_TYPE_TO_STRING_IMPL(...) \
- template <> \
- inline const char* type_to_string<__VA_ARGS__>() { \
- return "<" #__VA_ARGS__ ">"; \
- }
-#define DOCTEST_TYPE_TO_STRING(...) \
- namespace doctest { namespace detail { \
- DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__) \
+#define DOCTEST_TYPE_TO_STRING_AS(str, ...) \
+ namespace doctest { \
+ template <> \
+ inline String toString<__VA_ARGS__>() { \
+ return str; \
} \
} \
static_assert(true, "")
+#define DOCTEST_TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING_AS(#__VA_ARGS__, __VA_ARGS__)
+
#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \
template <typename T> \
static void func(); \
@@ -2145,7 +2131,7 @@ int registerReporter(const char* name, int priority, bool isReporter) {
iter(const char* file, unsigned line, int index) { \
doctest::detail::regTest(doctest::detail::TestCase(func<Type>, file, line, \
doctest_detail_test_suite_ns::getCurrentTestSuite(), \
- doctest::detail::type_to_string<Type>(), \
+ doctest::toString<Type>(), \
int(line) * 1000 + index) \
* dec); \
iter<std::tuple<Rest...>>(file, line, index + 1); \
@@ -2344,8 +2330,8 @@ int registerReporter(const char* name, int priority, bool isReporter) {
__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&) { \
+ } catch(const typename doctest::detail::types::remove_const< \
+ typename doctest::detail::types::remove_reference<__VA_ARGS__>::type>::type&) {\
DOCTEST_RB.translateException(); \
DOCTEST_RB.m_threw_as = true; \
} catch(...) { DOCTEST_RB.translateException(); } \
@@ -2595,8 +2581,8 @@ int registerReporter(const char* name, int priority, bool isReporter) {
DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name)
// for converting types to strings without the <typeinfo> header and demangling
+#define DOCTEST_TYPE_TO_STRING_AS(str, ...) static_assert(true, "")
#define DOCTEST_TYPE_TO_STRING(...) static_assert(true, "")
-#define DOCTEST_TYPE_TO_STRING_IMPL(...)
// for typed tests
#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \
@@ -2846,6 +2832,7 @@ namespace detail {
#define TEST_CASE(name) DOCTEST_TEST_CASE(name)
#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name)
#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name)
+#define TYPE_TO_STRING_AS(str, ...) DOCTEST_TYPE_TO_STRING_AS(str, __VA_ARGS__)
#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__)
#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__)
#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id)
@@ -2983,28 +2970,6 @@ namespace detail {
// this is here to clear the 'current test suite' for the current translation unit - at the top
DOCTEST_TEST_SUITE_END();
-// add stringification for primitive/fundamental types
-namespace doctest { namespace detail {
- DOCTEST_TYPE_TO_STRING_IMPL(bool)
- DOCTEST_TYPE_TO_STRING_IMPL(float)
- DOCTEST_TYPE_TO_STRING_IMPL(double)
- DOCTEST_TYPE_TO_STRING_IMPL(long double)
- DOCTEST_TYPE_TO_STRING_IMPL(char)
- DOCTEST_TYPE_TO_STRING_IMPL(signed char)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned char)
-#if !DOCTEST_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
- DOCTEST_TYPE_TO_STRING_IMPL(wchar_t)
-#endif // not MSVC or wchar_t support enabled
- DOCTEST_TYPE_TO_STRING_IMPL(short int)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int)
- DOCTEST_TYPE_TO_STRING_IMPL(int)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned int)
- DOCTEST_TYPE_TO_STRING_IMPL(long int)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int)
- DOCTEST_TYPE_TO_STRING_IMPL(long long int)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int)
-}} // namespace doctest::detail
-
#endif // DOCTEST_CONFIG_DISABLE
DOCTEST_CLANG_SUPPRESS_WARNING_POP
@@ -3116,6 +3081,10 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
#include <cfloat>
#include <cctype>
#include <cstdint>
+#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
+// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183
+#include <string>
+#endif // VS 2019
#ifdef DOCTEST_PLATFORM_MAC
#include <sys/types.h>
@@ -3232,20 +3201,6 @@ namespace {
}
}
- template <typename T>
- String fpToString(T value, int precision) {
- std::ostringstream oss;
- oss << std::setprecision(precision) << std::fixed << value;
- std::string d = oss.str();
- size_t i = d.find_last_not_of('0');
- if(i != std::string::npos && i != d.size() - 1) {
- if(d[i] == '.')
- i++;
- d = d.substr(0, i + 1);
- }
- return d.c_str();
- }
-
struct Endianness
{
enum Arch
@@ -3266,22 +3221,6 @@ namespace {
} // namespace
namespace detail {
- String rawMemoryToString(const void* object, unsigned size) {
- // Reverse order for little endian architectures
- int i = 0, end = static_cast<int>(size), inc = 1;
- if(Endianness::which() == Endianness::Little) {
- i = end - 1;
- end = inc = -1;
- }
-
- unsigned const char* bytes = static_cast<unsigned const char*>(object);
- std::ostream* oss = tlssPush();
- *oss << "0x" << std::setfill('0') << std::hex;
- for(; i != end; i += inc)
- *oss << std::setw(2) << static_cast<unsigned>(bytes[i]);
- return tlssPop();
- }
-
DOCTEST_THREAD_LOCAL class
{
std::vector<std::streampos> stack;
@@ -3545,7 +3484,7 @@ typedef timer_large_integer::type ticks_t;
#endif // DOCTEST_CONFIG_DISABLE
} // namespace detail
-char* String::allocate(unsigned sz) {
+char* String::allocate(size_type sz) {
if (sz <= last) {
buf[sz] = '\0';
setLast(last - sz);
@@ -3561,7 +3500,11 @@ char* String::allocate(unsigned sz) {
}
void String::setOnHeap() { *reinterpret_cast<unsigned char*>(&buf[last]) = 128; }
-void String::setLast(unsigned in) { buf[last] = char(in); }
+void String::setLast(size_type in) { buf[last] = char(in); }
+void String::setSize(size_type sz) {
+ if (isOnStack()) { buf[sz] = '\0'; setLast(last - sz); }
+ else { data.ptr[sz] = '\0'; data.size = sz; }
+}
void String::copy(const String& other) {
if(other.isOnStack()) {
@@ -3585,11 +3528,11 @@ String::~String() {
String::String(const char* in)
: String(in, strlen(in)) {}
-String::String(const char* in, unsigned in_size) {
+String::String(const char* in, size_type in_size) {
memcpy(allocate(in_size), in, in_size);
}
-String::String(std::istream& in, unsigned in_size) {
+String::String(std::istream& in, size_type in_size) {
in.read(allocate(in_size), in_size);
}
@@ -3607,9 +3550,9 @@ String& String::operator=(const String& other) {
}
String& String::operator+=(const String& other) {
- const unsigned my_old_size = size();
- const unsigned other_size = other.size();
- const unsigned total_size = my_old_size + other_size;
+ const size_type my_old_size = size();
+ const size_type other_size = other.size();
+ const size_type total_size = my_old_size + other_size;
if(isOnStack()) {
if(total_size < len) {
// append to the current stack space
@@ -3673,30 +3616,60 @@ String& String::operator=(String&& other) {
return *this;
}
-char String::operator[](unsigned i) const {
+char String::operator[](size_type i) const {
return const_cast<String*>(this)->operator[](i); // NOLINT
}
-char& String::operator[](unsigned i) {
+char& String::operator[](size_type i) {
if(isOnStack())
return reinterpret_cast<char*>(buf)[i];
return data.ptr[i];
}
DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized")
-unsigned String::size() const {
+String::size_type String::size() const {
if(isOnStack())
- return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32
+ return last - (size_type(buf[last]) & 31); // using "last" would work only if "len" is 32
return data.size;
}
DOCTEST_GCC_SUPPRESS_WARNING_POP
-unsigned String::capacity() const {
+String::size_type String::capacity() const {
if(isOnStack())
return len;
return data.capacity;
}
+String String::substr(size_type pos, size_type cnt) && {
+ cnt = std::min(cnt, size() - 1 - pos);
+ char* cptr = c_str();
+ memmove(cptr, cptr + pos, cnt);
+ setSize(cnt);
+ return std::move(*this);
+}
+
+String String::substr(size_type pos, size_type cnt) const & {
+ cnt = std::min(cnt, size() - 1 - pos);
+ return String{ c_str() + pos, cnt };
+}
+
+String::size_type String::find(char ch, size_type pos) const {
+ const char* begin = c_str();
+ const char* end = begin + size();
+ const char* it = begin + pos;
+ for (; it < end && *it != ch; it++);
+ if (it < end) { return static_cast<size_type>(it - begin); }
+ else { return npos; }
+}
+
+String::size_type String::rfind(char ch, size_type pos) const {
+ const char* begin = c_str();
+ const char* it = begin + std::min(pos, size() - 1);
+ for (; it >= begin && *it != ch; it--);
+ if (it >= begin) { return static_cast<size_type>(it - begin); }
+ else { return npos; }
+}
+
int String::compare(const char* other, bool no_case) const {
if(no_case)
return doctest::stricmp(c_str(), other);
@@ -3833,42 +3806,50 @@ bool SubcaseSignature::operator<(const SubcaseSignature& other) const {
IContextScope::IContextScope() = default;
IContextScope::~IContextScope() = default;
+namespace detail {
+ void filldata<const void*>::fill(std::ostream* stream, const void* in) {
+ if (in) { *stream << in; }
+ else { *stream << "nullptr"; }
+ }
+
+ template <typename T>
+ String toStreamLit(T t) {
+ std::ostream* os = tlssPush();
+ os->operator<<(t);
+ return tlssPop();
+ }
+}
+
#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
-String toString(char* in) { return toString(static_cast<const char*>(in)); }
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; }
#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
-String toString(bool in) { return in ? "true" : "false"; }
-String toString(float in) { return fpToString(in, 5) + "f"; }
-String toString(double in) { return fpToString(in, 10); }
-String toString(double long in) { return fpToString(in, 15); }
-
-#define DOCTEST_TO_STRING_OVERLOAD(type, fmt) \
- String toString(type in) { \
- char buf[64]; \
- std::sprintf(buf, fmt, in); \
- return buf; \
- }
-
-DOCTEST_TO_STRING_OVERLOAD(char, "%d")
-DOCTEST_TO_STRING_OVERLOAD(char signed, "%d")
-DOCTEST_TO_STRING_OVERLOAD(char unsigned, "%u")
-DOCTEST_TO_STRING_OVERLOAD(int short, "%d")
-DOCTEST_TO_STRING_OVERLOAD(int short unsigned, "%u")
-DOCTEST_TO_STRING_OVERLOAD(int, "%d")
-DOCTEST_TO_STRING_OVERLOAD(unsigned, "%u")
-DOCTEST_TO_STRING_OVERLOAD(int long, "%ld")
-DOCTEST_TO_STRING_OVERLOAD(int long unsigned, "%lu")
-DOCTEST_TO_STRING_OVERLOAD(int long long, "%lld")
-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/doctest/doctest/issues/183
String toString(const std::string& in) { return in.c_str(); }
#endif // VS 2019
+String toString(std::nullptr_t) { return "nullptr"; }
+
+String toString(bool in) { return in ? "true" : "false"; }
+
+String toString(float in) { return toStreamLit(in); }
+String toString(double in) { return toStreamLit(in); }
+String toString(double long in) { return toStreamLit(in); }
+
+String toString(char in) { return toStreamLit(static_cast<signed>(in)); }
+String toString(char signed in) { return toStreamLit(static_cast<signed>(in)); }
+String toString(char unsigned in) { return toStreamLit(static_cast<unsigned>(in)); }
+String toString(short in) { return toStreamLit(in); }
+String toString(short unsigned in) { return toStreamLit(in); }
+String toString(signed in) { return toStreamLit(in); }
+String toString(unsigned in) { return toStreamLit(in); }
+String toString(long in) { return toStreamLit(in); }
+String toString(long unsigned in) { return toStreamLit(in); }
+String toString(long long in) { return toStreamLit(in); }
+String toString(long long unsigned in) { return toStreamLit(in); }
+
Approx::Approx(double value)
: m_epsilon(static_cast<double>(std::numeric_limits<float>::epsilon()) * 100)
, m_scale(1.0)
@@ -3908,7 +3889,6 @@ bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs
bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; }
String toString(const Approx& in) {
- // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
return "Approx( " + doctest::toString(in.m_value) + " )";
}
const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); }
@@ -3916,18 +3896,17 @@ const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nu
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4738)
template <typename F>
IsNaN<F>::operator bool() const {
- return std::isnan(val);
+ return std::isnan(value) ^ flipped;
}
DOCTEST_MSVC_SUPPRESS_WARNING_POP
template struct DOCTEST_INTERFACE_DEF IsNaN<float>;
template struct DOCTEST_INTERFACE_DEF IsNaN<double>;
template struct DOCTEST_INTERFACE_DEF IsNaN<long double>;
-std::ostream& operator<<(std::ostream& out, IsNaN<float> nanCheck)
- { out << nanCheck.val; return out; }
-std::ostream& operator<<(std::ostream& out, IsNaN<double> nanCheck)
- { out << nanCheck.val; return out; }
-std::ostream& operator<<(std::ostream& out, IsNaN<long double> nanCheck)
- { out << nanCheck.val; return out; }
+template <typename F>
+String toString(IsNaN<F> nanCheck) { return String(nanCheck.flipped ? "! " : "") + "IsNaN( " + doctest::toString(nanCheck.value) + " )"; }
+String toString(IsNaN<float> nanCheck) { return toString<float>(nanCheck); }
+String toString(IsNaN<double> nanCheck) { return toString<double>(nanCheck); }
+String toString(IsNaN<double long> nanCheck) { return toString<double long>(nanCheck); }
} // namespace doctest
@@ -4203,7 +4182,7 @@ namespace detail {
}
TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,
- const char* type, int template_id) {
+ const String& type, int template_id) {
m_file = file;
m_line = line;
m_name = nullptr; // will be later overridden in operator*
@@ -4228,10 +4207,8 @@ namespace detail {
}
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function
- DOCTEST_MSVC_SUPPRESS_WARNING(26437) // Do not slice
TestCase& TestCase::operator=(const TestCase& other) {
- static_cast<TestCaseData&>(*this) = static_cast<const TestCaseData&>(other);
-
+ TestCaseData::operator=(other);
m_test = other.m_test;
m_type = other.m_type;
m_template_id = other.m_template_id;
@@ -4247,7 +4224,7 @@ namespace detail {
m_name = in;
// make a new name with an appended type for templated test case
if(m_template_id != -1) {
- m_full_name = String(m_name) + m_type;
+ m_full_name = String(m_name) + "<" + m_type + ">";
// redirect the name to point to the newly constructed full name
m_name = m_full_name.c_str();
}
@@ -4489,27 +4466,6 @@ namespace detail {
getExceptionTranslators().push_back(et);
}
-#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
- void toStream(std::ostream* s, char* in) { *s << in; }
- void toStream(std::ostream* s, const char* in) { *s << in; }
-#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
- void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; }
- void toStream(std::ostream* s, float in) { *s << in; }
- void toStream(std::ostream* s, double in) { *s << in; }
- void toStream(std::ostream* s, double long in) { *s << in; }
-
- void toStream(std::ostream* s, char in) { *s << in; }
- void toStream(std::ostream* s, char signed in) { *s << in; }
- void toStream(std::ostream* s, char unsigned in) { *s << in; }
- void toStream(std::ostream* s, int short in) { *s << in; }
- void toStream(std::ostream* s, int short unsigned in) { *s << in; }
- void toStream(std::ostream* s, int in) { *s << in; }
- void toStream(std::ostream* s, int unsigned in) { *s << in; }
- void toStream(std::ostream* s, int long in) { *s << in; }
- void toStream(std::ostream* s, int long unsigned in) { *s << in; }
- void toStream(std::ostream* s, int long long in) { *s << in; }
- void toStream(std::ostream* s, int long long unsigned in) { *s << in; }
-
DOCTEST_THREAD_LOCAL std::vector<IContextScope*> g_infoContexts; // for logging with INFO()
ContextScopeBase::ContextScopeBase() {
diff --git a/doctest/parts/doctest.cpp b/doctest/parts/doctest.cpp
index 5d27a041..1115912a 100644
--- a/doctest/parts/doctest.cpp
+++ b/doctest/parts/doctest.cpp
@@ -95,6 +95,7 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
#include <cfloat>
#include <cctype>
#include <cstdint>
+#include <string>
#ifdef DOCTEST_PLATFORM_MAC
#include <sys/types.h>
@@ -211,20 +212,6 @@ namespace {
}
}
- template <typename T>
- String fpToString(T value, int precision) {
- std::ostringstream oss;
- oss << std::setprecision(precision) << std::fixed << value;
- std::string d = oss.str();
- size_t i = d.find_last_not_of('0');
- if(i != std::string::npos && i != d.size() - 1) {
- if(d[i] == '.')
- i++;
- d = d.substr(0, i + 1);
- }
- return d.c_str();
- }
-
struct Endianness
{
enum Arch
@@ -245,22 +232,6 @@ namespace {
} // namespace
namespace detail {
- String rawMemoryToString(const void* object, unsigned size) {
- // Reverse order for little endian architectures
- int i = 0, end = static_cast<int>(size), inc = 1;
- if(Endianness::which() == Endianness::Little) {
- i = end - 1;
- end = inc = -1;
- }
-
- unsigned const char* bytes = static_cast<unsigned const char*>(object);
- std::ostream* oss = tlssPush();
- *oss << "0x" << std::setfill('0') << std::hex;
- for(; i != end; i += inc)
- *oss << std::setw(2) << static_cast<unsigned>(bytes[i]);
- return tlssPop();
- }
-
DOCTEST_THREAD_LOCAL class
{
std::vector<std::streampos> stack;
@@ -524,7 +495,7 @@ typedef timer_large_integer::type ticks_t;
#endif // DOCTEST_CONFIG_DISABLE
} // namespace detail
-char* String::allocate(unsigned sz) {
+char* String::allocate(size_type sz) {
if (sz <= last) {
buf[sz] = '\0';
setLast(last - sz);
@@ -540,7 +511,11 @@ char* String::allocate(unsigned sz) {
}
void String::setOnHeap() { *reinterpret_cast<unsigned char*>(&buf[last]) = 128; }
-void String::setLast(unsigned in) { buf[last] = char(in); }
+void String::setLast(size_type in) { buf[last] = char(in); }
+void String::setSize(size_type sz) {
+ if (isOnStack()) { buf[sz] = '\0'; setLast(last - sz); }
+ else { data.ptr[sz] = '\0'; data.size = sz; }
+}
void String::copy(const String& other) {
if(other.isOnStack()) {
@@ -564,11 +539,11 @@ String::~String() {
String::String(const char* in)
: String(in, strlen(in)) {}
-String::String(const char* in, unsigned in_size) {
+String::String(const char* in, size_type in_size) {
memcpy(allocate(in_size), in, in_size);
}
-String::String(std::istream& in, unsigned in_size) {
+String::String(std::istream& in, size_type in_size) {
in.read(allocate(in_size), in_size);
}
@@ -586,9 +561,9 @@ String& String::operator=(const String& other) {
}
String& String::operator+=(const String& other) {
- const unsigned my_old_size = size();
- const unsigned other_size = other.size();
- const unsigned total_size = my_old_size + other_size;
+ const size_type my_old_size = size();
+ const size_type other_size = other.size();
+ const size_type total_size = my_old_size + other_size;
if(isOnStack()) {
if(total_size < len) {
// append to the current stack space
@@ -652,30 +627,60 @@ String& String::operator=(String&& other) {
return *this;
}
-char String::operator[](unsigned i) const {
+char String::operator[](size_type i) const {
return const_cast<String*>(this)->operator[](i); // NOLINT
}
-char& String::operator[](unsigned i) {
+char& String::operator[](size_type i) {
if(isOnStack())
return reinterpret_cast<char*>(buf)[i];
return data.ptr[i];
}
DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized")
-unsigned String::size() const {
+String::size_type String::size() const {
if(isOnStack())
- return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32
+ return last - (size_type(buf[last]) & 31); // using "last" would work only if "len" is 32
return data.size;
}
DOCTEST_GCC_SUPPRESS_WARNING_POP
-unsigned String::capacity() const {
+String::size_type String::capacity() const {
if(isOnStack())
return len;
return data.capacity;
}
+String String::substr(size_type pos, size_type cnt) && {
+ cnt = std::min(cnt, size() - 1 - pos);
+ char* cptr = c_str();
+ memmove(cptr, cptr + pos, cnt);
+ setSize(cnt);
+ return std::move(*this);
+}
+
+String String::substr(size_type pos, size_type cnt) const & {
+ cnt = std::min(cnt, size() - 1 - pos);
+ return String{ c_str() + pos, cnt };
+}
+
+String::size_type String::find(char ch, size_type pos) const {
+ const char* begin = c_str();
+ const char* end = begin + size();
+ const char* it = begin + pos;
+ for (; it < end && *it != ch; it++);
+ if (it < end) { return static_cast<size_type>(it - begin); }
+ else { return npos; }
+}
+
+String::size_type String::rfind(char ch, size_type pos) const {
+ const char* begin = c_str();
+ const char* it = begin + std::min(pos, size() - 1);
+ for (; it >= begin && *it != ch; it--);
+ if (it >= begin) { return static_cast<size_type>(it - begin); }
+ else { return npos; }
+}
+
int String::compare(const char* other, bool no_case) const {
if(no_case)
return doctest::stricmp(c_str(), other);
@@ -812,42 +817,50 @@ bool SubcaseSignature::operator<(const SubcaseSignature& other) const {
IContextScope::IContextScope() = default;
IContextScope::~IContextScope() = default;
+namespace detail {
+ void filldata<const void*>::fill(std::ostream* stream, const void* in) {
+ if (in) { *stream << in; }
+ else { *stream << "nullptr"; }
+ }
+
+ template <typename T>
+ String toStreamLit(T t) {
+ std::ostream* os = tlssPush();
+ os->operator<<(t);
+ return tlssPop();
+ }
+}
+
#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
-String toString(char* in) { return toString(static_cast<const char*>(in)); }
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; }
#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
-String toString(bool in) { return in ? "true" : "false"; }
-String toString(float in) { return fpToString(in, 5) + "f"; }
-String toString(double in) { return fpToString(in, 10); }
-String toString(double long in) { return fpToString(in, 15); }
-
-#define DOCTEST_TO_STRING_OVERLOAD(type, fmt) \
- String toString(type in) { \
- char buf[64]; \
- std::sprintf(buf, fmt, in); \
- return buf; \
- }
-
-DOCTEST_TO_STRING_OVERLOAD(char, "%d")
-DOCTEST_TO_STRING_OVERLOAD(char signed, "%d")
-DOCTEST_TO_STRING_OVERLOAD(char unsigned, "%u")
-DOCTEST_TO_STRING_OVERLOAD(int short, "%d")
-DOCTEST_TO_STRING_OVERLOAD(int short unsigned, "%u")
-DOCTEST_TO_STRING_OVERLOAD(int, "%d")
-DOCTEST_TO_STRING_OVERLOAD(unsigned, "%u")
-DOCTEST_TO_STRING_OVERLOAD(int long, "%ld")
-DOCTEST_TO_STRING_OVERLOAD(int long unsigned, "%lu")
-DOCTEST_TO_STRING_OVERLOAD(int long long, "%lld")
-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/doctest/doctest/issues/183
String toString(const std::string& in) { return in.c_str(); }
#endif // VS 2019
+String toString(std::nullptr_t) { return "nullptr"; }
+
+String toString(bool in) { return in ? "true" : "false"; }
+
+String toString(float in) { return toStreamLit(in); }
+String toString(double in) { return toStreamLit(in); }
+String toString(double long in) { return toStreamLit(in); }
+
+String toString(char in) { return toStreamLit(static_cast<signed>(in)); }
+String toString(char signed in) { return toStreamLit(static_cast<signed>(in)); }
+String toString(char unsigned in) { return toStreamLit(static_cast<unsigned>(in)); }
+String toString(short in) { return toStreamLit(in); }
+String toString(short unsigned in) { return toStreamLit(in); }
+String toString(signed in) { return toStreamLit(in); }
+String toString(unsigned in) { return toStreamLit(in); }
+String toString(long in) { return toStreamLit(in); }
+String toString(long unsigned in) { return toStreamLit(in); }
+String toString(long long in) { return toStreamLit(in); }
+String toString(long long unsigned in) { return toStreamLit(in); }
+
Approx::Approx(double value)
: m_epsilon(static_cast<double>(std::numeric_limits<float>::epsilon()) * 100)
, m_scale(1.0)
@@ -887,7 +900,6 @@ bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs
bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; }
String toString(const Approx& in) {
- // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
return "Approx( " + doctest::toString(in.m_value) + " )";
}
const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); }
@@ -895,18 +907,17 @@ const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nu
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4738)
template <typename F>
IsNaN<F>::operator bool() const {
- return std::isnan(val);
+ return std::isnan(value) ^ flipped;
}
DOCTEST_MSVC_SUPPRESS_WARNING_POP
template struct DOCTEST_INTERFACE_DEF IsNaN<float>;
template struct DOCTEST_INTERFACE_DEF IsNaN<double>;
template struct DOCTEST_INTERFACE_DEF IsNaN<long double>;
-std::ostream& operator<<(std::ostream& out, IsNaN<float> nanCheck)
- { out << nanCheck.val; return out; }
-std::ostream& operator<<(std::ostream& out, IsNaN<double> nanCheck)
- { out << nanCheck.val; return out; }
-std::ostream& operator<<(std::ostream& out, IsNaN<long double> nanCheck)
- { out << nanCheck.val; return out; }
+template <typename F>
+String toString(IsNaN<F> nanCheck) { return String(nanCheck.flipped ? "! " : "") + "IsNaN( " + doctest::toString(nanCheck.value) + " )"; }
+String toString(IsNaN<float> nanCheck) { return toString<float>(nanCheck); }
+String toString(IsNaN<double> nanCheck) { return toString<double>(nanCheck); }
+String toString(IsNaN<double long> nanCheck) { return toString<double long>(nanCheck); }
} // namespace doctest
@@ -1182,7 +1193,7 @@ namespace detail {
}
TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,
- const char* type, int template_id) {
+ const String& type, int template_id) {
m_file = file;
m_line = line;
m_name = nullptr; // will be later overridden in operator*
@@ -1207,10 +1218,8 @@ namespace detail {
}
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function
- DOCTEST_MSVC_SUPPRESS_WARNING(26437) // Do not slice
TestCase& TestCase::operator=(const TestCase& other) {
- static_cast<TestCaseData&>(*this) = static_cast<const TestCaseData&>(other);
-
+ TestCaseData::operator=(other);
m_test = other.m_test;
m_type = other.m_type;
m_template_id = other.m_template_id;
@@ -1226,7 +1235,7 @@ namespace detail {
m_name = in;
// make a new name with an appended type for templated test case
if(m_template_id != -1) {
- m_full_name = String(m_name) + m_type;
+ m_full_name = String(m_name) + "<" + m_type + ">";
// redirect the name to point to the newly constructed full name
m_name = m_full_name.c_str();
}
@@ -1468,27 +1477,6 @@ namespace detail {
getExceptionTranslators().push_back(et);
}
-#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
- void toStream(std::ostream* s, char* in) { *s << in; }
- void toStream(std::ostream* s, const char* in) { *s << in; }
-#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
- void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; }
- void toStream(std::ostream* s, float in) { *s << in; }
- void toStream(std::ostream* s, double in) { *s << in; }
- void toStream(std::ostream* s, double long in) { *s << in; }
-
- void toStream(std::ostream* s, char in) { *s << in; }
- void toStream(std::ostream* s, char signed in) { *s << in; }
- void toStream(std::ostream* s, char unsigned in) { *s << in; }
- void toStream(std::ostream* s, int short in) { *s << in; }
- void toStream(std::ostream* s, int short unsigned in) { *s << in; }
- void toStream(std::ostream* s, int in) { *s << in; }
- void toStream(std::ostream* s, int unsigned in) { *s << in; }
- void toStream(std::ostream* s, int long in) { *s << in; }
- void toStream(std::ostream* s, int long unsigned in) { *s << in; }
- void toStream(std::ostream* s, int long long in) { *s << in; }
- void toStream(std::ostream* s, int long long unsigned in) { *s << in; }
-
DOCTEST_THREAD_LOCAL std::vector<IContextScope*> g_infoContexts; // for logging with INFO()
ContextScopeBase::ContextScopeBase() {
diff --git a/doctest/parts/doctest_fwd.h b/doctest/parts/doctest_fwd.h
index 877b24c2..b9a6dcc7 100644
--- a/doctest/parts/doctest_fwd.h
+++ b/doctest/parts/doctest_fwd.h
@@ -65,6 +65,12 @@
// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect
+#ifdef _MSC_VER
+#define DOCTEST_CPLUSPLUS _MSVC_LANG
+#else
+#define DOCTEST_CPLUSPLUS __cplusplus
+#endif
+
#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH))
// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl...
@@ -364,8 +370,10 @@ DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly define
#ifndef DOCTEST_CONSTEXPR
#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))
#define DOCTEST_CONSTEXPR const
+#define DOCTEST_CONSTEXPR_FUNC inline
#else // DOCTEST_MSVC
#define DOCTEST_CONSTEXPR constexpr
+#define DOCTEST_CONSTEXPR_FUNC constexpr
#endif // DOCTEST_MSVC
#endif // DOCTEST_CONSTEXPR
@@ -472,6 +480,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643)
namespace std { // NOLINT (cert-dcl58-cpp)
typedef decltype(nullptr) nullptr_t;
+typedef decltype(sizeof(void*)) size_t;
template <class charT>
struct char_traits;
template <>
@@ -479,6 +488,8 @@ struct char_traits<char>;
template <class charT, class traits>
class basic_ostream;
typedef basic_ostream<char, char_traits<char>> ostream;
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, const char*);
template <class charT, class traits>
class basic_istream;
typedef basic_istream<char, char_traits<char>> istream;
@@ -504,8 +515,14 @@ DOCTEST_MSVC_SUPPRESS_WARNING_POP
namespace doctest {
+using std::size_t;
+
DOCTEST_INTERFACE extern bool is_running_in_test;
+#ifndef DOCTEST_CONFIG_STRING_SIZE_TYPE
+#define DOCTEST_CONFIG_STRING_SIZE_TYPE unsigned
+#endif
+
// A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length
// of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for:
// - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128)
@@ -518,7 +535,6 @@ DOCTEST_INTERFACE extern bool is_running_in_test;
// TODO:
// - optimizations - like not deleting memory unnecessarily in operator= and etc.
// - resize/reserve/clear
-// - substr
// - replace
// - back/front
// - iterator stuff
@@ -528,14 +544,18 @@ DOCTEST_INTERFACE extern bool is_running_in_test;
// - relational operators as free functions - taking const char* as one of the params
class DOCTEST_INTERFACE String
{
- static const unsigned len = 24; //!OCLINT avoid private static members
- static const unsigned last = len - 1; //!OCLINT avoid private static members
+public:
+ using size_type = DOCTEST_CONFIG_STRING_SIZE_TYPE;
+
+private:
+ static DOCTEST_CONSTEXPR size_type len = 24; //!OCLINT avoid private static members
+ static DOCTEST_CONSTEXPR size_type last = len - 1; //!OCLINT avoid private static members
struct view // len should be more than sizeof(view) - because of the final byte for flags
{
char* ptr;
- unsigned size;
- unsigned capacity;
+ size_type size;
+ size_type capacity;
};
union
@@ -544,23 +564,26 @@ class DOCTEST_INTERFACE String
view data;
};
- char* allocate(unsigned sz);
+ char* allocate(size_type sz);
bool isOnStack() const { return (buf[last] & 128) == 0; }
void setOnHeap();
- void setLast(unsigned in = last);
+ void setLast(size_type in = last);
+ void setSize(size_type sz);
void copy(const String& other);
public:
+ static DOCTEST_CONSTEXPR size_type npos = static_cast<size_type>(-1);
+
String();
~String();
// cppcheck-suppress noExplicitConstructor
String(const char* in);
- String(const char* in, unsigned in_size);
+ String(const char* in, size_type in_size);
- String(std::istream& in, unsigned in_size);
+ String(std::istream& in, size_type in_size);
String(const String& other);
String& operator=(const String& other);
@@ -570,8 +593,8 @@ public:
String(String&& other);
String& operator=(String&& other);
- char operator[](unsigned i) const;
- char& operator[](unsigned i);
+ char operator[](size_type i) const;
+ char& operator[](size_type i);
// the only functions I'm willing to leave in the interface - available for inlining
const char* c_str() const { return const_cast<String*>(this)->c_str(); } // NOLINT
@@ -581,11 +604,19 @@ public:
return data.ptr;
}
- unsigned size() const;
- unsigned capacity() const;
+ size_type size() const;
+ size_type capacity() const;
+
+ String substr(size_type pos, size_type len = npos) &&;
+ String substr(size_type pos, size_type len = npos) const &;
+
+ size_type find(char ch, size_type pos = 0) const;
+ size_type rfind(char ch, size_type pos = npos) const;
int compare(const char* other, bool no_case = false) const;
int compare(const String& other, bool no_case = false) const;
+
+friend DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in);
};
DOCTEST_INTERFACE String operator+(const String& lhs, const String& rhs);
@@ -597,8 +628,6 @@ 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);
-DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in);
-
class DOCTEST_INTERFACE Contains {
public:
explicit Contains(const String& string);
@@ -868,200 +897,173 @@ struct ContextOptions //!OCLINT too many fields
};
namespace detail {
- template <bool CONDITION, typename TYPE = void>
- struct enable_if
- {};
+ namespace types {
+#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
+ using namespace std;
+#else
+ template <bool COND, typename T = void>
+ struct enable_if { };
+
+ template <typename T>
+ struct enable_if<true, T> { using type = T; };
- template <typename TYPE>
- struct enable_if<true, TYPE>
- { typedef TYPE type; };
+ struct true_type { static DOCTEST_CONSTEXPR bool value = true; };
+ struct false_type { static DOCTEST_CONSTEXPR bool value = false; };
- // clang-format off
- template<class T> struct remove_reference { typedef T type; };
- template<class T> struct remove_reference<T&> { typedef T type; };
- template<class T> struct remove_reference<T&&> { typedef T type; };
+ template <typename T> struct remove_reference { using type = T; };
+ template <typename T> struct remove_reference<T&> { using type = T; };
+ template <typename T> struct remove_reference<T&&> { using type = T; };
- template<typename T, typename U = T&&> U declval(int);
+ template <typename T> struct is_rvalue_reference : false_type { };
+ template <typename T> struct is_rvalue_reference<T&&> : true_type { };
- template<typename T> T declval(long);
+ template<typename T> struct remove_const { using type = T; };
+ template <typename T> struct remove_const<const T> { using type = T; };
- template<typename T> auto declval() DOCTEST_NOEXCEPT -> decltype(declval<T>(0)) ;
+ // Compiler intrinsics
+ template <typename T> struct is_enum { DOCTEST_CONSTEXPR static bool value = __is_enum(T); };
+ template <typename T> struct underlying_type { using type = __underlying_type(T); };
- 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 <typename T> struct is_pointer : false_type { };
+ template <typename T> struct is_pointer<T*> : true_type { };
- 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 <typename T> struct is_array : false_type { };
+ template <typename T, size_t SIZE> struct is_array<T[SIZE]> : true_type { };
+#endif
+ }
+
+ // <utility>
+ template <typename T>
+ T&& declval();
template <class T>
- inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT
- {
+ DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference<T>::type& t) DOCTEST_NOEXCEPT {
return static_cast<T&&>(t);
}
template <class T>
- inline T&& forward(typename remove_reference<T>::type&& t) DOCTEST_NOEXCEPT
- {
- static_assert(!is_lvalue_reference<T>::value,
- "Can not forward an rvalue as an lvalue.");
+ DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference<T>::type&& t) DOCTEST_NOEXCEPT {
return static_cast<T&&>(t);
}
- template<class T> struct remove_const { typedef T type; };
- template<class T> struct remove_const<const T> { typedef T type; };
-#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
- template<class T> struct is_enum : public std::is_enum<T> {};
- template<class T> struct underlying_type : public std::underlying_type<T> {};
-#else
- // Use compiler intrinsics
- 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
+ template <typename T>
+ struct deferred_false : types::false_type { };
+
+// MSVS 2015 :(
+#if defined(_MSC_VER) && _MSC_VER <= 1900
+ template <typename T, typename = void>
+ struct has_global_insertion_operator : types::false_type { };
template <typename T>
- struct deferred_false
- // cppcheck-suppress unusedStructMember
- { static const bool value = false; };
-
- namespace has_insertion_operator_impl {
- std::ostream &os();
- template<class T>
- DOCTEST_REF_WRAP(T) val();
-
- template<class, class = void>
- struct check {
- static DOCTEST_CONSTEXPR bool value = false;
- };
+ struct has_global_insertion_operator<T, decltype(::operator<<(declval<std::ostream&>(), declval<const T&>()), void())> : types::true_type { };
- template<class T>
- struct check<T, decltype(os() << val<T>(), void())> {
- static DOCTEST_CONSTEXPR bool value = true;
- };
- } // namespace has_insertion_operator_impl
+ template <typename T, typename = void>
+ struct has_insertion_operator { static DOCTEST_CONSTEXPR bool value = has_global_insertion_operator<T>::value; };
+
+ template <typename T, bool global>
+ struct insert_hack;
+
+ template <typename T>
+ struct insert_hack<T, true> {
+ static void insert(std::ostream& os, const T& t) { ::operator<<(os, t); }
+ };
+
+ template <typename T>
+ struct insert_hack<T, false> {
+ static void insert(std::ostream& os, const T& t) { operator<<(os, t); }
+ };
+
+ template <typename T>
+ using insert_hack_t = insert_hack<T, has_global_insertion_operator<T>::value>;
+#else
+ template <typename T, typename = void>
+ struct has_insertion_operator : types::false_type { };
+#endif
- template<class T>
- using has_insertion_operator = has_insertion_operator_impl::check<const T>;
+template <typename T>
+struct has_insertion_operator<T, decltype(operator<<(declval<std::ostream&>(), declval<const T&>()), void())> : types::true_type { };
DOCTEST_INTERFACE std::ostream* tlssPush();
DOCTEST_INTERFACE String tlssPop();
-
template <bool C>
- struct StringMakerBase
- {
+ struct StringMakerBase {
template <typename T>
static String convert(const DOCTEST_REF_WRAP(T)) {
+#ifdef DOCTEST_CONFIG_REQUIRE_STRINGIFICATION_FOR_ALL_USED_TYPES
+ static_assert(deferred_false<T>::value, "No stringification detected for type T. See string conversion manual");
+#endif
return "{?}";
}
};
- // Vector<int> and various type other than pointer or array.
- template<typename T>
- struct filldata
- {
- static void fill(std::ostream* stream, const T &in) {
- *stream << in;
- }
- };
-
- template<typename T,unsigned long N>
- struct filldata<T[N]>
- {
- static void fill(std::ostream* stream, const T (&in)[N]) {
- for (unsigned long i = 0; i < N; i++) {
- *stream << in[i];
- }
- }
- };
-
- // Specialized since we don't want the terminating null byte!
- template<unsigned long N>
- struct filldata<const char[N]>
- {
- static void fill(std::ostream* stream, const char(&in)[N]) {
- *stream << in;
- }
- };
+ template <typename T>
+ struct filldata;
- template<typename T>
+ template <typename T>
void filloss(std::ostream* stream, const T& in) {
filldata<T>::fill(stream, in);
}
- template<typename T,unsigned long N>
+ template <typename T, size_t N>
void filloss(std::ostream* stream, const T (&in)[N]) {
// T[N], T(&)[N], T(&&)[N] have same behaviour.
// Hence remove reference.
- filldata<typename remove_reference<decltype(in)>::type>::fill(stream, in);
+ filloss<typename types::remove_reference<decltype(in)>::type>(stream, in);
+ }
+
+ template <typename T>
+ String toStream(const T& in) {
+ std::ostream* stream = tlssPush();
+ filloss(stream, in);
+ return tlssPop();
}
template <>
- struct StringMakerBase<true>
- {
+ struct StringMakerBase<true> {
template <typename T>
static String convert(const DOCTEST_REF_WRAP(T) 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.
- */
-
- std::ostream* stream = tlssPush();
- filloss(stream, in);
- return tlssPop();
+ return toStream(in);
}
};
-
- DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size);
-
- template <typename T>
- String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) {
- return rawMemoryToString(&object, sizeof(object));
- }
-
- template <typename T>
- const char* type_to_string() {
- return "<>";
- }
} // namespace detail
template <typename T>
-struct StringMaker : public detail::StringMakerBase<detail::has_insertion_operator<T>::value>
+struct StringMaker : public detail::StringMakerBase<
+ detail::has_insertion_operator<T>::value || detail::types::is_pointer<T>::value || detail::types::is_array<T>::value>
{};
template <typename T>
-struct StringMaker<T*>
-{
- template <typename U>
- static String convert(U* p) {
- if(p)
- return detail::rawMemoryToString(p);
- return "NULL";
- }
-};
-
-template <typename R, typename C>
-struct StringMaker<R C::*>
-{
- static String convert(R C::*p) {
- if(p)
- return detail::rawMemoryToString(p);
- return "NULL";
- }
-};
+String toString() {
+#if DOCTEST_MSVC >= 0 && DOCTEST_CLANG == 0 && DOCTEST_GCC == 0
+ String ret = __FUNCSIG__; // class doctest::String __cdecl doctest::toString<TYPE>(void)
+ String::size_type beginPos = ret.find('<');
+ return ret.substr(beginPos + 1, ret.size() - beginPos - static_cast<String::size_type>(sizeof(">(void)")));
+#else
+ String ret = __PRETTY_FUNCTION__; // doctest::String toString() [with T = TYPE]
+ String::size_type begin = ret.find('=') + 2;
+ return ret.substr(begin, ret.size() - begin - 1);
+#endif
+}
-template <typename T, typename detail::enable_if<!detail::is_enum<T>::value, bool>::type = true>
+template <typename T, typename detail::types::enable_if<!detail::types::is_enum<T>::value, bool>::type = true>
String toString(const DOCTEST_REF_WRAP(T) value) {
return StringMaker<T>::convert(value);
}
#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
-DOCTEST_INTERFACE String toString(char* in);
DOCTEST_INTERFACE String toString(const char* in);
#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
+
+#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
+// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183
+DOCTEST_INTERFACE String toString(const std::string& in);
+#endif // VS 2019
+
+DOCTEST_INTERFACE String toString(std::nullptr_t);
+
DOCTEST_INTERFACE String toString(bool in);
+
DOCTEST_INTERFACE String toString(float in);
DOCTEST_INTERFACE String toString(double in);
DOCTEST_INTERFACE String toString(double long in);
@@ -1069,38 +1071,77 @@ DOCTEST_INTERFACE String toString(double long in);
DOCTEST_INTERFACE String toString(char in);
DOCTEST_INTERFACE String toString(char signed in);
DOCTEST_INTERFACE String toString(char unsigned in);
-DOCTEST_INTERFACE String toString(int short in);
-DOCTEST_INTERFACE String toString(int short unsigned in);
-DOCTEST_INTERFACE String toString(int in);
-DOCTEST_INTERFACE String toString(int unsigned in);
-DOCTEST_INTERFACE String toString(int long in);
-DOCTEST_INTERFACE String toString(int long unsigned in);
-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);
-
-template <typename T, typename detail::enable_if<detail::is_enum<T>::value, bool>::type = true>
+DOCTEST_INTERFACE String toString(short in);
+DOCTEST_INTERFACE String toString(short unsigned in);
+DOCTEST_INTERFACE String toString(signed in);
+DOCTEST_INTERFACE String toString(unsigned in);
+DOCTEST_INTERFACE String toString(long in);
+DOCTEST_INTERFACE String toString(long unsigned in);
+DOCTEST_INTERFACE String toString(long long in);
+DOCTEST_INTERFACE String toString(long long unsigned in);
+
+template <typename T, typename detail::types::enable_if<detail::types::is_enum<T>::value, bool>::type = true>
String toString(const DOCTEST_REF_WRAP(T) value) {
- typedef typename detail::underlying_type<T>::type UT;
+ typedef typename detail::types::underlying_type<T>::type UT;
return toString(static_cast<UT>(value));
}
-#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
-// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183
-DOCTEST_INTERFACE String toString(const std::string& in);
-#endif // VS 2019
+namespace detail {
+ template <typename T>
+ struct filldata
+ {
+ static void fill(std::ostream* stream, const T& in) {
+#if defined(_MSC_VER) && _MSC_VER <= 1900
+ insert_hack_t<T>::insert(*stream, in);
+#else
+ operator<<(*stream, in);
+#endif
+ }
+ };
+
+ template <typename T, size_t N>
+ struct filldata<T[N]> {
+ static void fill(std::ostream* stream, const T(&in)[N]) {
+ *stream << "[";
+ for (size_t i = 0; i < N; i++) {
+ if (i != 0) { *stream << ", "; }
+ *stream << toString(in[i]);
+ }
+ *stream << "]";
+ }
+ };
+
+ // Specialized since we don't want the terminating null byte!
+ template <size_t N>
+ struct filldata<const char[N]> {
+ static void fill(std::ostream* stream, const char (&in)[N]) {
+ *stream << String(in, in[N - 1] ? N : N - 1);
+ }
+ };
+
+ template <>
+ struct filldata<const void*> {
+ static void fill(std::ostream* stream, const void* in);
+ };
+
+ template <typename T>
+ struct filldata<T*> {
+ static void fill(std::ostream* stream, const T* in) {
+ filldata<const void*>::fill(stream, in);
+ }
+ };
+}
-class DOCTEST_INTERFACE Approx
+struct DOCTEST_INTERFACE Approx
{
-public:
- explicit Approx(double value);
+ Approx(double value);
Approx operator()(double value) const;
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
template <typename T>
explicit Approx(const T& value,
- typename detail::enable_if<std::is_constructible<double, T>::value>::type* =
+ typename detail::types::enable_if<std::is_constructible<double, T>::value>::type* =
static_cast<T*>(nullptr)) {
*this = Approx(static_cast<double>(value));
}
@@ -1110,7 +1151,7 @@ public:
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
template <typename T>
- typename detail::enable_if<std::is_constructible<double, T>::value, Approx&>::type epsilon(
+ typename std::enable_if<std::is_constructible<double, T>::value, Approx&>::type epsilon(
const T& newEpsilon) {
m_epsilon = static_cast<double>(newEpsilon);
return *this;
@@ -1121,7 +1162,7 @@ public:
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
template <typename T>
- typename detail::enable_if<std::is_constructible<double, T>::value, Approx&>::type scale(
+ typename std::enable_if<std::is_constructible<double, T>::value, Approx&>::type scale(
const T& newScale) {
m_scale = static_cast<double>(newScale);
return *this;
@@ -1142,11 +1183,9 @@ public:
DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs);
DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs);
- DOCTEST_INTERFACE friend String toString(const Approx& in);
-
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
#define DOCTEST_APPROX_PREFIX \
- template <typename T> friend typename detail::enable_if<std::is_constructible<double, T>::value, bool>::type
+ template <typename T> friend typename std::enable_if<std::is_constructible<double, T>::value, bool>::type
DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); }
DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); }
@@ -1165,7 +1204,6 @@ public:
// clang-format on
-private:
double m_epsilon;
double m_scale;
double m_value;
@@ -1178,8 +1216,9 @@ DOCTEST_INTERFACE const ContextOptions* getContextOptions();
template <typename F>
struct DOCTEST_INTERFACE_DECL IsNaN
{
- F val;
- IsNaN(F f) : val(f) { }
+ F value; bool flipped;
+ IsNaN(F f, bool flip = false) : value(f), flipped(flip) { }
+ IsNaN<F> operator!() const { return { value, !flipped }; }
operator bool() const;
};
#ifndef __MINGW32__
@@ -1187,9 +1226,9 @@ extern template struct DOCTEST_INTERFACE_DECL IsNaN<float>;
extern template struct DOCTEST_INTERFACE_DECL IsNaN<double>;
extern template struct DOCTEST_INTERFACE_DECL IsNaN<long double>;
#endif
-DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& out, IsNaN<float> nanCheck);
-DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& out, IsNaN<double> nanCheck);
-DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& out, IsNaN<long double> nanCheck);
+DOCTEST_INTERFACE String toString(IsNaN<float> in);
+DOCTEST_INTERFACE String toString(IsNaN<double> in);
+DOCTEST_INTERFACE String toString(IsNaN<double long> in);
#ifndef DOCTEST_CONFIG_DISABLE
@@ -1260,7 +1299,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
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> \
+ template <typename R ,typename types::enable_if<!doctest::detail::types::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), rhs); \
if(m_at & assertType::is_false) \
@@ -1343,7 +1382,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
#define DOCTEST_COMPARISON_RETURN_TYPE bool
#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
-#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type
+#define DOCTEST_COMPARISON_RETURN_TYPE typename types::enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); }
inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); }
@@ -1470,7 +1509,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
return Expression_lhs<L>(static_cast<L&&>(operand), m_at);
}
- template <typename L,typename enable_if<!doctest::detail::is_rvalue_reference<L>::value,void >::type* = nullptr>
+ template <typename L,typename types::enable_if<!doctest::detail::types::is_rvalue_reference<L>::value,void >::type* = nullptr>
Expression_lhs<const L&> operator<<(const L &operand) {
return Expression_lhs<const L&>(operand, m_at);
}
@@ -1503,12 +1542,12 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
{
funcType m_test; // a function pointer to the test case
- const char* m_type; // for templated test cases - gets appended to the real name
+ String m_type; // for templated test cases - gets appended to the real name
int m_template_id; // an ID used to distinguish between the different versions of a templated test case
String m_full_name; // contains the name (only for templated test cases!) + the template type
TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,
- const char* type = "", int template_id = -1);
+ const String& type = String(), int template_id = -1);
TestCase(const TestCase& other);
@@ -1706,58 +1745,6 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et);
- template <bool C>
- struct StringStreamBase
- {
- template <typename T>
- static void convert(std::ostream* s, const T& in) {
- *s << toString(in);
- }
-
- // always treat char* as a string in this context - no matter
- // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined
- static void convert(std::ostream* s, const char* in) { *s << String(in); }
- };
-
- template <>
- struct StringStreamBase<true>
- {
- template <typename T>
- static void convert(std::ostream* s, const T& in) {
- *s << in;
- }
- };
-
- template <typename T>
- struct StringStream : public StringStreamBase<has_insertion_operator<T>::value>
- {};
-
- template <typename T>
- void toStream(std::ostream* s, const T& value) {
- StringStream<T>::convert(s, value);
- }
-
-#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
- DOCTEST_INTERFACE void toStream(std::ostream* s, char* in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in);
-#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
- DOCTEST_INTERFACE void toStream(std::ostream* s, bool in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, float in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, double in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, double long in);
-
- DOCTEST_INTERFACE void toStream(std::ostream* s, char in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int short in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int long in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in);
- DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in);
-
// 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 {
@@ -1799,7 +1786,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING_POP
// the preferred way of chaining parameters for stringification
template <typename T>
MessageBuilder& operator,(const T& in) {
- toStream(m_stream, in);
+ *m_stream << toString(in);
return *this;
}
@@ -2102,7 +2089,7 @@ int registerReporter(const char* name, int priority, bool isReporter) {
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)
+#if DOCTEST_CPLUSPLUS >= 201703L
#define DOCTEST_TEST_CASE_CLASS(decorators) \
DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), \
DOCTEST_ANONYMOUS(DOCTEST_ANON_PROXY_), \
@@ -2118,18 +2105,17 @@ int registerReporter(const char* name, int priority, bool isReporter) {
DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators)
// for converting types to strings without the <typeinfo> header and demangling
-#define DOCTEST_TYPE_TO_STRING_IMPL(...) \
- template <> \
- inline const char* type_to_string<__VA_ARGS__>() { \
- return "<" #__VA_ARGS__ ">"; \
- }
-#define DOCTEST_TYPE_TO_STRING(...) \
- namespace doctest { namespace detail { \
- DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__) \
+#define DOCTEST_TYPE_TO_STRING_AS(str, ...) \
+ namespace doctest { \
+ template <> \
+ inline String toString<__VA_ARGS__>() { \
+ return str; \
} \
} \
static_assert(true, "")
+#define DOCTEST_TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING_AS(#__VA_ARGS__, __VA_ARGS__)
+
#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \
template <typename T> \
static void func(); \
@@ -2142,7 +2128,7 @@ int registerReporter(const char* name, int priority, bool isReporter) {
iter(const char* file, unsigned line, int index) { \
doctest::detail::regTest(doctest::detail::TestCase(func<Type>, file, line, \
doctest_detail_test_suite_ns::getCurrentTestSuite(), \
- doctest::detail::type_to_string<Type>(), \
+ doctest::toString<Type>(), \
int(line) * 1000 + index) \
* dec); \
iter<std::tuple<Rest...>>(file, line, index + 1); \
@@ -2341,8 +2327,8 @@ int registerReporter(const char* name, int priority, bool isReporter) {
__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&) { \
+ } catch(const typename doctest::detail::types::remove_const< \
+ typename doctest::detail::types::remove_reference<__VA_ARGS__>::type>::type&) {\
DOCTEST_RB.translateException(); \
DOCTEST_RB.m_threw_as = true; \
} catch(...) { DOCTEST_RB.translateException(); } \
@@ -2592,8 +2578,8 @@ int registerReporter(const char* name, int priority, bool isReporter) {
DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name)
// for converting types to strings without the <typeinfo> header and demangling
+#define DOCTEST_TYPE_TO_STRING_AS(str, ...) static_assert(true, "")
#define DOCTEST_TYPE_TO_STRING(...) static_assert(true, "")
-#define DOCTEST_TYPE_TO_STRING_IMPL(...)
// for typed tests
#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \
@@ -2843,6 +2829,7 @@ namespace detail {
#define TEST_CASE(name) DOCTEST_TEST_CASE(name)
#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name)
#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name)
+#define TYPE_TO_STRING_AS(str, ...) DOCTEST_TYPE_TO_STRING_AS(str, __VA_ARGS__)
#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__)
#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__)
#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id)
@@ -2980,28 +2967,6 @@ namespace detail {
// this is here to clear the 'current test suite' for the current translation unit - at the top
DOCTEST_TEST_SUITE_END();
-// add stringification for primitive/fundamental types
-namespace doctest { namespace detail {
- DOCTEST_TYPE_TO_STRING_IMPL(bool)
- DOCTEST_TYPE_TO_STRING_IMPL(float)
- DOCTEST_TYPE_TO_STRING_IMPL(double)
- DOCTEST_TYPE_TO_STRING_IMPL(long double)
- DOCTEST_TYPE_TO_STRING_IMPL(char)
- DOCTEST_TYPE_TO_STRING_IMPL(signed char)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned char)
-#if !DOCTEST_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
- DOCTEST_TYPE_TO_STRING_IMPL(wchar_t)
-#endif // not MSVC or wchar_t support enabled
- DOCTEST_TYPE_TO_STRING_IMPL(short int)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int)
- DOCTEST_TYPE_TO_STRING_IMPL(int)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned int)
- DOCTEST_TYPE_TO_STRING_IMPL(long int)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int)
- DOCTEST_TYPE_TO_STRING_IMPL(long long int)
- DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int)
-}} // namespace doctest::detail
-
#endif // DOCTEST_CONFIG_DISABLE
DOCTEST_CLANG_SUPPRESS_WARNING_POP
diff --git a/examples/all_features/header.h b/examples/all_features/header.h
index 63b50eb5..6a46aec3 100644
--- a/examples/all_features/header.h
+++ b/examples/all_features/header.h
@@ -26,6 +26,7 @@ REGISTER_EXCEPTION_TRANSLATOR(int& in) {
return doctest::toString(in);
}
+// Removes class on MSVC
TYPE_TO_STRING(doctest::String);
TEST_CASE_TEMPLATE("template 1", T, char) {
diff --git a/examples/all_features/stringification.cpp b/examples/all_features/stringification.cpp
index 2add560d..aa3167d8 100644
--- a/examples/all_features/stringification.cpp
+++ b/examples/all_features/stringification.cpp
@@ -1,7 +1,74 @@
+#ifdef _MSC_VER
+__pragma(warning(push))
+__pragma(warning(disable : 4643))
+namespace std {
+ template <typename> struct char_traits;
+ template <typename, typename> class basic_ostream;
+ typedef basic_ostream<char, char_traits<char>> ostream;
+ template<class TRAITS>
+ basic_ostream<char, TRAITS>& operator<<(basic_ostream<char, TRAITS>&, const char*);
+}
+__pragma(warning(pop))
+#else
+#include <iostream>
+#endif
+
+namespace N {
+ struct A { };
+ struct B {
+ friend std::ostream& operator<<(std::ostream& os, const B&) { return os << "B"; }
+ };
+ struct C { };
+ static std::ostream& operator<<(std::ostream& os, const C&) { return os << "C"; }
+}
+
+static std::ostream& operator<<(std::ostream& os, const N::A&) { return os << "A"; }
+
#include <doctest/doctest.h>
+#include <utility>
+
+TEST_CASE("operator<<") {
+ MESSAGE(N::A{ });
+ MESSAGE(N::B{ });
+ MESSAGE(N::C{ });
+}
+
#include "header.h"
+// std::move is broken with VS <= 15
+#if defined(_MSC_VER) && _MSC_VER <= 1900
+#define MOVE(...) __VA_ARGS__
+#else
+#define MOVE std::move
+#endif
+
+TEST_CASE("no headers") {
+ char chs[] = { '1', 'a', 's' };
+ MESSAGE(chs); CHECK(chs == nullptr);
+ MESSAGE("1as"); CHECK("1as" == nullptr);
+
+ int ints[] = { 0, 1, 1, 2, 3, 5, 8, 13 };
+ MESSAGE(ints); CHECK(ints == nullptr);
+ MESSAGE(MOVE(ints));
+
+ char* cptr = reinterpret_cast<char*>(ints + 4);
+ const char* ccptr = const_cast<const char*>(cptr);
+ void* vptr = reinterpret_cast<void*>(cptr);
+ CHECK(doctest::toString(cptr) == doctest::toString(ccptr));
+ CHECK(doctest::toString(ccptr) == doctest::toString(vptr));
+
+ char* cnptr = nullptr;
+ MESSAGE(cnptr); CHECK(cnptr != nullptr);
+
+ enum Test {
+ A = 0, B, C = 100,
+ };
+ MESSAGE(A); CHECK(A == C);
+
+ MESSAGE(doctest::toString<int>());
+}
+
DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
#include <string>
#include <vector>
@@ -18,11 +85,10 @@ namespace std
template <typename T>
ostream& operator<<(ostream& stream, const vector<T>& in) {
stream << "[";
- for(size_t i = 0; i < in.size(); ++i)
- if(i < in.size() - 1)
- stream << in[i] << ", ";
- else
- stream << in[i];
+ for (size_t i = 0; i < in.size(); ++i) {
+ if (i != 0) { stream << ", "; }
+ stream << in[i];
+ }
stream << "]";
return stream;
}
@@ -32,16 +98,17 @@ ostream& operator<<(ostream& stream, const vector<T>& in) {
namespace doctest
{
template <typename T>
-struct StringMaker<std::list<T> >
+struct StringMaker<std::list<T>>
{
static String convert(const std::list<T>& in) {
std::ostringstream oss;
oss << "[";
- for(typename std::list<T>::const_iterator it = in.begin(); it != in.end(); ++it)
- oss << *it << ", ";
+ for (typename std::list<T>::const_iterator it = in.begin(); it != in.end();) {
+ oss << *it;
+ if (++it != in.end()) { oss << ", "; }
+ }
oss << "]";
-
return oss.str().c_str();
}
};
@@ -100,18 +167,23 @@ REGISTER_EXCEPTION_TRANSLATOR(MyTypeInherited<int>& ex) {
doctest::toString(ex.two) + ")";
}
+#define CHECK_NOT_DEFAULT_STR(var) CHECK(toString(var) != "{?}")
+
TEST_CASE("all asserts should fail and show how the objects get stringified") {
MyTypeInherited<int> bla1;
bla1.one = 5;
bla1.two = 4u;
Bar::Foo f1;
+ MESSAGE(f1);
Bar::Foo f2;
CHECK(f1 == f2);
// std::string already has an operator<< working with std::ostream
std::string dummy = "omg";
+ MESSAGE(dummy);
+
CHECK(dummy == "tralala"); // should fail
CHECK("tralala" == dummy); // should fail
@@ -120,6 +192,8 @@ TEST_CASE("all asserts should fail and show how the objects get stringified") {
vec1.push_back(2);
vec1.push_back(3);
+ MESSAGE(vec1);
+
std::vector<int> vec2;
vec2.push_back(1);
vec2.push_back(2);
@@ -132,6 +206,8 @@ TEST_CASE("all asserts should fail and show how the objects get stringified") {
lst_1.push_back(42);
lst_1.push_back(3);
+ MESSAGE(lst_1);
+
std::list<int> lst_2;
lst_2.push_back(1);
lst_2.push_back(2);
@@ -147,9 +223,9 @@ TEST_CASE("all asserts should fail and show how the objects get stringified") {
CHECK_MESSAGE(s1 == s2, s1, " is not really ", s2);
}
- CHECK(doctest::IsNaN<double>(0.5));
- CHECK(doctest::IsNaN<float>(std::numeric_limits<float>::infinity()));
- // can't test actual nan because it's implementation defined
+ CHECK_NOT_DEFAULT_STR(doctest::IsNaN<double>(0.5));
+ CHECK_NOT_DEFAULT_STR(!doctest::IsNaN<float>(std::numeric_limits<float>::infinity()));
+ CHECK_NOT_DEFAULT_STR(doctest::IsNaN<double long>(std::numeric_limits<double long>::quiet_NaN()));
CHECK("a" == doctest::Contains("aaa"));
diff --git a/examples/all_features/templated_test_cases.cpp b/examples/all_features/templated_test_cases.cpp
index 5c204a59..7c45f135 100644
--- a/examples/all_features/templated_test_cases.cpp
+++ b/examples/all_features/templated_test_cases.cpp
@@ -8,6 +8,8 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
// NORMAL TEMPLATED TEST CASES
// =================================================================================================
+TYPE_TO_STRING_AS("SHORT!!!", short);
+
TEST_CASE_TEMPLATE("signed integers stuff", T, signed char, short, int) {
T var = T();
--var;
@@ -47,6 +49,10 @@ struct TypePair
typedef second B;
};
+TYPE_TO_STRING_AS("Custom name test", TypePair<int, char>);
+TYPE_TO_STRING_AS("Other custom name", TypePair<char, int>);
+TYPE_TO_STRING(TypePair<bool, int>);
+
TEST_CASE_TEMPLATE("multiple types", T, TypePair<int, char>, TypePair<char, int>, TypePair<bool, int>) {
typedef typename T::A T1;
typedef typename T::B T2;
diff --git a/examples/all_features/test_output/coverage_maxout.cpp.txt b/examples/all_features/test_output/coverage_maxout.cpp.txt
index c0975470..e0c193dd 100644
--- a/examples/all_features/test_output/coverage_maxout.cpp.txt
+++ b/examples/all_features/test_output/coverage_maxout.cpp.txt
@@ -11,28 +11,10 @@ coverage_maxout.cpp(0): ERROR: CHECK( str.compare("omgomgomg", false) != 0 ) is
values: CHECK( 0 != 0 )
logged: should fail
-coverage_maxout.cpp(0): ERROR: CHECK( len_is_zero ) is NOT correct!
- values: CHECK( false )
+coverage_maxout.cpp(0): ERROR: CHECK_FALSE( isThereAnything ) is NOT correct!
+ values: CHECK_FALSE( true )
logged: should fail
-coverage_maxout.cpp(0): ERROR: CHECK( b == 5 ) is NOT correct!
- values: CHECK( Approx( 7.0 ) == 5 )
-
-coverage_maxout.cpp(0): ERROR: CHECK( b < 5 ) is NOT correct!
- values: CHECK( Approx( 7.0 ) < 5 )
-
-coverage_maxout.cpp(0): ERROR: CHECK( b <= 5 ) is NOT correct!
- values: CHECK( Approx( 7.0 ) <= 5 )
-
-coverage_maxout.cpp(0): ERROR: CHECK( 6 == a ) is NOT correct!
- values: CHECK( 6 == Approx( 5.0 ) )
-
-coverage_maxout.cpp(0): ERROR: CHECK( 6 < a ) is NOT correct!
- values: CHECK( 6 < Approx( 5.0 ) )
-
-coverage_maxout.cpp(0): ERROR: CHECK( 6 <= a ) is NOT correct!
- values: CHECK( 6 <= Approx( 5.0 ) )
-
===============================================================================
coverage_maxout.cpp(0):
TEST SUITE: exception related
@@ -56,6 +38,6 @@ coverage_maxout.cpp(0): ERROR: test case THREW exception: unknown exception
===============================================================================
[doctest] test cases: 4 | 0 passed | 4 failed |
-[doctest] assertions: 31 | 22 passed | 9 failed |
+[doctest] assertions: 31 | 28 passed | 3 failed |
[doctest] Status: FAILURE!
Program code.
diff --git a/examples/all_features/test_output/coverage_maxout.cpp_junit.txt b/examples/all_features/test_output/coverage_maxout.cpp_junit.txt
index f93d418a..8f1e9920 100644
--- a/examples/all_features/test_output/coverage_maxout.cpp_junit.txt
+++ b/examples/all_features/test_output/coverage_maxout.cpp_junit.txt
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
- <testsuite name="all_features" errors="3" failures="9" tests="31">
+ <testsuite name="all_features" errors="3" failures="3" tests="31">
<testcase classname="coverage_maxout.cpp" name="exercising tricky code paths of doctest" status="run">
<failure message="0 != 0" type="CHECK">
coverage_maxout.cpp(0):
@@ -16,49 +16,13 @@ CHECK( str.compare("omgomgomg", false) != 0 ) is NOT correct!
logged: should fail
</failure>
- <failure message="false" type="CHECK">
+ <failure message="true" type="CHECK_FALSE">
coverage_maxout.cpp(0):
-CHECK( len_is_zero ) is NOT correct!
- values: CHECK( false )
+CHECK_FALSE( isThereAnything ) is NOT correct!
+ values: CHECK_FALSE( true )
logged: should fail
</failure>
- <failure message="Approx( 7.0 ) == 5" type="CHECK">
-coverage_maxout.cpp(0):
-CHECK( b == 5 ) is NOT correct!
- values: CHECK( Approx( 7.0 ) == 5 )
-
- </failure>
- <failure message="Approx( 7.0 ) &lt; 5" type="CHECK">
-coverage_maxout.cpp(0):
-CHECK( b &lt; 5 ) is NOT correct!
- values: CHECK( Approx( 7.0 ) &lt; 5 )
-
- </failure>
- <failure message="Approx( 7.0 ) &lt;= 5" type="CHECK">
-coverage_maxout.cpp(0):
-CHECK( b &lt;= 5 ) is NOT correct!
- values: CHECK( Approx( 7.0 ) &lt;= 5 )
-
- </failure>
- <failure message="6 == Approx( 5.0 )" type="CHECK">
-coverage_maxout.cpp(0):
-CHECK( 6 == a ) is NOT correct!
- values: CHECK( 6 == Approx( 5.0 ) )
-
- </failure>
- <failure message="6 &lt; Approx( 5.0 )" type="CHECK">
-coverage_maxout.cpp(0):
-CHECK( 6 &lt; a ) is NOT correct!
- values: CHECK( 6 &lt; Approx( 5.0 ) )
-
- </failure>
- <failure message="6 &lt;= Approx( 5.0 )" type="CHECK">
-coverage_maxout.cpp(0):
-CHECK( 6 &lt;= a ) is NOT correct!
- values: CHECK( 6 &lt;= Approx( 5.0 ) )
-
- </failure>
</testcase>
<testcase classname="coverage_maxout.cpp" name="will end from a std::string exception" status="run">
<error message="exception">
diff --git a/examples/all_features/test_output/coverage_maxout.cpp_xml.txt b/examples/all_features/test_output/coverage_maxout.cpp_xml.txt
index 1f81db18..9a9bf100 100644
--- a/examples/all_features/test_output/coverage_maxout.cpp_xml.txt
+++ b/examples/all_features/test_output/coverage_maxout.cpp_xml.txt
@@ -25,66 +25,18 @@
should fail
</Info>
</Expression>
- <Expression success="false" type="CHECK" filename="coverage_maxout.cpp" line="0">
+ <Expression success="false" type="CHECK_FALSE" filename="coverage_maxout.cpp" line="0">
<Original>
- len_is_zero
+ isThereAnything
</Original>
<Expanded>
- false
+ true
</Expanded>
<Info>
should fail
</Info>
</Expression>
- <Expression success="false" type="CHECK" filename="coverage_maxout.cpp" line="0">
- <Original>
- b == 5
- </Original>
- <Expanded>
- Approx( 7.0 ) == 5
- </Expanded>
- </Expression>
- <Expression success="false" type="CHECK" filename="coverage_maxout.cpp" line="0">
- <Original>
- b &lt; 5
- </Original>
- <Expanded>
- Approx( 7.0 ) &lt; 5
- </Expanded>
- </Expression>
- <Expression success="false" type="CHECK" filename="coverage_maxout.cpp" line="0">
- <Original>
- b &lt;= 5
- </Original>
- <Expanded>
- Approx( 7.0 ) &lt;= 5
- </Expanded>
- </Expression>
- <Expression success="false" type="CHECK" filename="coverage_maxout.cpp" line="0">
- <Original>
- 6 == a
- </Original>
- <Expanded>
- 6 == Approx( 5.0 )
- </Expanded>
- </Expression>
- <Expression success="false" type="CHECK" filename="coverage_maxout.cpp" line="0">
- <Original>
- 6 &lt; a
- </Original>
- <Expanded>
- 6 &lt; Approx( 5.0 )
- </Expanded>
- </Expression>
- <Expression success="false" type="CHECK" filename="coverage_maxout.cpp" line="0">
- <Original>
- 6 &lt;= a
- </Original>
- <Expanded>
- 6 &lt;= Approx( 5.0 )
- </Expanded>
- </Expression>
- <OverallResultsAsserts successes="22" failures="9" test_case_success="false"/>
+ <OverallResultsAsserts successes="28" failures="3" test_case_success="false"/>
</TestCase>
</TestSuite>
<TestSuite name="exception related">
@@ -107,7 +59,7 @@
<OverallResultsAsserts successes="0" failures="0" test_case_success="false"/>
</TestCase>
</TestSuite>
- <OverallResultsAsserts successes="22" failures="9"/>
+ <OverallResultsAsserts successes="28" failures="3"/>
<OverallResultsTestCases successes="0" failures="4"/>
</doctest>
Program code.
diff --git a/examples/all_features/test_output/filter_2_xml.txt b/examples/all_features/test_output/filter_2_xml.txt
index fa6cd147..ff3d9c7c 100644
--- a/examples/all_features/test_output/filter_2_xml.txt
+++ b/examples/all_features/test_output/filter_2_xml.txt
@@ -32,11 +32,11 @@
<TestCase name="check return values" filename="assertion_macros.cpp" line="0" skipped="true"/>
<TestCase name="check return values no print" filename="assertion_macros.cpp" line="0" skipped="true"/>
<TestCase name="custom macros" filename="alternative_macros.cpp" line="0" skipped="true"/>
+ <TestCase name="default construction&lt;SHORT!!!>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="default construction&lt;char>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="default construction&lt;double>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="default construction&lt;double>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="default construction&lt;int>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
- <TestCase name="default construction&lt;short int>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="default construction&lt;signed char>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="default construction&lt;unsigned char>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
</TestSuite>
@@ -78,9 +78,9 @@
<TestSuite>
<TestCase name="logging the counter of a loop" filename="logging.cpp" line="0" skipped="true"/>
<TestCase name="lots of nested subcases" filename="subcases.cpp" line="0" skipped="true"/>
- <TestCase name="multiple types&lt;>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
- <TestCase name="multiple types&lt;>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
- <TestCase name="multiple types&lt;>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
+ <TestCase name="multiple types&lt;Custom name test>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
+ <TestCase name="multiple types&lt;Other custom name>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
+ <TestCase name="multiple types&lt;TypePair&lt;bool, int>>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="namespace 1 global operator" filename="namespace1.cpp" line="0" skipped="true"/>
<TestCase name="namespace 2 friend operator" filename="namespace2.cpp" line="0" skipped="true"/>
<TestCase name="namespace 3 member operator" filename="namespace3.cpp" line="0" skipped="true"/>
@@ -91,11 +91,15 @@
<TestCase name="namespace 8 friend vs global" filename="namespace8.cpp" line="0" skipped="true"/>
<TestCase name="namespace 9 both global" filename="namespace9.cpp" line="0" skipped="true"/>
<TestCase name="no checks" filename="no_failures.cpp" line="0" skipped="true"/>
+ <TestCase name="no headers" filename="stringification.cpp" line="0" skipped="true"/>
<TestCase name="normal macros" filename="assertion_macros.cpp" line="0" skipped="true"/>
</TestSuite>
<TestSuite name="ts1">
<TestCase name="normal test in a test suite from a decorator" filename="test_cases_and_suites.cpp" line="0" skipped="true"/>
</TestSuite>
+ <TestSuite>
+ <TestCase name="operator&lt;&lt;" filename="stringification.cpp" line="0" skipped="true"/>
+ </TestSuite>
<TestSuite name="scoped test suite">
<TestCase name="part of scoped" filename="test_cases_and_suites.cpp" line="0" skipped="true"/>
<TestCase name="part of scoped 2" filename="test_cases_and_suites.cpp" line="0" skipped="true"/>
@@ -108,8 +112,8 @@
<TestCase name="should fail and no output" filename="no_failures.cpp" line="0" should_fail="true" skipped="true"/>
<TestCase name="should fail and no output" filename="test_cases_and_suites.cpp" line="0" should_fail="true" skipped="true"/>
<TestCase name="should fail because of an exception" filename="test_cases_and_suites.cpp" line="0" skipped="true"/>
+ <TestCase name="signed integers stuff&lt;SHORT!!!>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="signed integers stuff&lt;int>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
- <TestCase name="signed integers stuff&lt;short int>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="signed integers stuff&lt;signed char>" filename="templated_test_cases.cpp" line="0" skipped="true"/>
<TestCase name="simple check" filename="no_failures.cpp" line="0" skipped="true"/>
</TestSuite>
diff --git a/examples/all_features/test_output/stringification.cpp.txt b/examples/all_features/test_output/stringification.cpp.txt
index 650063ec..9f4cece4 100644
--- a/examples/all_features/test_output/stringification.cpp.txt
+++ b/examples/all_features/test_output/stringification.cpp.txt
@@ -1,22 +1,73 @@
[doctest] run with "--help" for options
===============================================================================
stringification.cpp(0):
+TEST CASE: operator<<
+
+stringification.cpp(0): MESSAGE: A
+
+stringification.cpp(0): MESSAGE: B
+
+stringification.cpp(0): MESSAGE: C
+
+===============================================================================
+stringification.cpp(0):
+TEST CASE: no headers
+
+stringification.cpp(0): MESSAGE: 1as
+
+stringification.cpp(0): ERROR: CHECK( chs == nullptr ) is NOT correct!
+ values: CHECK( 1as == nullptr )
+
+stringification.cpp(0): MESSAGE: 1as
+
+stringification.cpp(0): ERROR: CHECK( "1as" == nullptr ) is NOT correct!
+ values: CHECK( 1as == nullptr )
+
+stringification.cpp(0): MESSAGE: [0, 1, 1, 2, 3, 5, 8, 13]
+
+stringification.cpp(0): ERROR: CHECK( ints == nullptr ) is NOT correct!
+ values: CHECK( [0, 1, 1, 2, 3, 5, 8, 13] == nullptr )
+
+stringification.cpp(0): MESSAGE: [0, 1, 1, 2, 3, 5, 8, 13]
+
+stringification.cpp(0): MESSAGE: nullptr
+
+stringification.cpp(0): ERROR: CHECK( cnptr != nullptr ) is NOT correct!
+ values: CHECK( nullptr != nullptr )
+
+stringification.cpp(0): MESSAGE: 0
+
+stringification.cpp(0): ERROR: CHECK( A == C ) is NOT correct!
+ values: CHECK( 0 == 100 )
+
+stringification.cpp(0): MESSAGE: int
+
+===============================================================================
+stringification.cpp(0):
TEST CASE: all asserts should fail and show how the objects get stringified
+stringification.cpp(0): MESSAGE: Foo{}
+
stringification.cpp(0): ERROR: CHECK( f1 == f2 ) is NOT correct!
values: CHECK( Foo{} == Foo{} )
+stringification.cpp(0): MESSAGE: omg
+
stringification.cpp(0): ERROR: CHECK( dummy == "tralala" ) is NOT correct!
values: CHECK( omg == tralala )
stringification.cpp(0): ERROR: CHECK( "tralala" == dummy ) is NOT correct!
values: CHECK( tralala == omg )
+stringification.cpp(0): MESSAGE: [1, 2, 3]
+
stringification.cpp(0): ERROR: CHECK( vec1 == vec2 ) is NOT correct!
values: CHECK( [1, 2, 3] == [1, 2, 4] )
+stringification.cpp(0): MESSAGE: [1, 42, 3]
+
stringification.cpp(0): ERROR: CHECK( lst_1 == lst_2 ) is NOT correct!
- values: CHECK( [1, 42, 3, ] == [1, 2, 666, ] )
+ values: CHECK( [1, 42, 3] == [1, 2, 666] )
stringification.cpp(0): ERROR: CHECK( s1 == s2 ) is NOT correct!
values: CHECK( MyOtherType: 42 == MyOtherType: 666 )
@@ -27,12 +78,6 @@ stringification.cpp(0): ERROR: CHECK( s1 == s2 ) is NOT correct!
logged: s1=MyOtherType: 42 s2=MyOtherType: 666
MyOtherType: 42 is not really MyOtherType: 666
-stringification.cpp(0): ERROR: CHECK( doctest::IsNaN<double>(0.5) ) is NOT correct!
- values: CHECK( 0.5 )
-
-stringification.cpp(0): ERROR: CHECK( doctest::IsNaN<float>(std::numeric_limits<float>::infinity()) ) is NOT correct!
- values: CHECK( inf )
-
stringification.cpp(0): ERROR: CHECK( "a" == doctest::Contains("aaa") ) is NOT correct!
values: CHECK( a == Contains( aaa ) )
@@ -45,7 +90,7 @@ TEST CASE: a test case that registers an exception translator for int and then
stringification.cpp(0): ERROR: test case THREW exception: 5
===============================================================================
-[doctest] test cases: 2 | 0 passed | 2 failed |
-[doctest] assertions: 10 | 0 passed | 10 failed |
+[doctest] test cases: 4 | 1 passed | 3 failed |
+[doctest] assertions: 18 | 5 passed | 13 failed |
[doctest] Status: FAILURE!
Program code.
diff --git a/examples/all_features/test_output/stringification.cpp_junit.txt b/examples/all_features/test_output/stringification.cpp_junit.txt
index eac29e12..93cc0769 100644
--- a/examples/all_features/test_output/stringification.cpp_junit.txt
+++ b/examples/all_features/test_output/stringification.cpp_junit.txt
@@ -1,6 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
- <testsuite name="all_features" errors="2" failures="10" tests="10">
+ <testsuite name="all_features" errors="2" failures="13" tests="18">
+ <testcase classname="stringification.cpp" name="operator&lt;&lt;" status="run"/>
+ <testcase classname="stringification.cpp" name="no headers" status="run">
+ <failure message="1as == nullptr" type="CHECK">
+stringification.cpp(0):
+CHECK( chs == nullptr ) is NOT correct!
+ values: CHECK( 1as == nullptr )
+
+ </failure>
+ <failure message="1as == nullptr" type="CHECK">
+stringification.cpp(0):
+CHECK( "1as" == nullptr ) is NOT correct!
+ values: CHECK( 1as == nullptr )
+
+ </failure>
+ <failure message="[0, 1, 1, 2, 3, 5, 8, 13] == nullptr" type="CHECK">
+stringification.cpp(0):
+CHECK( ints == nullptr ) is NOT correct!
+ values: CHECK( [0, 1, 1, 2, 3, 5, 8, 13] == nullptr )
+
+ </failure>
+ <failure message="nullptr != nullptr" type="CHECK">
+stringification.cpp(0):
+CHECK( cnptr != nullptr ) is NOT correct!
+ values: CHECK( nullptr != nullptr )
+
+ </failure>
+ <failure message="0 == 100" type="CHECK">
+stringification.cpp(0):
+CHECK( A == C ) is NOT correct!
+ values: CHECK( 0 == 100 )
+
+ </failure>
+ </testcase>
<testcase classname="stringification.cpp" name="all asserts should fail and show how the objects get stringified" status="run">
<failure message="Foo{} == Foo{}" type="CHECK">
stringification.cpp(0):
@@ -26,10 +59,10 @@ CHECK( vec1 == vec2 ) is NOT correct!
values: CHECK( [1, 2, 3] == [1, 2, 4] )
</failure>
- <failure message="[1, 42, 3, ] == [1, 2, 666, ]" type="CHECK">
+ <failure message="[1, 42, 3] == [1, 2, 666]" type="CHECK">
stringification.cpp(0):
CHECK( lst_1 == lst_2 ) is NOT correct!
- values: CHECK( [1, 42, 3, ] == [1, 2, 666, ] )
+ values: CHECK( [1, 42, 3] == [1, 2, 666] )
</failure>
<failure message="MyOtherType: 42 == MyOtherType: 666" type="CHECK">
@@ -47,18 +80,6 @@ CHECK( s1 == s2 ) is NOT correct!
MyOtherType: 42 is not really MyOtherType: 666
</failure>
- <failure message="0.5" type="CHECK">
-stringification.cpp(0):
-CHECK( doctest::IsNaN&lt;double>(0.5) ) is NOT correct!
- values: CHECK( 0.5 )
-
- </failure>
- <failure message="inf" type="CHECK">
-stringification.cpp(0):
-CHECK( doctest::IsNaN&lt;float>(std::numeric_limits&lt;float>::infinity()) ) is NOT correct!
- values: CHECK( inf )
-
- </failure>
<failure message="a == Contains( aaa )" type="CHECK">
stringification.cpp(0):
CHECK( "a" == doctest::Contains("aaa") ) is NOT correct!
diff --git a/examples/all_features/test_output/stringification.cpp_xml.txt b/examples/all_features/test_output/stringification.cpp_xml.txt
index 066df99f..e4de969a 100644
--- a/examples/all_features/test_output/stringification.cpp_xml.txt
+++ b/examples/all_features/test_output/stringification.cpp_xml.txt
@@ -2,7 +2,108 @@
<doctest binary="all_features">
<Options order_by="file" rand_seed="324" first="0" last="4294967295" abort_after="0" subcase_filter_levels="2147483647" case_sensitive="false" no_throw="false" no_skip="false"/>
<TestSuite>
+ <TestCase name="operator&lt;&lt;" filename="stringification.cpp" line="0">
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ A
+ </Text>
+ </Message>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ B
+ </Text>
+ </Message>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ C
+ </Text>
+ </Message>
+ <OverallResultsAsserts successes="0" failures="0" test_case_success="true"/>
+ </TestCase>
+ <TestCase name="no headers" filename="stringification.cpp" line="0">
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ 1as
+ </Text>
+ </Message>
+ <Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
+ <Original>
+ chs == nullptr
+ </Original>
+ <Expanded>
+ 1as == nullptr
+ </Expanded>
+ </Expression>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ 1as
+ </Text>
+ </Message>
+ <Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
+ <Original>
+ "1as" == nullptr
+ </Original>
+ <Expanded>
+ 1as == nullptr
+ </Expanded>
+ </Expression>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ [0, 1, 1, 2, 3, 5, 8, 13]
+ </Text>
+ </Message>
+ <Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
+ <Original>
+ ints == nullptr
+ </Original>
+ <Expanded>
+ [0, 1, 1, 2, 3, 5, 8, 13] == nullptr
+ </Expanded>
+ </Expression>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ [0, 1, 1, 2, 3, 5, 8, 13]
+ </Text>
+ </Message>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ nullptr
+ </Text>
+ </Message>
+ <Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
+ <Original>
+ cnptr != nullptr
+ </Original>
+ <Expanded>
+ nullptr != nullptr
+ </Expanded>
+ </Expression>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ 0
+ </Text>
+ </Message>
+ <Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
+ <Original>
+ A == C
+ </Original>
+ <Expanded>
+ 0 == 100
+ </Expanded>
+ </Expression>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ int
+ </Text>
+ </Message>
+ <OverallResultsAsserts successes="2" failures="5" test_case_success="false"/>
+ </TestCase>
<TestCase name="all asserts should fail and show how the objects get stringified" filename="stringification.cpp" line="0">
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ Foo{}
+ </Text>
+ </Message>
<Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
<Original>
f1 == f2
@@ -11,6 +112,11 @@
Foo{} == Foo{}
</Expanded>
</Expression>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ omg
+ </Text>
+ </Message>
<Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
<Original>
dummy == "tralala"
@@ -27,6 +133,11 @@
tralala == omg
</Expanded>
</Expression>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ [1, 2, 3]
+ </Text>
+ </Message>
<Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
<Original>
vec1 == vec2
@@ -35,12 +146,17 @@
[1, 2, 3] == [1, 2, 4]
</Expanded>
</Expression>
+ <Message type="WARNING" filename="stringification.cpp" line="0">
+ <Text>
+ [1, 42, 3]
+ </Text>
+ </Message>
<Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
<Original>
lst_1 == lst_2
</Original>
<Expanded>
- [1, 42, 3, ] == [1, 2, 666, ]
+ [1, 42, 3] == [1, 2, 666]
</Expanded>
</Expression>
<Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
@@ -70,22 +186,6 @@
</Expression>
<Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
<Original>
- doctest::IsNaN&lt;double>(0.5)
- </Original>
- <Expanded>
- 0.5
- </Expanded>
- </Expression>
- <Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
- <Original>
- doctest::IsNaN&lt;float>(std::numeric_limits&lt;float>::infinity())
- </Original>
- <Expanded>
- inf
- </Expanded>
- </Expression>
- <Expression success="false" type="CHECK" filename="stringification.cpp" line="0">
- <Original>
"a" == doctest::Contains("aaa")
</Original>
<Expanded>
@@ -95,7 +195,7 @@
<Exception crash="false">
MyTypeInherited&lt;int>(5, 4)
</Exception>
- <OverallResultsAsserts successes="0" failures="10" test_case_success="false"/>
+ <OverallResultsAsserts successes="3" failures="8" test_case_success="false"/>
</TestCase>
<TestCase name="a test case that registers an exception translator for int and then throws one" filename="stringification.cpp" line="0">
<Exception crash="false">
@@ -104,7 +204,7 @@
<OverallResultsAsserts successes="0" failures="0" test_case_success="false"/>
</TestCase>
</TestSuite>
- <OverallResultsAsserts successes="0" failures="10"/>
- <OverallResultsTestCases successes="0" failures="2"/>
+ <OverallResultsAsserts successes="5" failures="13"/>
+ <OverallResultsTestCases successes="1" failures="3"/>
</doctest>
Program code.
diff --git a/examples/all_features/test_output/templated_test_cases.cpp.txt b/examples/all_features/test_output/templated_test_cases.cpp.txt
index 05195f0e..d4296938 100644
--- a/examples/all_features/test_output/templated_test_cases.cpp.txt
+++ b/examples/all_features/test_output/templated_test_cases.cpp.txt
@@ -8,21 +8,21 @@ templated_test_cases.cpp(0): ERROR: CHECK( vec.size() == 20 ) is NOT correct!
===============================================================================
templated_test_cases.cpp(0):
-TEST CASE: multiple types<>
+TEST CASE: multiple types<Custom name test>
templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
values: CHECK( 0 != 0 )
===============================================================================
templated_test_cases.cpp(0):
-TEST CASE: multiple types<>
+TEST CASE: multiple types<Other custom name>
templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
values: CHECK( 0 != 0 )
===============================================================================
templated_test_cases.cpp(0):
-TEST CASE: multiple types<>
+TEST CASE: multiple types<TypePair<bool, int>>
templated_test_cases.cpp(0): ERROR: CHECK( t2 != T2() ) is NOT correct!
values: CHECK( 0 != 0 )
diff --git a/examples/all_features/test_output/templated_test_cases.cpp_junit.txt b/examples/all_features/test_output/templated_test_cases.cpp_junit.txt
index 90e9df8d..2c9d17de 100644
--- a/examples/all_features/test_output/templated_test_cases.cpp_junit.txt
+++ b/examples/all_features/test_output/templated_test_cases.cpp_junit.txt
@@ -2,7 +2,7 @@
<testsuites>
<testsuite name="all_features" errors="0" failures="5" tests="19">
<testcase classname="templated_test_cases.cpp" name="signed integers stuff&lt;signed char>" status="run"/>
- <testcase classname="templated_test_cases.cpp" name="signed integers stuff&lt;short int>" status="run"/>
+ <testcase classname="templated_test_cases.cpp" name="signed integers stuff&lt;SHORT!!!>" status="run"/>
<testcase classname="templated_test_cases.cpp" name="signed integers stuff&lt;int>" status="run"/>
<testcase classname="templated_test_cases.cpp" name="vector stuff&lt;std::vector&lt;int>>" status="run">
<failure message="10 == 20" type="CHECK">
@@ -13,13 +13,13 @@ CHECK( vec.size() == 20 ) is NOT correct!
</failure>
</testcase>
<testcase classname="templated_test_cases.cpp" name="default construction&lt;signed char>" status="run"/>
- <testcase classname="templated_test_cases.cpp" name="default construction&lt;short int>" status="run"/>
+ <testcase classname="templated_test_cases.cpp" name="default construction&lt;SHORT!!!>" status="run"/>
<testcase classname="templated_test_cases.cpp" name="default construction&lt;int>" status="run"/>
<testcase classname="templated_test_cases.cpp" name="default construction&lt;double>" status="run"/>
<testcase classname="templated_test_cases.cpp" name="default construction&lt;double>" status="run"/>
<testcase classname="templated_test_cases.cpp" name="default construction&lt;unsigned char>" status="run"/>
<testcase classname="templated_test_cases.cpp" name="default construction&lt;char>" status="run"/>
- <testcase classname="templated_test_cases.cpp" name="multiple types&lt;>" status="run">
+ <testcase classname="templated_test_cases.cpp" name="multiple types&lt;Custom name test>" status="run">
<failure message="0 != 0" type="CHECK">
templated_test_cases.cpp(0):
CHECK( t2 != T2() ) is NOT correct!
@@ -27,7 +27,7 @@ CHECK( t2 != T2() ) is NOT correct!
</failure>
</testcase>
- <testcase classname="templated_test_cases.cpp" name="multiple types&lt;>" status="run">
+ <testcase classname="templated_test_cases.cpp" name="multiple types&lt;Other custom name>" status="run">
<failure message="0 != 0" type="CHECK">
templated_test_cases.cpp(0):
CHECK( t2 != T2() ) is NOT correct!
@@ -35,7 +35,7 @@ CHECK( t2 != T2() ) is NOT correct!
</failure>
</testcase>
- <testcase classname="templated_test_cases.cpp" name="multiple types&lt;>" status="run">
+ <testcase classname="templated_test_cases.cpp" name="multiple types&lt;TypePair&lt;bool, int>>" status="run">
<failure message="0 != 0" type="CHECK">
templated_test_cases.cpp(0):
CHECK( t2 != T2() ) is NOT correct!
diff --git a/examples/all_features/test_output/templated_test_cases.cpp_xml.txt b/examples/all_features/test_output/templated_test_cases.cpp_xml.txt
index c2f8b9e4..2b43e30e 100644
--- a/examples/all_features/test_output/templated_test_cases.cpp_xml.txt
+++ b/examples/all_features/test_output/templated_test_cases.cpp_xml.txt
@@ -5,7 +5,7 @@
<TestCase name="signed integers stuff&lt;signed char>" filename="templated_test_cases.cpp" line="0">
<OverallResultsAsserts successes="1" failures="0" test_case_success="true"/>
</TestCase>
- <TestCase name="signed integers stuff&lt;short int>" filename="templated_test_cases.cpp" line="0">
+ <TestCase name="signed integers stuff&lt;SHORT!!!>" filename="templated_test_cases.cpp" line="0">
<OverallResultsAsserts successes="1" failures="0" test_case_success="true"/>
</TestCase>
<TestCase name="signed integers stuff&lt;int>" filename="templated_test_cases.cpp" line="0">
@@ -25,7 +25,7 @@
<TestCase name="default construction&lt;signed char>" filename="templated_test_cases.cpp" line="0">
<OverallResultsAsserts successes="1" failures="0" test_case_success="true"/>
</TestCase>
- <TestCase name="default construction&lt;short int>" filename="templated_test_cases.cpp" line="0">
+ <TestCase name="default construction&lt;SHORT!!!>" filename="templated_test_cases.cpp" line="0">
<OverallResultsAsserts successes="1" failures="0" test_case_success="true"/>
</TestCase>
<TestCase name="default construction&lt;int>" filename="templated_test_cases.cpp" line="0">
@@ -43,7 +43,7 @@
<TestCase name="default construction&lt;char>" filename="templated_test_cases.cpp" line="0">
<OverallResultsAsserts successes="1" failures="0" test_case_success="true"/>
</TestCase>
- <TestCase name="multiple types&lt;>" filename="templated_test_cases.cpp" line="0">
+ <TestCase name="multiple types&lt;Custom name test>" filename="templated_test_cases.cpp" line="0">
<Expression success="false" type="CHECK" filename="templated_test_cases.cpp" line="0">
<Original>
t2 != T2()
@@ -54,7 +54,7 @@
</Expression>
<OverallResultsAsserts successes="1" failures="1" test_case_success="false"/>
</TestCase>
- <TestCase name="multiple types&lt;>" filename="templated_test_cases.cpp" line="0">
+ <TestCase name="multiple types&lt;Other custom name>" filename="templated_test_cases.cpp" line="0">
<Expression success="false" type="CHECK" filename="templated_test_cases.cpp" line="0">
<Original>
t2 != T2()
@@ -65,7 +65,7 @@
</Expression>
<OverallResultsAsserts successes="1" failures="1" test_case_success="false"/>
</TestCase>
- <TestCase name="multiple types&lt;>" filename="templated_test_cases.cpp" line="0">
+ <TestCase name="multiple types&lt;TypePair&lt;bool, int>>" filename="templated_test_cases.cpp" line="0">
<Expression success="false" type="CHECK" filename="templated_test_cases.cpp" line="0">
<Original>
t2 != T2()
diff --git a/examples/executable_dll_and_plugin/dll.cpp b/examples/executable_dll_and_plugin/dll.cpp
index 22e498b4..b436e8fa 100644
--- a/examples/executable_dll_and_plugin/dll.cpp
+++ b/examples/executable_dll_and_plugin/dll.cpp
@@ -8,7 +8,6 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
TEST_CASE("dll") {
std::cout << "I am a test from the dll!\n";
CHECK(true);
- CHECK(doctest::IsNaN<long double>(0.1L));
}
DOCTEST_SYMBOL_EXPORT void from_dll(); // to silence "-Wmissing-declarations" with GCC
diff --git a/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin.txt b/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin.txt
index d489082d..bc674380 100644
--- a/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin.txt
+++ b/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin.txt
@@ -1,12 +1,5 @@
[doctest] run with "--help" for options
I am a test from the dll!
-===============================================================================
-dll.cpp(0):
-TEST CASE: dll
-
-dll.cpp(0): ERROR: CHECK( doctest::IsNaN<long double>(0.1L) ) is NOT correct!
- values: CHECK( 0.1 )
-
I am a test from the implementation!
I am a test from the implementation_2!
I am a test from the executable!
@@ -33,6 +26,6 @@ plugin.cpp(0): FATAL ERROR: certain death!
logged: some info
===============================================================================
-[doctest] test cases: 5 | 2 passed | 3 failed | 0 skipped
-[doctest] assertions: 4 | 1 passed | 3 failed |
+[doctest] test cases: 5 | 3 passed | 2 failed | 0 skipped
+[doctest] assertions: 3 | 1 passed | 2 failed |
[doctest] Status: FAILURE!
diff --git a/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_junit.txt b/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_junit.txt
index 00d66345..e5ff58ee 100644
--- a/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_junit.txt
+++ b/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_junit.txt
@@ -4,15 +4,8 @@ I am a test from the implementation!
I am a test from the implementation_2!
I am a test from the executable!
<testsuites>
- <testsuite name="executable_dll_and_plugin" errors="1" failures="2" tests="4">
- <testcase classname="dll.cpp" name="dll" status="run">
- <failure message="0.1" type="CHECK">
-dll.cpp(0):
-CHECK( doctest::IsNaN&lt;long double>(0.1L) ) is NOT correct!
- values: CHECK( 0.1 )
-
- </failure>
- </testcase>
+ <testsuite name="executable_dll_and_plugin" errors="1" failures="1" tests="3">
+ <testcase classname="dll.cpp" name="dll" status="run"/>
<testcase classname="implementation.cpp" name="implementation" status="run"/>
<testcase classname="implementation_2.cpp" name="implementation_2" status="run"/>
<testcase classname="main.cpp" name="executable" status="run">
diff --git a/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_xml.txt b/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_xml.txt
index 960f0312..b300e78c 100644
--- a/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_xml.txt
+++ b/examples/executable_dll_and_plugin/test_output/executable_dll_and_plugin_xml.txt
@@ -4,15 +4,7 @@
<TestSuite>
<TestCase name="dll" filename="dll.cpp" line="0">
I am a test from the dll!
- <Expression success="false" type="CHECK" filename="dll.cpp" line="0">
- <Original>
- doctest::IsNaN&lt;long double>(0.1L)
- </Original>
- <Expanded>
- 0.1
- </Expanded>
- </Expression>
- <OverallResultsAsserts successes="1" failures="1" test_case_success="false"/>
+ <OverallResultsAsserts successes="1" failures="0" test_case_success="true"/>
</TestCase>
<TestCase name="implementation" filename="implementation.cpp" line="0">
I am a test from the implementation!
@@ -64,6 +56,6 @@ I am a test from the executable!
<OverallResultsAsserts successes="0" failures="2" test_case_success="false"/>
</TestCase>
</TestSuite>
- <OverallResultsAsserts successes="1" failures="3"/>
- <OverallResultsTestCases successes="2" failures="3" skipped="0"/>
+ <OverallResultsAsserts successes="1" failures="2"/>
+ <OverallResultsTestCases successes="3" failures="2" skipped="0"/>
</doctest>
diff --git a/scripts/coverage_maxout.cpp b/scripts/coverage_maxout.cpp
index 8b6e574f..ad55ef42 100644
--- a/scripts/coverage_maxout.cpp
+++ b/scripts/coverage_maxout.cpp
@@ -61,37 +61,19 @@ TEST_CASE("exercising tricky code paths of doctest") {
str += toString("aaa") //
+ toString(nullptr) //
+ toString(true) //
- + toString(static_cast<unsigned int>(0)) //
- + toString(0.5f) //
- + toString(0.5) //
- + toString(static_cast<long double>(0.1)) //
+ + toString(0u) //
+ toString('c') //
+ toString(static_cast<signed char>('c')) //
+ toString(static_cast<unsigned char>(1)) //
+ toString(static_cast<short>(1)) //
- + toString(static_cast<long>(1)) //
- + toString(static_cast<unsigned long>(1)) //
+ + toString(1L) //
+ + toString(1UL) //
+ toString(static_cast<unsigned short>(1)) //
- + toString(static_cast<long long>(1)) //
- + toString(static_cast<unsigned long long>(1));
+ + toString(1LL) //
+ + toString(1ULL);
std::ostringstream oss;
- // toStream
- detail::toStream(&oss, true);
- detail::toStream(&oss, 0.5f);
- detail::toStream(&oss, 0.5);
- detail::toStream(&oss, static_cast<long double>(0.1));
- detail::toStream(&oss, 'c');
- detail::toStream(&oss, static_cast<signed char>('c'));
- detail::toStream(&oss, static_cast<unsigned char>(1));
- detail::toStream(&oss, static_cast<short>(1));
- detail::toStream(&oss, static_cast<long>(1));
- detail::toStream(&oss, static_cast<unsigned long>(1));
- detail::toStream(&oss, static_cast<unsigned short>(1));
- detail::toStream(&oss, static_cast<long long>(1));
- detail::toStream(&oss, static_cast<unsigned long long>(1));
-
// trigger code path for String to ostream through operator<<
oss << str;
// trigger code path for assert string of a non-existent assert type
@@ -102,32 +84,31 @@ TEST_CASE("exercising tricky code paths of doctest") {
#endif
str += oss.str().c_str();
str += failureString(assertType::is_normal);
- CHECK(str == "omgomgomgaaaNULLtrue00.5f0.50.199991111111true0.50.50.1cc"
- "111111omgomgomgaaaNULLtrue00.5f0.50.199991111111");
+ CHECK(str == "omgomgomgaaanullptrtrue099991111111"
+ "omgomgomgaaanullptrtrue099991111111");
// trigger code path for rawMemoryToString
bool isThereAnything = str.size() > 0u;
- bool len_is_zero = detail::rawMemoryToString(isThereAnything).size() == 0u;
String unknown = toString(skip()); // trigger code path for "{?}"
str = unknown; // trigger code path for deleting memory in operator=
- CHECK_MESSAGE(len_is_zero, "should fail");
+ CHECK_FALSE_MESSAGE(isThereAnything, "should fail");
Approx a(5);
a.scale(4);
Approx b = a(7);
- CHECK(b == 5);
- CHECK(b != 5);
- CHECK(b > 5);
- CHECK(b < 5);
- CHECK(b >= 5);
- CHECK(b <= 5);
+ CHECK(b == 7);
+ CHECK(b != 6);
+ CHECK(b > 6);
+ CHECK(b < 8);
+ CHECK(b >= 7);
+ CHECK(b <= 7);
- CHECK(6 == a);
+ CHECK(5 == a);
CHECK(6 != a);
CHECK(6 > a);
- CHECK(6 < a);
- CHECK(6 >= a);
- CHECK(6 <= a);
+ CHECK(4 < a);
+ CHECK(5 >= a);
+ CHECK(5 <= a);
// trigger another single line of code... lol
auto oldVal = const_cast<ContextOptions*>(getContextOptions())->no_path_in_filenames;