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