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