[libc] Replace the use of gtest with a new light weight unittest framework.
[lldb.git] / libc / utils / UnitTest / Test.h
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 // This file should stricly not include any other file. Not even standard
10 // library headers.
11
12 namespace llvm_libc {
13 namespace testing {
14
15 // We define our own EnableIf and IsIntegerType traits because we do not want to
16 // include even the standard header <type_traits>.
17 template <bool B, typename T> struct EnableIf;
18 template <typename T> struct EnableIf<true, T> { typedef T Type; };
19
20 template <bool B, typename T>
21 using EnableIfType = typename EnableIf<B, T>::Type;
22
23 template <typename Type> struct IsIntegerType {
24   static const bool Value = false;
25 };
26
27 template <> struct IsIntegerType<char> { static const bool Value = true; };
28 template <> struct IsIntegerType<unsigned char> {
29   static const bool Value = true;
30 };
31
32 template <> struct IsIntegerType<short> { static const bool Value = true; };
33 template <> struct IsIntegerType<unsigned short> {
34   static const bool Value = true;
35 };
36
37 template <> struct IsIntegerType<int> { static const bool Value = true; };
38 template <> struct IsIntegerType<unsigned int> {
39   static const bool Value = true;
40 };
41
42 template <> struct IsIntegerType<long> { static const bool Value = true; };
43 template <> struct IsIntegerType<unsigned long> {
44   static const bool Value = true;
45 };
46
47 template <> struct IsIntegerType<long long> { static const bool Value = true; };
48 template <> struct IsIntegerType<unsigned long long> {
49   static const bool Value = true;
50 };
51
52 template <typename T> struct IsPointerType;
53
54 template <typename T> struct IsPointerType<T *> {
55   static const bool Value = true;
56 };
57
58 class RunContext;
59
60 // Only the following conditions are supported. Notice that we do not have
61 // a TRUE or FALSE condition. That is because, C library funtions do not
62 // return, but use integral return values to indicate true or false
63 // conditions. Hence, it is more appropriate to use the other comparison
64 // condtions for such cases.
65 enum TestCondition {
66   Cond_None,
67   Cond_EQ,
68   Cond_NE,
69   Cond_LT,
70   Cond_LE,
71   Cond_GT,
72   Cond_GE,
73 };
74
75 namespace internal {
76
77 template <typename ValType>
78 bool test(RunContext &Ctx, TestCondition Cond, ValType LHS, ValType RHS,
79           const char *LHSStr, const char *RHSStr, const char *File,
80           unsigned long Line);
81
82 } // namespace internal
83
84 // NOTE: One should not create instances and call methods on them directly. One
85 // should use the macros TEST or TEST_F to write test cases.
86 class Test {
87 private:
88   Test *Next = nullptr;
89
90 public:
91   virtual ~Test() {}
92   virtual void SetUp() {}
93   virtual void TearDown() {}
94
95   static int runTests();
96
97 protected:
98   static void addTest(Test *T);
99
100   // We make use of a template function, with |LHS| and |RHS| as explicit
101   // parameters, for enhanced type checking. Other gtest like test unittest
102   // frameworks have a similar functions which takes a boolean argument
103   // instead of the explicit |LHS| and |RHS| arguments. This boolean argument
104   // is the result of the |Cond| operation on |LHS| and |RHS|. Though not bad,
105   // mismatched |LHS| and |RHS| types can potentially succeed because of type
106   // promotion.
107   template <typename ValType,
108             EnableIfType<IsIntegerType<ValType>::Value, ValType> = 0>
109   static bool test(RunContext &Ctx, TestCondition Cond, ValType LHS,
110                    ValType RHS, const char *LHSStr, const char *RHSStr,
111                    const char *File, unsigned long Line) {
112     return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, File, Line);
113   }
114
115   template <typename ValType,
116             EnableIfType<IsPointerType<ValType>::Value, ValType> = nullptr>
117   static bool test(RunContext &Ctx, TestCondition Cond, ValType LHS,
118                    ValType RHS, const char *LHSStr, const char *RHSStr,
119                    const char *File, unsigned long Line) {
120     return internal::test(Ctx, Cond, (unsigned long long)LHS,
121                           (unsigned long long)RHS, LHSStr, RHSStr, File, Line);
122   }
123
124   static bool testStrEq(RunContext &Ctx, const char *LHS, const char *RHS,
125                         const char *LHSStr, const char *RHSStr,
126                         const char *File, unsigned long Line);
127
128   static bool testStrNe(RunContext &Ctx, const char *LHS, const char *RHS,
129                         const char *LHSStr, const char *RHSStr,
130                         const char *File, unsigned long Line);
131
132 private:
133   virtual void Run(RunContext &Ctx) = 0;
134   virtual const char *getName() const = 0;
135
136   static Test *Start;
137   static Test *End;
138 };
139
140 } // namespace testing
141 } // namespace llvm_libc
142
143 #define TEST(SuiteName, TestName)                                              \
144   class SuiteName##_##TestName : public llvm_libc::testing::Test {             \
145   public:                                                                      \
146     SuiteName##_##TestName() { addTest(this); }                                \
147     void Run(llvm_libc::testing::RunContext &) override;                       \
148     const char *getName() const override { return #SuiteName "." #TestName; }  \
149   };                                                                           \
150   SuiteName##_##TestName SuiteName##_##TestName##_Instance;                    \
151   void SuiteName##_##TestName::Run(llvm_libc::testing::RunContext &Ctx)
152
153 #define TEST_F(SuiteClass, TestName)                                           \
154   class SuiteClass##_##TestName : public SuiteClass {                          \
155   public:                                                                      \
156     SuiteClass##_##TestName() { addTest(this); }                               \
157     void Run(llvm_libc::testing::RunContext &) override;                       \
158     const char *getName() const override { return #SuiteClass "." #TestName; } \
159   };                                                                           \
160   SuiteClass##_##TestName SuiteClass##_##TestName##_Instance;                  \
161   void SuiteClass##_##TestName::Run(llvm_libc::testing::RunContext &Ctx)
162
163 #define EXPECT_EQ(LHS, RHS)                                                    \
164   llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_EQ, (LHS),      \
165                                  (RHS), #LHS, #RHS, __FILE__, __LINE__)
166 #define ASSERT_EQ(LHS, RHS)                                                    \
167   if (!EXPECT_EQ(LHS, RHS))                                                    \
168   return
169
170 #define EXPECT_NE(LHS, RHS)                                                    \
171   llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_NE, (LHS),      \
172                                  (RHS), #LHS, #RHS, __FILE__, __LINE__)
173 #define ASSERT_NE(LHS, RHS)                                                    \
174   if (!EXPECT_NE(LHS, RHS))                                                    \
175   return
176
177 #define EXPECT_LT(LHS, RHS)                                                    \
178   llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_LT, (LHS),      \
179                                  (RHS), #LHS, #RHS, __FILE__, __LINE__)
180 #define ASSERT_LT(LHS, RHS)                                                    \
181   if (!EXPECT_LT(LHS, RHS))                                                    \
182   return
183
184 #define EXPECT_LE(LHS, RHS)                                                    \
185   llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_LE, (LHS),      \
186                                  (RHS), #LHS, #RHS, __FILE__, __LINE__)
187 #define ASSERT_LE(LHS, RHS)                                                    \
188   if (!EXPECT_LE(LHS, RHS))                                                    \
189   return
190
191 #define EXPECT_GT(LHS, RHS)                                                    \
192   llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_GT, (LHS),      \
193                                  (RHS), #LHS, #RHS, __FILE__, __LINE__)
194 #define ASSERT_GT(LHS, RHS)                                                    \
195   if (!EXPECT_GT(LHS, RHS))                                                    \
196   return
197
198 #define EXPECT_GE(LHS, RHS)                                                    \
199   llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_GE, (LHS),      \
200                                  (RHS), #LHS, #RHS, __FILE__, __LINE__)
201 #define ASSERT_GE(LHS, RHS)                                                    \
202   if (!EXPECT_GE(LHS, RHS))                                                    \
203   return
204
205 #define EXPECT_STREQ(LHS, RHS)                                                 \
206   llvm_libc::testing::Test::testStrEq(Ctx, (LHS), (RHS), #LHS, #RHS, __FILE__, \
207                                       __LINE__)
208 #define ASSERT_STREQ(LHS, RHS)                                                 \
209   if (!EXPECT_STREQ(LHS, RHS))                                                 \
210   return
211
212 #define EXPECT_STRNE(LHS, RHS)                                                 \
213   llvm_libc::testing::Test::testStrNe(Ctx, (LHS), (RHS), #LHS, #RHS, __FILE__, \
214                                       __LINE__)
215 #define ASSERT_STRNE(LHS, RHS)                                                 \
216   if (!EXPECT_STRNE(LHS, RHS))                                                 \
217   return