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