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_H 10 #define LLVM_LIBC_UTILS_UNITTEST_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 63 public: 64 virtual ~Test() {} 65 virtual void SetUp() {} 66 virtual void TearDown() {} 67 68 static int runTests(); 69 70 protected: 71 static void addTest(Test *T); 72 73 // We make use of a template function, with |LHS| and |RHS| as explicit 74 // parameters, for enhanced type checking. Other gtest like unittest 75 // frameworks have a similar function which takes a boolean argument 76 // instead of the explicit |LHS| and |RHS| arguments. This boolean argument 77 // is the result of the |Cond| operation on |LHS| and |RHS|. Though not bad, 78 // |Cond| on mismatched |LHS| and |RHS| types can potentially succeed because 79 // of type promotion. 80 template <typename ValType, 81 cpp::EnableIfType<cpp::IsIntegral<ValType>::Value, ValType> = 0> 82 static bool test(RunContext &Ctx, TestCondition Cond, ValType LHS, 83 ValType RHS, const char *LHSStr, const char *RHSStr, 84 const char *File, unsigned long Line) { 85 return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, File, Line); 86 } 87 88 template < 89 typename ValType, 90 cpp::EnableIfType<cpp::IsPointerType<ValType>::Value, ValType> = nullptr> 91 static bool test(RunContext &Ctx, TestCondition Cond, ValType LHS, 92 ValType RHS, const char *LHSStr, const char *RHSStr, 93 const char *File, unsigned long Line) { 94 return internal::test(Ctx, Cond, (unsigned long long)LHS, 95 (unsigned long long)RHS, LHSStr, RHSStr, File, Line); 96 } 97 98 static bool testStrEq(RunContext &Ctx, const char *LHS, const char *RHS, 99 const char *LHSStr, const char *RHSStr, 100 const char *File, unsigned long Line); 101 102 static bool testStrNe(RunContext &Ctx, const char *LHS, const char *RHS, 103 const char *LHSStr, const char *RHSStr, 104 const char *File, unsigned long Line); 105 106 static bool testMatch(RunContext &Ctx, bool MatchResult, MatcherBase &Matcher, 107 const char *LHSStr, const char *RHSStr, 108 const char *File, unsigned long Line); 109 110 static bool testProcessExits(RunContext &Ctx, testutils::FunctionCaller *Func, 111 int ExitCode, const char *LHSStr, 112 const char *RHSStr, const char *File, 113 unsigned long Line); 114 115 static bool testProcessKilled(RunContext &Ctx, 116 testutils::FunctionCaller *Func, int Signal, 117 const char *LHSStr, const char *RHSStr, 118 const char *File, unsigned long Line); 119 120 template <typename Func> testutils::FunctionCaller *createCallable(Func f) { 121 struct Callable : public testutils::FunctionCaller { 122 Func f; 123 Callable(Func f) : f(f) {} 124 void operator()() override { f(); } 125 }; 126 127 return new Callable(f); 128 } 129 130 private: 131 virtual void Run(RunContext &Ctx) = 0; 132 virtual const char *getName() const = 0; 133 134 static Test *Start; 135 static Test *End; 136 }; 137 138 } // namespace testing 139 } // namespace __llvm_libc 140 141 #define TEST(SuiteName, TestName) \ 142 class SuiteName##_##TestName : public __llvm_libc::testing::Test { \ 143 public: \ 144 SuiteName##_##TestName() { addTest(this); } \ 145 void Run(__llvm_libc::testing::RunContext &) override; \ 146 const char *getName() const override { return #SuiteName "." #TestName; } \ 147 }; \ 148 SuiteName##_##TestName SuiteName##_##TestName##_Instance; \ 149 void SuiteName##_##TestName::Run(__llvm_libc::testing::RunContext &Ctx) 150 151 #define TEST_F(SuiteClass, TestName) \ 152 class SuiteClass##_##TestName : public SuiteClass { \ 153 public: \ 154 SuiteClass##_##TestName() { addTest(this); } \ 155 void Run(__llvm_libc::testing::RunContext &) override; \ 156 const char *getName() const override { return #SuiteClass "." #TestName; } \ 157 }; \ 158 SuiteClass##_##TestName SuiteClass##_##TestName##_Instance; \ 159 void SuiteClass##_##TestName::Run(__llvm_libc::testing::RunContext &Ctx) 160 161 #define EXPECT_EQ(LHS, RHS) \ 162 __llvm_libc::testing::Test::test(Ctx, __llvm_libc::testing::Cond_EQ, (LHS), \ 163 (RHS), #LHS, #RHS, __FILE__, __LINE__) 164 #define ASSERT_EQ(LHS, RHS) \ 165 if (!EXPECT_EQ(LHS, RHS)) \ 166 return 167 168 #define EXPECT_NE(LHS, RHS) \ 169 __llvm_libc::testing::Test::test(Ctx, __llvm_libc::testing::Cond_NE, (LHS), \ 170 (RHS), #LHS, #RHS, __FILE__, __LINE__) 171 #define ASSERT_NE(LHS, RHS) \ 172 if (!EXPECT_NE(LHS, RHS)) \ 173 return 174 175 #define EXPECT_LT(LHS, RHS) \ 176 __llvm_libc::testing::Test::test(Ctx, __llvm_libc::testing::Cond_LT, (LHS), \ 177 (RHS), #LHS, #RHS, __FILE__, __LINE__) 178 #define ASSERT_LT(LHS, RHS) \ 179 if (!EXPECT_LT(LHS, RHS)) \ 180 return 181 182 #define EXPECT_LE(LHS, RHS) \ 183 __llvm_libc::testing::Test::test(Ctx, __llvm_libc::testing::Cond_LE, (LHS), \ 184 (RHS), #LHS, #RHS, __FILE__, __LINE__) 185 #define ASSERT_LE(LHS, RHS) \ 186 if (!EXPECT_LE(LHS, RHS)) \ 187 return 188 189 #define EXPECT_GT(LHS, RHS) \ 190 __llvm_libc::testing::Test::test(Ctx, __llvm_libc::testing::Cond_GT, (LHS), \ 191 (RHS), #LHS, #RHS, __FILE__, __LINE__) 192 #define ASSERT_GT(LHS, RHS) \ 193 if (!EXPECT_GT(LHS, RHS)) \ 194 return 195 196 #define EXPECT_GE(LHS, RHS) \ 197 __llvm_libc::testing::Test::test(Ctx, __llvm_libc::testing::Cond_GE, (LHS), \ 198 (RHS), #LHS, #RHS, __FILE__, __LINE__) 199 #define ASSERT_GE(LHS, RHS) \ 200 if (!EXPECT_GE(LHS, RHS)) \ 201 return 202 203 #define EXPECT_STREQ(LHS, RHS) \ 204 __llvm_libc::testing::Test::testStrEq(Ctx, (LHS), (RHS), #LHS, #RHS, \ 205 __FILE__, __LINE__) 206 #define ASSERT_STREQ(LHS, RHS) \ 207 if (!EXPECT_STREQ(LHS, RHS)) \ 208 return 209 210 #define EXPECT_STRNE(LHS, RHS) \ 211 __llvm_libc::testing::Test::testStrNe(Ctx, (LHS), (RHS), #LHS, #RHS, \ 212 __FILE__, __LINE__) 213 #define ASSERT_STRNE(LHS, RHS) \ 214 if (!EXPECT_STRNE(LHS, RHS)) \ 215 return 216 217 #define EXPECT_TRUE(VAL) EXPECT_EQ((VAL), true) 218 219 #define ASSERT_TRUE(VAL) \ 220 if (!EXPECT_TRUE(VAL)) \ 221 return 222 223 #define EXPECT_FALSE(VAL) EXPECT_EQ((VAL), false) 224 225 #define ASSERT_FALSE(VAL) \ 226 if (!EXPECT_FALSE(VAL)) \ 227 return 228 229 #define EXPECT_EXITS(FUNC, EXIT) \ 230 __llvm_libc::testing::Test::testProcessExits( \ 231 Ctx, __llvm_libc::testing::Test::createCallable(FUNC), EXIT, #FUNC, \ 232 #EXIT, __FILE__, __LINE__) 233 234 #define ASSERT_EXITS(FUNC, EXIT) \ 235 if (!EXPECT_EXITS(FUNC, EXIT)) \ 236 return 237 238 #define EXPECT_DEATH(FUNC, SIG) \ 239 __llvm_libc::testing::Test::testProcessKilled( \ 240 Ctx, __llvm_libc::testing::Test::createCallable(FUNC), SIG, #FUNC, #SIG, \ 241 __FILE__, __LINE__) 242 243 #define ASSERT_DEATH(FUNC, EXIT) \ 244 if (!EXPECT_DEATH(FUNC, EXIT)) \ 245 return 246 247 #define __CAT1(a, b) a##b 248 #define __CAT(a, b) __CAT1(a, b) 249 #define UNIQUE_VAR(prefix) __CAT(prefix, __LINE__) 250 251 #define EXPECT_THAT(MATCH, MATCHER) \ 252 do { \ 253 auto UNIQUE_VAR(__matcher) = (MATCHER); \ 254 __llvm_libc::testing::Test::testMatch( \ 255 Ctx, UNIQUE_VAR(__matcher).match((MATCH)), UNIQUE_VAR(__matcher), \ 256 #MATCH, #MATCHER, __FILE__, __LINE__); \ 257 } while (0) 258 259 #define ASSERT_THAT(MATCH, MATCHER) \ 260 do { \ 261 auto UNIQUE_VAR(__matcher) = (MATCHER); \ 262 if (!__llvm_libc::testing::Test::testMatch( \ 263 Ctx, UNIQUE_VAR(__matcher).match((MATCH)), UNIQUE_VAR(__matcher), \ 264 #MATCH, #MATCHER, __FILE__, __LINE__)) \ 265 return; \ 266 } while (0) 267 268 #endif // LLVM_LIBC_UTILS_UNITTEST_H 269