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