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.
diff --git a/examples/all_features/stringification.cpp b/examples/all_features/stringification.cpp
index 2add560..aa3167d 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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"));