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