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/properties/types.h" // LIBC_TYPES_HAS_INT128 |
16 | #include "src/__support/uint128.h" |
17 | #include "test/UnitTest/TestLogger.h" |
18 | |
19 | #if __STDC_HOSTED__ |
20 | #include <time.h> |
21 | #define LIBC_TEST_USE_CLOCK |
22 | #elif defined(TARGET_SUPPORTS_CLOCK) |
23 | #include <time.h> |
24 | |
25 | #include "src/time/clock.h" |
26 | extern "C" clock_t clock() noexcept { return LIBC_NAMESPACE::clock(); } |
27 | #define LIBC_TEST_USE_CLOCK |
28 | #endif |
29 | |
30 | namespace LIBC_NAMESPACE { |
31 | namespace testing { |
32 | |
33 | namespace internal { |
34 | |
35 | TestLogger &operator<<(TestLogger &logger, Location Loc) { |
36 | return logger << Loc.file << ":" << Loc.line << ": FAILURE\n" ; |
37 | } |
38 | |
39 | // When the value is UInt128, __uint128_t or wider, show its hexadecimal |
40 | // digits. |
41 | template <typename T> |
42 | cpp::enable_if_t<(cpp::is_integral_v<T> && (sizeof(T) > sizeof(uint64_t))) || |
43 | is_big_int_v<T>, |
44 | cpp::string> |
45 | describeValue(T Value) { |
46 | static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt" ); |
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::runTests(const char *TestFilter) { |
131 | int TestCount = 0; |
132 | int FailCount = 0; |
133 | for (Test *T = Start; T != nullptr; T = T->Next) { |
134 | const char *TestName = T->getName(); |
135 | cpp::string StrTestName(TestName); |
136 | constexpr auto GREEN = "\033[32m" ; |
137 | constexpr auto RED = "\033[31m" ; |
138 | constexpr auto RESET = "\033[0m" ; |
139 | if ((TestFilter != nullptr) && (StrTestName != TestFilter)) { |
140 | continue; |
141 | } |
142 | tlog << GREEN << "[ RUN ] " << RESET << TestName << '\n'; |
143 | [[maybe_unused]] const auto start_time = clock(); |
144 | RunContext Ctx; |
145 | T->SetUp(); |
146 | T->setContext(&Ctx); |
147 | T->Run(); |
148 | T->TearDown(); |
149 | [[maybe_unused]] const auto end_time = clock(); |
150 | switch (Ctx.status()) { |
151 | case RunContext::RunResult::Fail: |
152 | tlog << RED << "[ FAILED ] " << RESET << TestName << '\n'; |
153 | ++FailCount; |
154 | break; |
155 | case RunContext::RunResult::Pass: |
156 | tlog << GREEN << "[ OK ] " << RESET << TestName; |
157 | #ifdef LIBC_TEST_USE_CLOCK |
158 | tlog << " (took " ; |
159 | if (start_time > end_time) { |
160 | tlog << "unknown - try rerunning)\n" ; |
161 | } else { |
162 | const auto duration = end_time - start_time; |
163 | const uint64_t duration_ms = (duration * 1000) / CLOCKS_PER_SEC; |
164 | const uint64_t duration_us = (duration * 1000 * 1000) / CLOCKS_PER_SEC; |
165 | const uint64_t duration_ns = |
166 | (duration * 1000 * 1000 * 1000) / CLOCKS_PER_SEC; |
167 | if (duration_ms != 0) |
168 | tlog << duration_ms << " ms)\n" ; |
169 | else if (duration_us != 0) |
170 | tlog << duration_us << " us)\n" ; |
171 | else |
172 | tlog << duration_ns << " ns)\n" ; |
173 | } |
174 | #else |
175 | tlog << '\n'; |
176 | #endif |
177 | break; |
178 | } |
179 | ++TestCount; |
180 | } |
181 | |
182 | if (TestCount > 0) { |
183 | tlog << "Ran " << TestCount << " tests. " |
184 | << " PASS: " << TestCount - FailCount << ' ' << " FAIL: " << FailCount |
185 | << '\n'; |
186 | } else { |
187 | tlog << "No tests run.\n" ; |
188 | if (TestFilter) { |
189 | tlog << "No matching test for " << TestFilter << '\n'; |
190 | } |
191 | } |
192 | |
193 | return FailCount > 0 || TestCount == 0 ? 1 : 0; |
194 | } |
195 | |
196 | namespace internal { |
197 | |
198 | #define TEST_SPECIALIZATION(TYPE) \ |
199 | template bool test<TYPE>(RunContext * Ctx, TestCond Cond, TYPE LHS, \ |
200 | TYPE RHS, const char *LHSStr, const char *RHSStr, \ |
201 | Location Loc) |
202 | |
203 | TEST_SPECIALIZATION(char); |
204 | TEST_SPECIALIZATION(short); |
205 | TEST_SPECIALIZATION(int); |
206 | TEST_SPECIALIZATION(long); |
207 | TEST_SPECIALIZATION(long long); |
208 | |
209 | TEST_SPECIALIZATION(unsigned char); |
210 | TEST_SPECIALIZATION(unsigned short); |
211 | TEST_SPECIALIZATION(unsigned int); |
212 | TEST_SPECIALIZATION(unsigned long); |
213 | TEST_SPECIALIZATION(unsigned long long); |
214 | |
215 | TEST_SPECIALIZATION(bool); |
216 | |
217 | // We cannot just use a single UInt128 specialization as that resolves to only |
218 | // one type, UInt<128> or __uint128_t. We want both overloads as we want to |
219 | #ifdef LIBC_TYPES_HAS_INT128 |
220 | // When builtin __uint128_t type is available, include its specialization |
221 | // also. |
222 | TEST_SPECIALIZATION(__uint128_t); |
223 | #endif // LIBC_TYPES_HAS_INT128 |
224 | |
225 | TEST_SPECIALIZATION(LIBC_NAMESPACE::Int<128>); |
226 | |
227 | TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<128>); |
228 | TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<192>); |
229 | TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<256>); |
230 | TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<320>); |
231 | |
232 | TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::string_view); |
233 | TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::string); |
234 | |
235 | #ifdef LIBC_COMPILER_HAS_FIXED_POINT |
236 | TEST_SPECIALIZATION(short fract); |
237 | TEST_SPECIALIZATION(fract); |
238 | TEST_SPECIALIZATION(long fract); |
239 | TEST_SPECIALIZATION(unsigned short fract); |
240 | TEST_SPECIALIZATION(unsigned fract); |
241 | TEST_SPECIALIZATION(unsigned long fract); |
242 | |
243 | TEST_SPECIALIZATION(short accum); |
244 | TEST_SPECIALIZATION(accum); |
245 | TEST_SPECIALIZATION(long accum); |
246 | TEST_SPECIALIZATION(unsigned short accum); |
247 | TEST_SPECIALIZATION(unsigned accum); |
248 | TEST_SPECIALIZATION(unsigned long accum); |
249 | #endif // LIBC_COMPILER_HAS_FIXED_POINT |
250 | |
251 | } // namespace internal |
252 | |
253 | bool Test::testStrEq(const char *LHS, const char *RHS, const char *LHSStr, |
254 | const char *RHSStr, internal::Location Loc) { |
255 | return internal::test( |
256 | Ctx, Cond: TestCond::EQ, LHS: LHS ? cpp::string_view(LHS) : cpp::string_view(), |
257 | RHS: RHS ? cpp::string_view(RHS) : cpp::string_view(), LHSStr, RHSStr, Loc); |
258 | } |
259 | |
260 | bool Test::testStrNe(const char *LHS, const char *RHS, const char *LHSStr, |
261 | const char *RHSStr, internal::Location Loc) { |
262 | return internal::test( |
263 | Ctx, Cond: TestCond::NE, LHS: LHS ? cpp::string_view(LHS) : cpp::string_view(), |
264 | RHS: RHS ? cpp::string_view(RHS) : cpp::string_view(), LHSStr, RHSStr, Loc); |
265 | } |
266 | |
267 | bool Test::testMatch(bool MatchResult, MatcherBase &Matcher, const char *LHSStr, |
268 | const char *RHSStr, internal::Location Loc) { |
269 | if (MatchResult) |
270 | return true; |
271 | |
272 | Ctx->markFail(); |
273 | if (!Matcher.is_silent()) { |
274 | tlog << Loc; |
275 | tlog << "Failed to match " << LHSStr << " against " << RHSStr << ".\n" ; |
276 | Matcher.explainError(); |
277 | } |
278 | return false; |
279 | } |
280 | |
281 | } // namespace testing |
282 | } // namespace LIBC_NAMESPACE |
283 | |