xref: /llvm-project/libc/test/UnitTest/LibcTest.cpp (revision 04e066df5eb363a24c7685837734ca6186cd478f)
1 //===-- Implementation of the base class for libc unittests----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "LibcTest.h"
10 
11 #include "src/__support/CPP/string.h"
12 #include "src/__support/CPP/string_view.h"
13 #include "src/__support/UInt128.h"
14 #include "test/UnitTest/TestLogger.h"
15 
16 #if __STDC_HOSTED__
17 #include <time.h>
18 #else
19 static long clock() { return 0; }
20 #define CLOCKS_PER_SEC 1
21 #endif
22 
23 namespace __llvm_libc {
24 namespace testing {
25 
26 namespace internal {
27 
28 // When the value is UInt128, __uint128_t or wider, show its hexadecimal digits.
29 template <typename T>
30 cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T> &&
31                      (sizeof(T) > sizeof(uint64_t)),
32                  cpp::string>
33 describeValue(T Value) {
34   static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt");
35   char buf[IntegerToString::hex_bufsize<T>()];
36   IntegerToString::hex(Value, buf, false);
37   return "0x" + cpp::string(buf, sizeof(buf));
38 }
39 
40 // When the value is of a standard integral type, just display it as normal.
41 template <typename ValType>
42 cpp::enable_if_t<cpp::is_integral_v<ValType> &&
43                      sizeof(ValType) <= sizeof(uint64_t),
44                  cpp::string>
45 describeValue(ValType Value) {
46   return cpp::to_string(Value);
47 }
48 
49 cpp::string describeValue(cpp::string Value) { return Value; }
50 cpp::string_view describeValue(cpp::string_view Value) { return Value; }
51 
52 template <typename ValType>
53 void explainDifference(ValType LHS, ValType RHS, const char *LHSStr,
54                        const char *RHSStr, const char *File, unsigned long Line,
55                        cpp::string OpString) {
56   size_t OffsetLength = OpString.size() > 2 ? OpString.size() - 2 : 0;
57   cpp::string Offset(OffsetLength, ' ');
58 
59   tlog << File << ":" << Line << ": FAILURE\n"
60        << Offset << "Expected: " << LHSStr << '\n'
61        << Offset << "Which is: " << describeValue(LHS) << '\n'
62        << "To be " << OpString << ": " << RHSStr << '\n'
63        << Offset << "Which is: " << describeValue(RHS) << '\n';
64 }
65 
66 template <typename ValType>
67 bool test(RunContext *Ctx, TestCondition Cond, ValType LHS, ValType RHS,
68           const char *LHSStr, const char *RHSStr, const char *File,
69           unsigned long Line) {
70   auto ExplainDifference = [=](cpp::string OpString) {
71     explainDifference(LHS, RHS, LHSStr, RHSStr, File, Line, OpString);
72   };
73 
74   switch (Cond) {
75   case Cond_EQ:
76     if (LHS == RHS)
77       return true;
78 
79     Ctx->markFail();
80     ExplainDifference("equal to");
81     return false;
82   case Cond_NE:
83     if (LHS != RHS)
84       return true;
85 
86     Ctx->markFail();
87     ExplainDifference("not equal to");
88     return false;
89   case Cond_LT:
90     if (LHS < RHS)
91       return true;
92 
93     Ctx->markFail();
94     ExplainDifference("less than");
95     return false;
96   case Cond_LE:
97     if (LHS <= RHS)
98       return true;
99 
100     Ctx->markFail();
101     ExplainDifference("less than or equal to");
102     return false;
103   case Cond_GT:
104     if (LHS > RHS)
105       return true;
106 
107     Ctx->markFail();
108     ExplainDifference("greater than");
109     return false;
110   case Cond_GE:
111     if (LHS >= RHS)
112       return true;
113 
114     Ctx->markFail();
115     ExplainDifference("greater than or equal to");
116     return false;
117   default:
118     Ctx->markFail();
119     tlog << "Unexpected test condition.\n";
120     return false;
121   }
122 }
123 
124 } // namespace internal
125 
126 Test *Test::Start = nullptr;
127 Test *Test::End = nullptr;
128 
129 int argc = 0;
130 char **argv = nullptr;
131 char **envp = nullptr;
132 
133 using internal::RunContext;
134 
135 void Test::addTest(Test *T) {
136   if (End == nullptr) {
137     Start = T;
138     End = T;
139     return;
140   }
141 
142   End->Next = T;
143   End = T;
144 }
145 
146 int Test::runTests(const char *TestFilter) {
147   int TestCount = 0;
148   int FailCount = 0;
149   for (Test *T = Start; T != nullptr; T = T->Next) {
150     const char *TestName = T->getName();
151     cpp::string StrTestName(TestName);
152     constexpr auto GREEN = "\033[32m";
153     constexpr auto RED = "\033[31m";
154     constexpr auto RESET = "\033[0m";
155     if ((TestFilter != nullptr) && (StrTestName != TestFilter)) {
156       continue;
157     }
158     tlog << GREEN << "[ RUN      ] " << RESET << TestName << '\n';
159     [[maybe_unused]] const auto start_time = clock();
160     RunContext Ctx;
161     T->SetUp();
162     T->setContext(&Ctx);
163     T->Run();
164     T->TearDown();
165     [[maybe_unused]] const auto end_time = clock();
166     auto Result = Ctx.status();
167     switch (Result) {
168     case RunContext::Result_Fail:
169       tlog << RED << "[  FAILED  ] " << RESET << TestName << '\n';
170       ++FailCount;
171       break;
172     case RunContext::Result_Pass:
173       tlog << GREEN << "[       OK ] " << RESET << TestName;
174 #if __STDC_HOSTED__
175       tlog << " (took ";
176       if (start_time > end_time) {
177         tlog << "unknown - try rerunning)\n";
178       } else {
179         const auto duration = end_time - start_time;
180         const uint64_t duration_ms = duration * 1000 / CLOCKS_PER_SEC;
181         tlog << duration_ms << " ms)\n";
182       }
183 #else
184       tlog << '\n';
185 #endif
186       break;
187     }
188     ++TestCount;
189   }
190 
191   if (TestCount > 0) {
192     tlog << "Ran " << TestCount << " tests. "
193          << " PASS: " << TestCount - FailCount << ' ' << " FAIL: " << FailCount
194          << '\n';
195   } else {
196     tlog << "No tests run.\n";
197     if (TestFilter) {
198       tlog << "No matching test for " << TestFilter << '\n';
199     }
200   }
201 
202   return FailCount > 0 || TestCount == 0 ? 1 : 0;
203 }
204 
205 namespace internal {
206 
207 template bool test<char>(RunContext *Ctx, TestCondition Cond, char LHS,
208                          char RHS, const char *LHSStr, const char *RHSStr,
209                          const char *File, unsigned long Line);
210 
211 template bool test<short>(RunContext *Ctx, TestCondition Cond, short LHS,
212                           short RHS, const char *LHSStr, const char *RHSStr,
213                           const char *File, unsigned long Line);
214 
215 template bool test<int>(RunContext *Ctx, TestCondition Cond, int LHS, int RHS,
216                         const char *LHSStr, const char *RHSStr,
217                         const char *File, unsigned long Line);
218 
219 template bool test<long>(RunContext *Ctx, TestCondition Cond, long LHS,
220                          long RHS, const char *LHSStr, const char *RHSStr,
221                          const char *File, unsigned long Line);
222 
223 template bool test<long long>(RunContext *Ctx, TestCondition Cond,
224                               long long LHS, long long RHS, const char *LHSStr,
225                               const char *RHSStr, const char *File,
226                               unsigned long Line);
227 
228 template bool test<unsigned char>(RunContext *Ctx, TestCondition Cond,
229                                   unsigned char LHS, unsigned char RHS,
230                                   const char *LHSStr, const char *RHSStr,
231                                   const char *File, unsigned long Line);
232 
233 template bool test<unsigned short>(RunContext *Ctx, TestCondition Cond,
234                                    unsigned short LHS, unsigned short RHS,
235                                    const char *LHSStr, const char *RHSStr,
236                                    const char *File, unsigned long Line);
237 
238 template bool test<unsigned int>(RunContext *Ctx, TestCondition Cond,
239                                  unsigned int LHS, unsigned int RHS,
240                                  const char *LHSStr, const char *RHSStr,
241                                  const char *File, unsigned long Line);
242 
243 template bool test<unsigned long>(RunContext *Ctx, TestCondition Cond,
244                                   unsigned long LHS, unsigned long RHS,
245                                   const char *LHSStr, const char *RHSStr,
246                                   const char *File, unsigned long Line);
247 
248 template bool test<bool>(RunContext *Ctx, TestCondition Cond, bool LHS,
249                          bool RHS, const char *LHSStr, const char *RHSStr,
250                          const char *File, unsigned long Line);
251 
252 template bool test<unsigned long long>(RunContext *Ctx, TestCondition Cond,
253                                        unsigned long long LHS,
254                                        unsigned long long RHS,
255                                        const char *LHSStr, const char *RHSStr,
256                                        const char *File, unsigned long Line);
257 
258 // We cannot just use a single UInt128 specialization as that resolves to only
259 // one type, UInt<128> or __uint128_t. We want both overloads as we want to
260 // be able to unittest UInt<128> on platforms where UInt128 resolves to
261 // UInt128.
262 #ifdef __SIZEOF_INT128__
263 // When builtin __uint128_t type is available, include its specialization
264 // also.
265 template bool test<__uint128_t>(RunContext *Ctx, TestCondition Cond,
266                                 __uint128_t LHS, __uint128_t RHS,
267                                 const char *LHSStr, const char *RHSStr,
268                                 const char *File, unsigned long Line);
269 #endif
270 
271 template bool test<__llvm_libc::cpp::UInt<128>>(
272     RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<128> LHS,
273     __llvm_libc::cpp::UInt<128> RHS, const char *LHSStr, const char *RHSStr,
274     const char *File, unsigned long Line);
275 
276 template bool test<__llvm_libc::cpp::UInt<192>>(
277     RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<192> LHS,
278     __llvm_libc::cpp::UInt<192> RHS, const char *LHSStr, const char *RHSStr,
279     const char *File, unsigned long Line);
280 
281 template bool test<__llvm_libc::cpp::UInt<256>>(
282     RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<256> LHS,
283     __llvm_libc::cpp::UInt<256> RHS, const char *LHSStr, const char *RHSStr,
284     const char *File, unsigned long Line);
285 
286 template bool test<__llvm_libc::cpp::UInt<320>>(
287     RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<320> LHS,
288     __llvm_libc::cpp::UInt<320> RHS, const char *LHSStr, const char *RHSStr,
289     const char *File, unsigned long Line);
290 
291 template bool test<__llvm_libc::cpp::string_view>(
292     RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::string_view LHS,
293     __llvm_libc::cpp::string_view RHS, const char *LHSStr, const char *RHSStr,
294     const char *File, unsigned long Line);
295 
296 template bool test<__llvm_libc::cpp::string>(
297     RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::string LHS,
298     __llvm_libc::cpp::string RHS, const char *LHSStr, const char *RHSStr,
299     const char *File, unsigned long Line);
300 
301 } // namespace internal
302 
303 bool Test::testStrEq(const char *LHS, const char *RHS, const char *LHSStr,
304                      const char *RHSStr, const char *File, unsigned long Line) {
305   return internal::test(Ctx, Cond_EQ, LHS ? cpp::string(LHS) : cpp::string(),
306                         RHS ? cpp::string(RHS) : cpp::string(), LHSStr, RHSStr,
307                         File, Line);
308 }
309 
310 bool Test::testStrNe(const char *LHS, const char *RHS, const char *LHSStr,
311                      const char *RHSStr, const char *File, unsigned long Line) {
312   return internal::test(Ctx, Cond_NE, LHS ? cpp::string(LHS) : cpp::string(),
313                         RHS ? cpp::string(RHS) : cpp::string(), LHSStr, RHSStr,
314                         File, Line);
315 }
316 
317 bool Test::testMatch(bool MatchResult, MatcherBase &Matcher, const char *LHSStr,
318                      const char *RHSStr, const char *File, unsigned long Line) {
319   if (MatchResult)
320     return true;
321 
322   Ctx->markFail();
323   if (!Matcher.is_silent()) {
324     tlog << File << ":" << Line << ": FAILURE\n"
325          << "Failed to match " << LHSStr << " against " << RHSStr << ".\n";
326     Matcher.explainError();
327   }
328   return false;
329 }
330 
331 } // namespace testing
332 } // namespace __llvm_libc
333