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