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 __llvm_libc::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)]] __llvm_libc_clock_freq; 27 #define CLOCKS_PER_SEC __llvm_libc_clock_freq 28 #endif 29 #else 30 static long clock() { return 0; } 31 #define CLOCKS_PER_SEC 1 32 #endif 33 34 namespace __llvm_libc { 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<__llvm_libc::cpp::Int<128>>(RunContext *Ctx, TestCond Cond, 248 __llvm_libc::cpp::Int<128> LHS, 249 __llvm_libc::cpp::Int<128> RHS, 250 const char *LHSStr, 251 const char *RHSStr, 252 Location Loc); 253 254 template bool test<__llvm_libc::cpp::UInt<128>>(RunContext *Ctx, TestCond Cond, 255 __llvm_libc::cpp::UInt<128> LHS, 256 __llvm_libc::cpp::UInt<128> RHS, 257 const char *LHSStr, 258 const char *RHSStr, 259 Location Loc); 260 261 template bool test<__llvm_libc::cpp::UInt<192>>(RunContext *Ctx, TestCond Cond, 262 __llvm_libc::cpp::UInt<192> LHS, 263 __llvm_libc::cpp::UInt<192> RHS, 264 const char *LHSStr, 265 const char *RHSStr, 266 Location Loc); 267 268 template bool test<__llvm_libc::cpp::UInt<256>>(RunContext *Ctx, TestCond Cond, 269 __llvm_libc::cpp::UInt<256> LHS, 270 __llvm_libc::cpp::UInt<256> RHS, 271 const char *LHSStr, 272 const char *RHSStr, 273 Location Loc); 274 275 template bool test<__llvm_libc::cpp::UInt<320>>(RunContext *Ctx, TestCond Cond, 276 __llvm_libc::cpp::UInt<320> LHS, 277 __llvm_libc::cpp::UInt<320> RHS, 278 const char *LHSStr, 279 const char *RHSStr, 280 Location Loc); 281 282 template bool test<__llvm_libc::cpp::string_view>( 283 RunContext *Ctx, TestCond Cond, __llvm_libc::cpp::string_view LHS, 284 __llvm_libc::cpp::string_view RHS, const char *LHSStr, const char *RHSStr, 285 Location Loc); 286 287 template bool test<__llvm_libc::cpp::string>(RunContext *Ctx, TestCond Cond, 288 __llvm_libc::cpp::string LHS, 289 __llvm_libc::cpp::string RHS, 290 const char *LHSStr, 291 const char *RHSStr, Location Loc); 292 293 } // namespace internal 294 295 bool Test::testStrEq(const char *LHS, const char *RHS, const char *LHSStr, 296 const char *RHSStr, internal::Location Loc) { 297 return internal::test( 298 Ctx, TestCond::EQ, LHS ? cpp::string_view(LHS) : cpp::string_view(), 299 RHS ? cpp::string_view(RHS) : cpp::string_view(), LHSStr, RHSStr, Loc); 300 } 301 302 bool Test::testStrNe(const char *LHS, const char *RHS, const char *LHSStr, 303 const char *RHSStr, internal::Location Loc) { 304 return internal::test( 305 Ctx, TestCond::NE, LHS ? cpp::string_view(LHS) : cpp::string_view(), 306 RHS ? cpp::string_view(RHS) : cpp::string_view(), LHSStr, RHSStr, Loc); 307 } 308 309 bool Test::testMatch(bool MatchResult, MatcherBase &Matcher, const char *LHSStr, 310 const char *RHSStr, internal::Location Loc) { 311 if (MatchResult) 312 return true; 313 314 Ctx->markFail(); 315 if (!Matcher.is_silent()) { 316 tlog << Loc; 317 tlog << "Failed to match " << LHSStr << " against " << RHSStr << ".\n"; 318 Matcher.explainError(); 319 } 320 return false; 321 } 322 323 } // namespace testing 324 } // namespace __llvm_libc 325