ToStringWhich.tests.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * Demonstrate which version of toString/StringMaker is being used
  3. * for various types
  4. */
  5. // Replace fallback stringifier for this TU
  6. // We should avoid ODR violations because these specific types aren't
  7. // present in different TUs
  8. #include <string>
  9. template <typename T>
  10. std::string fallbackStringifier(T const&) {
  11. return "{ !!! }";
  12. }
  13. #define CATCH_CONFIG_FALLBACK_STRINGIFIER fallbackStringifier
  14. #include "catch.hpp"
  15. #if defined(__GNUC__)
  16. // This has to be left enabled until end of the TU, because the GCC
  17. // frontend reports operator<<(std::ostream& os, const has_maker_and_operator&)
  18. // as unused anyway
  19. # pragma GCC diagnostic ignored "-Wunused-function"
  20. #endif
  21. namespace {
  22. struct has_operator { };
  23. struct has_maker {};
  24. struct has_maker_and_operator {};
  25. struct has_neither {};
  26. struct has_template_operator {};
  27. std::ostream& operator<<(std::ostream& os, const has_operator&) {
  28. os << "operator<<( has_operator )";
  29. return os;
  30. }
  31. std::ostream& operator<<(std::ostream& os, const has_maker_and_operator&) {
  32. os << "operator<<( has_maker_and_operator )";
  33. return os;
  34. }
  35. template <typename StreamT>
  36. StreamT& operator<<(StreamT& os, const has_template_operator&) {
  37. os << "operator<<( has_template_operator )";
  38. return os;
  39. }
  40. } // end anonymous namespace
  41. namespace Catch {
  42. template<>
  43. struct StringMaker<has_maker> {
  44. static std::string convert( const has_maker& ) {
  45. return "StringMaker<has_maker>";
  46. }
  47. };
  48. template<>
  49. struct StringMaker<has_maker_and_operator> {
  50. static std::string convert( const has_maker_and_operator& ) {
  51. return "StringMaker<has_maker_and_operator>";
  52. }
  53. };
  54. }
  55. // Call the operator
  56. TEST_CASE( "stringify( has_operator )", "[toString]" ) {
  57. has_operator item;
  58. REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" );
  59. }
  60. // Call the stringmaker
  61. TEST_CASE( "stringify( has_maker )", "[toString]" ) {
  62. has_maker item;
  63. REQUIRE( ::Catch::Detail::stringify( item ) == "StringMaker<has_maker>" );
  64. }
  65. // Call the stringmaker
  66. TEST_CASE( "stringify( has_maker_and_operator )", "[toString]" ) {
  67. has_maker_and_operator item;
  68. REQUIRE( ::Catch::Detail::stringify( item ) == "StringMaker<has_maker_and_operator>" );
  69. }
  70. TEST_CASE("stringify( has_neither )", "[toString]") {
  71. has_neither item;
  72. REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" );
  73. }
  74. // Call the templated operator
  75. TEST_CASE( "stringify( has_template_operator )", "[toString]" ) {
  76. has_template_operator item;
  77. REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" );
  78. }
  79. // Vectors...
  80. TEST_CASE( "stringify( vectors<has_operator> )", "[toString]" ) {
  81. std::vector<has_operator> v(1);
  82. REQUIRE( ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" );
  83. }
  84. TEST_CASE( "stringify( vectors<has_maker> )", "[toString]" ) {
  85. std::vector<has_maker> v(1);
  86. REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" );
  87. }
  88. TEST_CASE( "stringify( vectors<has_maker_and_operator> )", "[toString]" ) {
  89. std::vector<has_maker_and_operator> v(1);
  90. REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker_and_operator> }" );
  91. }
  92. namespace {
  93. // Range-based conversion should only be used if other possibilities fail
  94. struct int_iterator {
  95. using iterator_category = std::input_iterator_tag;
  96. using difference_type = std::ptrdiff_t;
  97. using value_type = int;
  98. using reference = int&;
  99. using pointer = int*;
  100. int_iterator() = default;
  101. int_iterator(int i) :val(i) {}
  102. value_type operator*() const { return val; }
  103. bool operator==(int_iterator rhs) const { return val == rhs.val; }
  104. bool operator!=(int_iterator rhs) const { return val != rhs.val; }
  105. int_iterator operator++() { ++val; return *this; }
  106. int_iterator operator++(int) {
  107. auto temp(*this);
  108. ++val;
  109. return temp;
  110. }
  111. private:
  112. int val = 5;
  113. };
  114. struct streamable_range {
  115. int_iterator begin() const { return int_iterator{ 1 }; }
  116. int_iterator end() const { return {}; }
  117. };
  118. std::ostream& operator<<(std::ostream& os, const streamable_range&) {
  119. os << "op<<(streamable_range)";
  120. return os;
  121. }
  122. struct stringmaker_range {
  123. int_iterator begin() const { return int_iterator{ 1 }; }
  124. int_iterator end() const { return {}; }
  125. };
  126. } // end anonymous namespace
  127. namespace Catch {
  128. template <>
  129. struct StringMaker<stringmaker_range> {
  130. static std::string convert(stringmaker_range const&) {
  131. return "stringmaker(streamable_range)";
  132. }
  133. };
  134. }
  135. namespace {
  136. struct just_range {
  137. int_iterator begin() const { return int_iterator{ 1 }; }
  138. int_iterator end() const { return {}; }
  139. };
  140. struct disabled_range {
  141. int_iterator begin() const { return int_iterator{ 1 }; }
  142. int_iterator end() const { return {}; }
  143. };
  144. } // end anonymous namespace
  145. namespace Catch {
  146. template <>
  147. struct is_range<disabled_range> {
  148. static const bool value = false;
  149. };
  150. }
  151. TEST_CASE("stringify ranges", "[toString]") {
  152. REQUIRE(::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)");
  153. REQUIRE(::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)");
  154. REQUIRE(::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }");
  155. REQUIRE(::Catch::Detail::stringify(disabled_range{}) == "{ !!! }");
  156. }