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