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