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 | const IntegerToString<T, radix::Hex::WithPrefix> buffer(Value); |
48 | return buffer.view(); |
49 | } |
50 | |
51 | // When the value is of a standard integral type, just display it as normal. |
52 | template <typename T> |
53 | cpp::enable_if_t<cpp::is_integral_v<T> && (sizeof(T) <= sizeof(uint64_t)), |
54 | cpp::string> |
55 | describeValue(T Value) { |
56 | return cpp::to_string(Value); |
57 | } |
58 | |
59 | #ifdef LIBC_COMPILER_HAS_FIXED_POINT |
60 | template <typename T> |
61 | cpp::enable_if_t<cpp::is_fixed_point_v<T>, cpp::string> describeValue(T Value) { |
62 | using FXRep = fixed_point::FXRep<T>; |
63 | using comp_t = typename FXRep::CompType; |
64 | |
65 | return cpp::to_string(cpp::bit_cast<comp_t>(Value)) + " * 2^-" + |
66 | cpp::to_string(FXRep::FRACTION_LEN); |
67 | } |
68 | #endif // LIBC_COMPILER_HAS_FIXED_POINT |
69 | |
70 | cpp::string_view describeValue(const cpp::string &Value) { return Value; } |
71 | cpp::string_view describeValue(cpp::string_view Value) { return Value; } |
72 | |
73 | template <typename ValType> |
74 | bool test(RunContext *Ctx, TestCond Cond, ValType LHS, ValType RHS, |
75 | const char *LHSStr, const char *RHSStr, Location Loc) { |
76 | auto ExplainDifference = [=, &Ctx](bool Cond, |
77 | cpp::string_view OpString) -> bool { |
78 | if (Cond) |
79 | return true; |
80 | Ctx->markFail(); |
81 | size_t OffsetLength = OpString.size() > 2 ? OpString.size() - 2 : 0; |
82 | cpp::string Offset(OffsetLength, ' '); |
83 | tlog << Loc; |
84 | tlog << Offset << "Expected: " << LHSStr << '\n' |
85 | << Offset << "Which is: " << describeValue(LHS) << '\n' |
86 | << "To be " << OpString << ": " << RHSStr << '\n' |
87 | << Offset << "Which is: " << describeValue(RHS) << '\n'; |
88 | return false; |
89 | }; |
90 | |
91 | switch (Cond) { |
92 | case TestCond::EQ: |
93 | return ExplainDifference(LHS == RHS, "equal to" ); |
94 | case TestCond::NE: |
95 | return ExplainDifference(LHS != RHS, "not equal to" ); |
96 | case TestCond::LT: |
97 | return ExplainDifference(LHS < RHS, "less than" ); |
98 | case TestCond::LE: |
99 | return ExplainDifference(LHS <= RHS, "less than or equal to" ); |
100 | case TestCond::GT: |
101 | return ExplainDifference(LHS > RHS, "greater than" ); |
102 | case TestCond::GE: |
103 | return ExplainDifference(LHS >= RHS, "greater than or equal to" ); |
104 | } |
105 | __builtin_unreachable(); |
106 | } |
107 | |
108 | } // namespace internal |
109 | |
110 | Test *Test::Start = nullptr; |
111 | Test *Test::End = nullptr; |
112 | |
113 | int argc = 0; |
114 | char **argv = nullptr; |
115 | char **envp = nullptr; |
116 | |
117 | using internal::RunContext; |
118 | |
119 | void Test::addTest(Test *T) { |
120 | if (End == nullptr) { |
121 | Start = T; |
122 | End = T; |
123 | return; |
124 | } |
125 | |
126 | End->Next = T; |
127 | End = T; |
128 | } |
129 | |
130 | int Test::getNumTests() { |
131 | int N = 0; |
132 | for (Test *T = Start; T; T = T->Next, ++N) |
133 | ; |
134 | return N; |
135 | } |
136 | |
137 | int Test::runTests(const TestOptions &Options) { |
138 | const char *green = Options.PrintColor ? "\033[32m" : "" ; |
139 | const char *red = Options.PrintColor ? "\033[31m" : "" ; |
140 | const char *reset = Options.PrintColor ? "\033[0m" : "" ; |
141 | |
142 | int TestCount = getNumTests(); |
143 | if (TestCount) { |
144 | tlog << green << "[==========] " << reset << "Running " << TestCount |
145 | << " test" ; |
146 | if (TestCount > 1) |
147 | tlog << "s" ; |
148 | tlog << " from 1 test suite.\n" ; |
149 | } |
150 | |
151 | int FailCount = 0; |
152 | for (Test *T = Start; T != nullptr; T = T->Next) { |
153 | const char *TestName = T->getName(); |
154 | |
155 | if (Options.TestFilter && cpp::string(TestName) != Options.TestFilter) { |
156 | --TestCount; |
157 | continue; |
158 | } |
159 | |
160 | tlog << green << "[ RUN ] " << reset << TestName << '\n'; |
161 | [[maybe_unused]] const uint64_t start_time = static_cast<uint64_t>(clock()); |
162 | RunContext Ctx; |
163 | T->SetUp(); |
164 | T->setContext(&Ctx); |
165 | T->Run(); |
166 | T->TearDown(); |
167 | [[maybe_unused]] const uint64_t end_time = static_cast<uint64_t>(clock()); |
168 | switch (Ctx.status()) { |
169 | case RunContext::RunResult::Fail: |
170 | tlog << red << "[ FAILED ] " << reset << TestName << '\n'; |
171 | ++FailCount; |
172 | break; |
173 | case RunContext::RunResult::Pass: |
174 | tlog << green << "[ OK ] " << reset << TestName; |
175 | #ifdef LIBC_TEST_USE_CLOCK |
176 | tlog << " (" ; |
177 | if (start_time > end_time) { |
178 | tlog << "unknown - try rerunning)\n" ; |
179 | } else { |
180 | const auto duration = end_time - start_time; |
181 | const uint64_t duration_ms = (duration * 1000) / CLOCKS_PER_SEC; |
182 | const uint64_t duration_us = (duration * 1000 * 1000) / CLOCKS_PER_SEC; |
183 | const uint64_t duration_ns = |
184 | (duration * 1000 * 1000 * 1000) / CLOCKS_PER_SEC; |
185 | if (Options.TimeInMs || duration_ms != 0) |
186 | tlog << duration_ms << " ms)\n" ; |
187 | else if (duration_us != 0) |
188 | tlog << duration_us << " us)\n" ; |
189 | else |
190 | tlog << duration_ns << " ns)\n" ; |
191 | } |
192 | #else |
193 | tlog << '\n'; |
194 | #endif |
195 | break; |
196 | } |
197 | } |
198 | |
199 | if (TestCount > 0) { |
200 | tlog << "Ran " << TestCount << " tests. " |
201 | << " PASS: " << TestCount - FailCount << ' ' << " FAIL: " << FailCount |
202 | << '\n'; |
203 | } else { |
204 | tlog << "No tests run.\n" ; |
205 | if (Options.TestFilter) { |
206 | tlog << "No matching test for " << Options.TestFilter << '\n'; |
207 | } |
208 | } |
209 | |
210 | return FailCount > 0 || TestCount == 0 ? 1 : 0; |
211 | } |
212 | |
213 | namespace internal { |
214 | |
215 | #define TEST_SPECIALIZATION(TYPE) \ |
216 | template bool test<TYPE>(RunContext * Ctx, TestCond Cond, TYPE LHS, \ |
217 | TYPE RHS, const char *LHSStr, const char *RHSStr, \ |
218 | Location Loc) |
219 | |
220 | TEST_SPECIALIZATION(char); |
221 | TEST_SPECIALIZATION(short); |
222 | TEST_SPECIALIZATION(int); |
223 | TEST_SPECIALIZATION(long); |
224 | TEST_SPECIALIZATION(long long); |
225 | |
226 | TEST_SPECIALIZATION(signed char); |
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<96>); |
246 | TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<128>); |
247 | TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<192>); |
248 | TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<256>); |
249 | TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<320>); |
250 | |
251 | TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::string_view); |
252 | TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::string); |
253 | |
254 | #ifdef LIBC_COMPILER_HAS_FIXED_POINT |
255 | TEST_SPECIALIZATION(short fract); |
256 | TEST_SPECIALIZATION(fract); |
257 | TEST_SPECIALIZATION(long fract); |
258 | TEST_SPECIALIZATION(unsigned short fract); |
259 | TEST_SPECIALIZATION(unsigned fract); |
260 | TEST_SPECIALIZATION(unsigned long fract); |
261 | |
262 | TEST_SPECIALIZATION(short accum); |
263 | TEST_SPECIALIZATION(accum); |
264 | TEST_SPECIALIZATION(long accum); |
265 | TEST_SPECIALIZATION(unsigned short accum); |
266 | TEST_SPECIALIZATION(unsigned accum); |
267 | TEST_SPECIALIZATION(unsigned long accum); |
268 | #endif // LIBC_COMPILER_HAS_FIXED_POINT |
269 | |
270 | } // namespace internal |
271 | |
272 | bool Test::testStrEq(const char *LHS, const char *RHS, const char *LHSStr, |
273 | const char *RHSStr, internal::Location Loc) { |
274 | return internal::test( |
275 | Ctx, TestCond::EQ, LHS ? cpp::string_view(LHS) : cpp::string_view(), |
276 | RHS ? cpp::string_view(RHS) : cpp::string_view(), LHSStr, RHSStr, Loc); |
277 | } |
278 | |
279 | bool Test::testStrNe(const char *LHS, const char *RHS, const char *LHSStr, |
280 | const char *RHSStr, internal::Location Loc) { |
281 | return internal::test( |
282 | Ctx, TestCond::NE, LHS ? cpp::string_view(LHS) : cpp::string_view(), |
283 | RHS ? cpp::string_view(RHS) : cpp::string_view(), LHSStr, RHSStr, Loc); |
284 | } |
285 | |
286 | bool Test::testMatch(bool MatchResult, MatcherBase &Matcher, const char *LHSStr, |
287 | const char *RHSStr, internal::Location Loc) { |
288 | if (MatchResult) |
289 | return true; |
290 | |
291 | Ctx->markFail(); |
292 | if (!Matcher.is_silent()) { |
293 | tlog << Loc; |
294 | tlog << "Failed to match " << LHSStr << " against " << RHSStr << ".\n" ; |
295 | Matcher.explainError(); |
296 | } |
297 | return false; |
298 | } |
299 | |
300 | } // namespace testing |
301 | } // namespace LIBC_NAMESPACE_DECL |
302 | |