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