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