verbose_assert.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #ifndef TEST_SUPPORT_VERBOSE_ASSERT
  2. #define TEST_SUPPORT_VERBOSE_ASSERT
  3. #include <iostream>
  4. #include <cstdio>
  5. #include <sstream>
  6. #include <string>
  7. #include "test_macros.h"
  8. namespace verbose_assert {
  9. typedef std::basic_ostream<char>&(EndLType)(std::basic_ostream<char>&);
  10. template <class Stream, class Tp,
  11. class = decltype(std::declval<Stream&>() << std::declval<Tp const&>())>
  12. std::true_type IsStreamableImp(int);
  13. template <class Stream, class Tp> std::false_type IsStreamableImp(long);
  14. template <class Stream, class Tp>
  15. struct IsStreamable : decltype(IsStreamableImp<Stream, Tp>(0)) {};
  16. template <class Tp, int ST = (IsStreamable<decltype(std::cerr), Tp>::value ? 1
  17. : (IsStreamable<decltype(std::wcerr), Tp>::value ? 2 : -1))>
  18. struct SelectStream {
  19. static_assert(ST == -1, "specialization required for ST != -1");
  20. static void Print(Tp const&) { std::clog << "Value Not Streamable!\n"; }
  21. };
  22. template <class Tp>
  23. struct SelectStream<Tp, 1> {
  24. static void Print(Tp const& val) { std::cerr << val; }
  25. };
  26. template <class Tp>
  27. struct SelectStream<Tp, 2> {
  28. static void Print(Tp const& val) { std::wcerr << val; }
  29. };
  30. struct AssertData {
  31. AssertData(const char* xcheck, const char* xfile, const char* xfunc,
  32. unsigned long xline, bool xpassed = true)
  33. : passed(xpassed), check(xcheck), file(xfile), func(xfunc), line(xline),
  34. msg() {}
  35. AssertData& SetFailed(std::string xmsg = std::string()) {
  36. msg = xmsg;
  37. passed = false;
  38. return *this;
  39. }
  40. void PrintFailed() const {
  41. std::fprintf(stderr, "%s:%lu %s: Assertion '%s' failed.\n", file, line,
  42. func, check);
  43. if (!msg.empty())
  44. std::fprintf(stderr, "%s\n", msg.data());
  45. }
  46. bool passed;
  47. const char* check;
  48. const char* file;
  49. const char* func;
  50. unsigned long line;
  51. std::string msg;
  52. };
  53. // AssertHandler is the class constructed by failing CHECK macros. AssertHandler
  54. // will log information about the failures and abort when it is destructed.
  55. class AssertHandler {
  56. public:
  57. AssertHandler(AssertData const& Data)
  58. : passed(Data.passed) {
  59. if (!passed)
  60. Data.PrintFailed();
  61. }
  62. ~AssertHandler() TEST_NOEXCEPT_FALSE {
  63. if (!passed) {
  64. error_log << std::endl;
  65. std::abort();
  66. }
  67. }
  68. class LogType {
  69. friend class AssertHandler;
  70. template <class Tp>
  71. friend LogType& operator<<(LogType& log, Tp const& value) {
  72. if (!log.is_disabled) {
  73. SelectStream<Tp>::Print(value);
  74. }
  75. return log;
  76. }
  77. friend LogType& operator<<(LogType& log, EndLType* m) {
  78. if (!log.is_disabled) {
  79. SelectStream<EndLType*>::Print(m);
  80. }
  81. return log;
  82. }
  83. private:
  84. LogType(bool disable) : is_disabled(disable) {}
  85. bool is_disabled;
  86. LogType(LogType const&);
  87. LogType& operator=(LogType const&);
  88. };
  89. LogType& GetLog() {
  90. if (passed)
  91. return null_log;
  92. return error_log;
  93. }
  94. private:
  95. static LogType null_log;
  96. static LogType error_log;
  97. AssertHandler& operator=(const AssertHandler&) = delete;
  98. AssertHandler(const AssertHandler&) = delete;
  99. AssertHandler() = delete;
  100. private:
  101. bool passed;
  102. };
  103. AssertHandler::LogType AssertHandler::null_log(true);
  104. AssertHandler::LogType AssertHandler::error_log(false);
  105. template <class It1>
  106. std::string PrintRange(const char* Name, It1 F, It1 E) {
  107. std::stringstream ss;
  108. ss << " " << Name << " = [";
  109. while (F != E) {
  110. ss << *F;
  111. ++F;
  112. if (F != E)
  113. ss << ", ";
  114. }
  115. ss << "]\n";
  116. return ss.str();
  117. }
  118. template <class Tp, class Up>
  119. std::string PrintMismatch(Tp const& LHS, Up const& RHS, int Elem) {
  120. std::stringstream ss;
  121. ss << " Element " << Elem << " mismatched: `" << LHS << "` != `" << RHS
  122. << "`!\n";
  123. return ss.str();
  124. };
  125. struct EqualToComp {
  126. template <class Tp, class Up>
  127. bool operator()(Tp const& LHS, Up const& RHS) const {
  128. return LHS == RHS;
  129. }
  130. };
  131. template <class It1, class It2, class Comp>
  132. AssertData CheckCollectionsEqual(It1 F1, It1 E1, It2 F2, It2 E2,
  133. AssertData Data, Comp C = EqualToComp()) {
  134. const It1 F1Orig = F1;
  135. const It2 F2Orig = F2;
  136. bool Failed = false;
  137. std::string ErrorMsg;
  138. int Idx = 0;
  139. while (F1 != E1 && F2 != E2) {
  140. if (!(C(*F1, *F2))) {
  141. ErrorMsg += PrintMismatch(*F1, *F2, Idx);
  142. Failed = true;
  143. break;
  144. }
  145. ++Idx;
  146. ++F1;
  147. ++F2;
  148. }
  149. if (!Failed && (F1 != E1 || F2 != E2)) {
  150. ErrorMsg += " Ranges have different sizes!\n";
  151. Failed = true;
  152. }
  153. if (Failed) {
  154. ErrorMsg += PrintRange("LHS", F1Orig, E1);
  155. ErrorMsg += PrintRange("RHS", F2Orig, E2);
  156. Data.SetFailed(ErrorMsg);
  157. }
  158. return Data;
  159. }
  160. } // namespace verbose_assert
  161. #ifdef __GNUC__
  162. #define ASSERT_FN_NAME() __PRETTY_FUNCTION__
  163. #else
  164. #define ASSERT_FN_NAME() __func__
  165. #endif
  166. #define DISPLAY(...) " " #__VA_ARGS__ " = " << (__VA_ARGS__) << "\n"
  167. #define ASSERT(...) \
  168. ::verbose_assert::AssertHandler(::verbose_assert::AssertData( \
  169. #__VA_ARGS__, __FILE__, ASSERT_FN_NAME(), __LINE__,(__VA_ARGS__))).GetLog()
  170. #define ASSERT_EQ(LHS, RHS) \
  171. ASSERT(LHS == RHS) << DISPLAY(LHS) << DISPLAY(RHS)
  172. #define ASSERT_NEQ(LHS, RHS) \
  173. ASSERT(LHS != RHS) << DISPLAY(LHS) << DISPLAY(RHS)
  174. #define ASSERT_PRED(PRED, LHS, RHS) \
  175. ASSERT(PRED(LHS, RHS)) << DISPLAY(LHS) << DISPLAY(RHS)
  176. #define ASSERT_COLLECTION_EQ_COMP(F1, E1, F2, E2, Comp) \
  177. (::verbose_assert::AssertHandler( \
  178. ::verbose_assert::CheckCollectionsEqual( \
  179. F1, E1, F2, E2, \
  180. ::verbose_assert::AssertData("CheckCollectionsEqual(" #F1 ", " #E1 \
  181. ", " #F2 ", " #E2 ")", \
  182. __FILE__, ASSERT_FN_NAME(), __LINE__), \
  183. Comp)) \
  184. .GetLog())
  185. #define ASSERT_COLLECTION_EQ(F1, E1, F2, E2) \
  186. ASSERT_COLLECTION_EQ_COMP(F1, E1, F2, E2, ::verbose_assert::EqualToComp())
  187. #endif