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