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