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