1 //===-- Base class for libc unittests ---------------------------*- C++ -*-===// 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 #ifndef LLVM_LIBC_UTILS_UNITTEST_LIBCTEST_H 10 #define LLVM_LIBC_UTILS_UNITTEST_LIBCTEST_H 11 12 // This file can only include headers from utils/CPP/ or utils/testutils. No 13 // other headers should be included. 14 15 #include "utils/CPP/TypeTraits.h" 16 #include "utils/testutils/ExecuteFunction.h" 17 #include "utils/testutils/StreamWrapper.h" 18 19 namespace __llvm_libc { 20 namespace testing { 21 22 class RunContext; 23 24 // Only the following conditions are supported. Notice that we do not have 25 // a TRUE or FALSE condition. That is because, C library funtions do not 26 // return boolean values, but use integral return values to indicate true or 27 // false conditions. Hence, it is more appropriate to use the other comparison 28 // conditions for such cases. 29 enum TestCondition { 30 Cond_None, 31 Cond_EQ, 32 Cond_NE, 33 Cond_LT, 34 Cond_LE, 35 Cond_GT, 36 Cond_GE, 37 }; 38 39 namespace internal { 40 41 template <typename ValType> 42 bool test(RunContext *Ctx, TestCondition Cond, ValType LHS, ValType RHS, 43 const char *LHSStr, const char *RHSStr, const char *File, 44 unsigned long Line); 45 46 } // namespace internal 47 48 struct MatcherBase { 49 virtual ~MatcherBase() {} 50 virtual void explainError(testutils::StreamWrapper &OS) { 51 OS << "unknown error\n"; 52 } 53 }; 54 55 template <typename T> struct Matcher : public MatcherBase { bool match(T &t); }; 56 57 // NOTE: One should not create instances and call methods on them directly. One 58 // should use the macros TEST or TEST_F to write test cases. 59 class Test { 60 private: 61 Test *Next = nullptr; 62 RunContext *Ctx = nullptr; 63 64 void setContext(RunContext *C) { Ctx = C; } 65 66 public: 67 virtual ~Test() {} 68 virtual void SetUp() {} 69 virtual void TearDown() {} 70 71 static int runTests(); 72 73 protected: 74 static void addTest(Test *T); 75 76 // We make use of a template function, with |LHS| and |RHS| as explicit 77 // parameters, for enhanced type checking. Other gtest like unittest 78 // frameworks have a similar function which takes a boolean argument 79 // instead of the explicit |LHS| and |RHS| arguments. This boolean argument 80 // is the result of the |Cond| operation on |LHS| and |RHS|. Though not bad, 81 // |Cond| on mismatched |LHS| and |RHS| types can potentially succeed because 82 // of type promotion. 83 template <typename ValType, 84 cpp::EnableIfType<cpp::IsIntegral<ValType>::Value, int> = 0> 85 bool test(TestCondition Cond, ValType LHS, ValType RHS, const char *LHSStr, 86 const char *RHSStr, const char *File, unsigned long Line) { 87 return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, File, Line); 88 } 89 90 template < 91 typename ValType, 92 cpp::EnableIfType<cpp::IsPointerType<ValType>::Value, ValType> = nullptr> 93 bool test(TestCondition Cond, ValType LHS, ValType RHS, const char *LHSStr, 94 const char *RHSStr, const char *File, unsigned long Line) { 95 return internal::test(Ctx, Cond, (unsigned long long)LHS, 96 (unsigned long long)RHS, LHSStr, RHSStr, File, Line); 97 } 98 99 bool testStrEq(const char *LHS, const char *RHS, const char *LHSStr, 100 const char *RHSStr, const char *File, unsigned long Line); 101 102 bool testStrNe(const char *LHS, const char *RHS, const char *LHSStr, 103 const char *RHSStr, const char *File, unsigned long Line); 104 105 bool testMatch(bool MatchResult, MatcherBase &Matcher, const char *LHSStr, 106 const char *RHSStr, const char *File, unsigned long Line); 107 108 bool testProcessExits(testutils::FunctionCaller *Func, int ExitCode, 109 const char *LHSStr, const char *RHSStr, 110 const char *File, unsigned long Line); 111 112 bool testProcessKilled(testutils::FunctionCaller *Func, int Signal, 113 const char *LHSStr, const char *RHSStr, 114 const char *File, unsigned long Line); 115 116 template <typename Func> testutils::FunctionCaller *createCallable(Func f) { 117 struct Callable : public testutils::FunctionCaller { 118 Func f; 119 Callable(Func f) : f(f) {} 120 void operator()() override { f(); } 121 }; 122 123 return new Callable(f); 124 } 125 126 private: 127 virtual void Run() = 0; 128 virtual const char *getName() const = 0; 129 130 static Test *Start; 131 static Test *End; 132 }; 133 134 namespace internal { 135 136 constexpr bool same_prefix(char const *lhs, char const *rhs, int const len) { 137 for (int i = 0; (*lhs || *rhs) && (i < len); ++lhs, ++rhs, ++i) 138 if (*lhs != *rhs) 139 return false; 140 return true; 141 } 142 143 constexpr bool valid_prefix(char const *lhs) { 144 return same_prefix(lhs, "LlvmLibc", 8); 145 } 146 147 // 'str' is a null terminated string of the form 148 // "const char *__llvm_libc::testing::internal::GetTypeName() [ParamType = XXX]" 149 // We return the substring that start at character '[' or a default message. 150 constexpr char const *GetPrettyFunctionParamType(char const *str) { 151 for (const char *ptr = str; *ptr != '\0'; ++ptr) 152 if (*ptr == '[') 153 return ptr; 154 return "UNSET : declare with REGISTER_TYPE_NAME"; 155 } 156 157 // This function recovers ParamType at compile time by using __PRETTY_FUNCTION__ 158 // It can be customized by using the REGISTER_TYPE_NAME macro below. 159 template <typename ParamType> static constexpr const char *GetTypeName() { 160 return GetPrettyFunctionParamType(__PRETTY_FUNCTION__); 161 } 162 163 template <typename T> 164 static inline void GenerateName(char *buffer, int buffer_size, 165 const char *prefix) { 166 if (buffer_size == 0) 167 return; 168 169 // Make sure string is null terminated. 170 --buffer_size; 171 buffer[buffer_size] = '\0'; 172 173 const auto AppendChar = [&](char c) { 174 if (buffer_size > 0) { 175 *buffer = c; 176 ++buffer; 177 --buffer_size; 178 } 179 }; 180 const auto AppendStr = [&](const char *str) { 181 for (; str && *str != '\0'; ++str) 182 AppendChar(*str); 183 }; 184 185 AppendStr(prefix); 186 AppendChar(' '); 187 AppendStr(GetTypeName<T>()); 188 AppendChar('\0'); 189 } 190 191 // TestCreator implements a linear hierarchy of test instances, effectively 192 // instanciating all tests with Types in a single object. 193 template <template <typename> class TemplatedTestClass, typename... Types> 194 struct TestCreator; 195 196 template <template <typename> class TemplatedTestClass, typename Head, 197 typename... Tail> 198 struct TestCreator<TemplatedTestClass, Head, Tail...> 199 : private TestCreator<TemplatedTestClass, Tail...> { 200 TemplatedTestClass<Head> instance; 201 }; 202 203 template <template <typename> class TemplatedTestClass> 204 struct TestCreator<TemplatedTestClass> {}; 205 206 // A type list to declare the set of types to instantiate the tests with. 207 template <typename... Types> struct TypeList { 208 template <template <typename> class TemplatedTestClass> struct Tests { 209 using type = TestCreator<TemplatedTestClass, Types...>; 210 }; 211 }; 212 213 } // namespace internal 214 215 // Make TypeList visible in __llvm_libc::testing. 216 template <typename... Types> using TypeList = internal::TypeList<Types...>; 217 218 } // namespace testing 219 } // namespace __llvm_libc 220 221 // For TYPED_TEST and TYPED_TEST_F below we need to display which type was used 222 // to run the test. The default will return the fully qualified canonical type 223 // but it can be difficult to read. We provide the following macro to allow the 224 // client to register the type name as they see it in the code. 225 #define REGISTER_TYPE_NAME(TYPE) \ 226 template <> \ 227 constexpr const char *__llvm_libc::testing::internal::GetTypeName<TYPE>() { \ 228 return "[ParamType = " #TYPE "]"; \ 229 } 230 231 #define TYPED_TEST(SuiteName, TestName, TypeList) \ 232 static_assert( \ 233 __llvm_libc::testing::internal::valid_prefix(#SuiteName), \ 234 "All LLVM-libc TYPED_TEST suite names must start with 'LlvmLibc'."); \ 235 template <typename T> \ 236 class SuiteName##_##TestName : public __llvm_libc::testing::Test { \ 237 public: \ 238 using ParamType = T; \ 239 char name[256]; \ 240 SuiteName##_##TestName() { \ 241 addTest(this); \ 242 __llvm_libc::testing::internal::GenerateName<T>( \ 243 name, sizeof(name), #SuiteName "." #TestName); \ 244 } \ 245 void Run() override; \ 246 const char *getName() const override { return name; } \ 247 }; \ 248 TypeList::Tests<SuiteName##_##TestName>::type \ 249 SuiteName##_##TestName##_Instance; \ 250 template <typename T> void SuiteName##_##TestName<T>::Run() 251 252 #define TYPED_TEST_F(SuiteClass, TestName, TypeList) \ 253 static_assert(__llvm_libc::testing::internal::valid_prefix(#SuiteClass), \ 254 "All LLVM-libc TYPED_TEST_F suite class names must start " \ 255 "with 'LlvmLibc'."); \ 256 template <typename T> class SuiteClass##_##TestName : public SuiteClass<T> { \ 257 public: \ 258 using ParamType = T; \ 259 char name[256]; \ 260 SuiteClass##_##TestName() { \ 261 SuiteClass<T>::addTest(this); \ 262 __llvm_libc::testing::internal::GenerateName<T>( \ 263 name, sizeof(name), #SuiteClass "." #TestName); \ 264 } \ 265 void Run() override; \ 266 const char *getName() const override { return name; } \ 267 }; \ 268 TypeList::Tests<SuiteClass##_##TestName>::type \ 269 SuiteClass##_##TestName##_Instance; \ 270 template <typename T> void SuiteClass##_##TestName<T>::Run() 271 272 #define TEST(SuiteName, TestName) \ 273 static_assert(__llvm_libc::testing::internal::valid_prefix(#SuiteName), \ 274 "All LLVM-libc TEST suite names must start with 'LlvmLibc'."); \ 275 class SuiteName##_##TestName : public __llvm_libc::testing::Test { \ 276 public: \ 277 SuiteName##_##TestName() { addTest(this); } \ 278 void Run() override; \ 279 const char *getName() const override { return #SuiteName "." #TestName; } \ 280 }; \ 281 SuiteName##_##TestName SuiteName##_##TestName##_Instance; \ 282 void SuiteName##_##TestName::Run() 283 284 #define TEST_F(SuiteClass, TestName) \ 285 static_assert( \ 286 __llvm_libc::testing::internal::valid_prefix(#SuiteClass), \ 287 "All LLVM-libc TEST_F suite class names must start with 'LlvmLibc'."); \ 288 class SuiteClass##_##TestName : public SuiteClass { \ 289 public: \ 290 SuiteClass##_##TestName() { addTest(this); } \ 291 void Run() override; \ 292 const char *getName() const override { return #SuiteClass "." #TestName; } \ 293 }; \ 294 SuiteClass##_##TestName SuiteClass##_##TestName##_Instance; \ 295 void SuiteClass##_##TestName::Run() 296 297 #define EXPECT_EQ(LHS, RHS) \ 298 this->test(__llvm_libc::testing::Cond_EQ, (LHS), (RHS), #LHS, #RHS, \ 299 __FILE__, __LINE__) 300 #define ASSERT_EQ(LHS, RHS) \ 301 if (!EXPECT_EQ(LHS, RHS)) \ 302 return 303 304 #define EXPECT_NE(LHS, RHS) \ 305 this->test(__llvm_libc::testing::Cond_NE, (LHS), (RHS), #LHS, #RHS, \ 306 __FILE__, __LINE__) 307 #define ASSERT_NE(LHS, RHS) \ 308 if (!EXPECT_NE(LHS, RHS)) \ 309 return 310 311 #define EXPECT_LT(LHS, RHS) \ 312 this->test(__llvm_libc::testing::Cond_LT, (LHS), (RHS), #LHS, #RHS, \ 313 __FILE__, __LINE__) 314 #define ASSERT_LT(LHS, RHS) \ 315 if (!EXPECT_LT(LHS, RHS)) \ 316 return 317 318 #define EXPECT_LE(LHS, RHS) \ 319 this->test(__llvm_libc::testing::Cond_LE, (LHS), (RHS), #LHS, #RHS, \ 320 __FILE__, __LINE__) 321 #define ASSERT_LE(LHS, RHS) \ 322 if (!EXPECT_LE(LHS, RHS)) \ 323 return 324 325 #define EXPECT_GT(LHS, RHS) \ 326 this->test(__llvm_libc::testing::Cond_GT, (LHS), (RHS), #LHS, #RHS, \ 327 __FILE__, __LINE__) 328 #define ASSERT_GT(LHS, RHS) \ 329 if (!EXPECT_GT(LHS, RHS)) \ 330 return 331 332 #define EXPECT_GE(LHS, RHS) \ 333 this->test(__llvm_libc::testing::Cond_GE, (LHS), (RHS), #LHS, #RHS, \ 334 __FILE__, __LINE__) 335 #define ASSERT_GE(LHS, RHS) \ 336 if (!EXPECT_GE(LHS, RHS)) \ 337 return 338 339 #define EXPECT_STREQ(LHS, RHS) \ 340 this->testStrEq((LHS), (RHS), #LHS, #RHS, __FILE__, __LINE__) 341 #define ASSERT_STREQ(LHS, RHS) \ 342 if (!EXPECT_STREQ(LHS, RHS)) \ 343 return 344 345 #define EXPECT_STRNE(LHS, RHS) \ 346 this->testStrNe((LHS), (RHS), #LHS, #RHS, __FILE__, __LINE__) 347 #define ASSERT_STRNE(LHS, RHS) \ 348 if (!EXPECT_STRNE(LHS, RHS)) \ 349 return 350 351 #define EXPECT_TRUE(VAL) EXPECT_EQ((VAL), true) 352 353 #define ASSERT_TRUE(VAL) \ 354 if (!EXPECT_TRUE(VAL)) \ 355 return 356 357 #define EXPECT_FALSE(VAL) EXPECT_EQ((VAL), false) 358 359 #define ASSERT_FALSE(VAL) \ 360 if (!EXPECT_FALSE(VAL)) \ 361 return 362 363 #define EXPECT_EXITS(FUNC, EXIT) \ 364 this->testProcessExits(__llvm_libc::testing::Test::createCallable(FUNC), \ 365 EXIT, #FUNC, #EXIT, __FILE__, __LINE__) 366 367 #define ASSERT_EXITS(FUNC, EXIT) \ 368 if (!EXPECT_EXITS(FUNC, EXIT)) \ 369 return 370 371 #define EXPECT_DEATH(FUNC, SIG) \ 372 this->testProcessKilled(__llvm_libc::testing::Test::createCallable(FUNC), \ 373 SIG, #FUNC, #SIG, __FILE__, __LINE__) 374 375 #define ASSERT_DEATH(FUNC, EXIT) \ 376 if (!EXPECT_DEATH(FUNC, EXIT)) \ 377 return 378 379 #define __CAT1(a, b) a##b 380 #define __CAT(a, b) __CAT1(a, b) 381 #define UNIQUE_VAR(prefix) __CAT(prefix, __LINE__) 382 383 #define EXPECT_THAT(MATCH, MATCHER) \ 384 do { \ 385 auto UNIQUE_VAR(__matcher) = (MATCHER); \ 386 this->testMatch(UNIQUE_VAR(__matcher).match((MATCH)), \ 387 UNIQUE_VAR(__matcher), #MATCH, #MATCHER, __FILE__, \ 388 __LINE__); \ 389 } while (0) 390 391 #define ASSERT_THAT(MATCH, MATCHER) \ 392 do { \ 393 auto UNIQUE_VAR(__matcher) = (MATCHER); \ 394 if (!this->testMatch(UNIQUE_VAR(__matcher).match((MATCH)), \ 395 UNIQUE_VAR(__matcher), #MATCH, #MATCHER, __FILE__, \ 396 __LINE__)) \ 397 return; \ 398 } while (0) 399 400 #define WITH_SIGNAL(X) X 401 402 #endif // LLVM_LIBC_UTILS_UNITTEST_LIBCTEST_H 403