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