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_TEST_UNITTEST_LIBCTEST_H
10#define LLVM_LIBC_TEST_UNITTEST_LIBCTEST_H
11
12// This is defined as a simple macro in test.h so that it exists for platforms
13// that don't use our test infrastructure. It's defined as a proper function
14// below.
15#ifdef libc_make_test_file_path
16#undef libc_make_test_file_path
17#endif // libc_make_test_file_path
18
19// This is defined as a macro here to avoid namespace issues.
20#define libc_make_test_file_path(file_name) \
21 (LIBC_NAMESPACE::testing::libc_make_test_file_path_func(file_name))
22
23// This file can only include headers from src/__support/ or test/UnitTest. No
24// other headers should be included.
25
26#include "PlatformDefs.h"
27
28#include "src/__support/CPP/string.h"
29#include "src/__support/CPP/string_view.h"
30#include "src/__support/CPP/type_traits.h"
31#include "src/__support/c_string.h"
32#include "test/UnitTest/ExecuteFunction.h"
33#include "test/UnitTest/TestLogger.h"
34
35namespace LIBC_NAMESPACE {
36namespace testing {
37
38// Only the following conditions are supported. Notice that we do not have
39// a TRUE or FALSE condition. That is because, C library functions do not
40// return boolean values, but use integral return values to indicate true or
41// false conditions. Hence, it is more appropriate to use the other comparison
42// conditions for such cases.
43enum class TestCond { EQ, NE, LT, LE, GT, GE };
44
45struct MatcherBase {
46 virtual ~MatcherBase() {}
47 virtual void explainError() { tlog << "unknown error\n"; }
48 // Override and return true to skip `explainError` step.
49 virtual bool is_silent() const { return false; }
50};
51
52template <typename T> struct Matcher : public MatcherBase {
53 bool match(const T &t);
54};
55
56namespace internal {
57
58// A simple location object to allow consistent passing of __FILE__ and
59// __LINE__.
60struct Location {
61 Location(const char *file, int line) : file(file), line(line) {}
62 const char *file;
63 int line;
64};
65
66// Supports writing a failing Location to tlog.
67TestLogger &operator<<(TestLogger &logger, Location Loc);
68
69#define LIBC_TEST_LOC_() \
70 LIBC_NAMESPACE::testing::internal::Location(__FILE__, __LINE__)
71
72// Object to forward custom logging after the EXPECT / ASSERT macros.
73struct Message {
74 template <typename T> Message &operator<<(T value) {
75 tlog << value;
76 return *this;
77 }
78};
79
80// A trivial object to catch the Message, this enables custom logging and
81// returning from the test function, see LIBC_TEST_SCAFFOLDING_ below.
82struct Failure {
83 void operator=(Message msg) {}
84};
85
86struct RunContext {
87 enum class RunResult : bool { Pass, Fail };
88
89 RunResult status() const { return Status; }
90
91 void markFail() { Status = RunResult::Fail; }
92
93private:
94 RunResult Status = RunResult::Pass;
95};
96
97template <typename ValType>
98bool test(RunContext *Ctx, TestCond Cond, ValType LHS, ValType RHS,
99 const char *LHSStr, const char *RHSStr, Location Loc);
100
101} // namespace internal
102
103// NOTE: One should not create instances and call methods on them directly. One
104// should use the macros TEST or TEST_F to write test cases.
105class Test {
106 Test *Next = nullptr;
107 internal::RunContext *Ctx = nullptr;
108
109 void setContext(internal::RunContext *C) { Ctx = C; }
110
111public:
112 virtual ~Test() {}
113 virtual void SetUp() {}
114 virtual void TearDown() {}
115
116 static int runTests(const char *);
117
118protected:
119 static void addTest(Test *T);
120
121 // We make use of a template function, with |LHS| and |RHS| as explicit
122 // parameters, for enhanced type checking. Other gtest like unittest
123 // frameworks have a similar function which takes a boolean argument
124 // instead of the explicit |LHS| and |RHS| arguments. This boolean argument
125 // is the result of the |Cond| operation on |LHS| and |RHS|. Though not bad,
126 // |Cond| on mismatched |LHS| and |RHS| types can potentially succeed because
127 // of type promotion.
128 template <
129 typename ValType,
130 cpp::enable_if_t<cpp::is_integral_v<ValType> || is_big_int_v<ValType> ||
131 cpp::is_fixed_point_v<ValType>,
132 int> = 0>
133 bool test(TestCond Cond, ValType LHS, ValType RHS, const char *LHSStr,
134 const char *RHSStr, internal::Location Loc) {
135 return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, Loc);
136 }
137
138 template <typename ValType,
139 cpp::enable_if_t<cpp::is_enum_v<ValType>, int> = 0>
140 bool test(TestCond Cond, ValType LHS, ValType RHS, const char *LHSStr,
141 const char *RHSStr, internal::Location Loc) {
142 return internal::test(Ctx, Cond, LHS: (long long)LHS, RHS: (long long)RHS, LHSStr,
143 RHSStr, Loc);
144 }
145
146 template <typename ValType,
147 cpp::enable_if_t<cpp::is_pointer_v<ValType>, ValType> = nullptr>
148 bool test(TestCond Cond, ValType LHS, ValType RHS, const char *LHSStr,
149 const char *RHSStr, internal::Location Loc) {
150 return internal::test(Ctx, Cond, LHS: (unsigned long long)LHS,
151 RHS: (unsigned long long)RHS, LHSStr, RHSStr, Loc);
152 }
153
154 template <
155 typename ValType,
156 cpp::enable_if_t<
157 cpp::is_same_v<ValType, LIBC_NAMESPACE::cpp::string_view>, int> = 0>
158 bool test(TestCond Cond, ValType LHS, ValType RHS, const char *LHSStr,
159 const char *RHSStr, internal::Location Loc) {
160 return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, Loc);
161 }
162
163 template <typename ValType,
164 cpp::enable_if_t<
165 cpp::is_same_v<ValType, LIBC_NAMESPACE::cpp::string>, int> = 0>
166 bool test(TestCond Cond, ValType LHS, ValType RHS, const char *LHSStr,
167 const char *RHSStr, internal::Location Loc) {
168 return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, Loc);
169 }
170
171 bool testStrEq(const char *LHS, const char *RHS, const char *LHSStr,
172 const char *RHSStr, internal::Location Loc);
173
174 bool testStrNe(const char *LHS, const char *RHS, const char *LHSStr,
175 const char *RHSStr, internal::Location Loc);
176
177 bool testMatch(bool MatchResult, MatcherBase &Matcher, const char *LHSStr,
178 const char *RHSStr, internal::Location Loc);
179
180 template <typename MatcherT, typename ValType>
181 bool matchAndExplain(MatcherT &&Matcher, ValType Value,
182 const char *MatcherStr, const char *ValueStr,
183 internal::Location Loc) {
184 return testMatch(MatchResult: Matcher.match(Value), Matcher, LHSStr: ValueStr, RHSStr: MatcherStr, Loc);
185 }
186
187 bool testProcessExits(testutils::FunctionCaller *Func, int ExitCode,
188 const char *LHSStr, const char *RHSStr,
189 internal::Location Loc);
190
191 bool testProcessKilled(testutils::FunctionCaller *Func, int Signal,
192 const char *LHSStr, const char *RHSStr,
193 internal::Location Loc);
194
195 template <typename Func> testutils::FunctionCaller *createCallable(Func f) {
196 struct Callable : public testutils::FunctionCaller {
197 Func f;
198 Callable(Func f) : f(f) {}
199 void operator()() override { f(); }
200 };
201
202 return new Callable(f);
203 }
204
205private:
206 virtual void Run() = 0;
207 virtual const char *getName() const = 0;
208
209 static Test *Start;
210 static Test *End;
211};
212
213extern int argc;
214extern char **argv;
215extern char **envp;
216
217namespace internal {
218
219constexpr bool same_prefix(char const *lhs, char const *rhs, int const len) {
220 for (int i = 0; (*lhs || *rhs) && (i < len); ++lhs, ++rhs, ++i)
221 if (*lhs != *rhs)
222 return false;
223 return true;
224}
225
226constexpr bool valid_prefix(char const *lhs) {
227 return same_prefix(lhs, rhs: "LlvmLibc", len: 8);
228}
229
230// 'str' is a null terminated string of the form
231// "const char *LIBC_NAMESPACE::testing::internal::GetTypeName() [ParamType =
232// XXX]" We return the substring that start at character '[' or a default
233// message.
234constexpr char const *GetPrettyFunctionParamType(char const *str) {
235 for (const char *ptr = str; *ptr != '\0'; ++ptr)
236 if (*ptr == '[')
237 return ptr;
238 return "UNSET : declare with REGISTER_TYPE_NAME";
239}
240
241// This function recovers ParamType at compile time by using __PRETTY_FUNCTION__
242// It can be customized by using the REGISTER_TYPE_NAME macro below.
243template <typename ParamType> static constexpr const char *GetTypeName() {
244 return GetPrettyFunctionParamType(__PRETTY_FUNCTION__);
245}
246
247template <typename T>
248static inline void GenerateName(char *buffer, int buffer_size,
249 const char *prefix) {
250 if (buffer_size == 0)
251 return;
252
253 // Make sure string is null terminated.
254 --buffer_size;
255 buffer[buffer_size] = '\0';
256
257 const auto AppendChar = [&](char c) {
258 if (buffer_size > 0) {
259 *buffer = c;
260 ++buffer;
261 --buffer_size;
262 }
263 };
264 const auto AppendStr = [&](const char *str) {
265 for (; str && *str != '\0'; ++str)
266 AppendChar(*str);
267 };
268
269 AppendStr(prefix);
270 AppendChar(' ');
271 AppendStr(GetTypeName<T>());
272 AppendChar('\0');
273}
274
275// TestCreator implements a linear hierarchy of test instances, effectively
276// instanciating all tests with Types in a single object.
277template <template <typename> class TemplatedTestClass, typename... Types>
278struct TestCreator;
279
280template <template <typename> class TemplatedTestClass, typename Head,
281 typename... Tail>
282struct TestCreator<TemplatedTestClass, Head, Tail...>
283 : private TestCreator<TemplatedTestClass, Tail...> {
284 TemplatedTestClass<Head> instance;
285};
286
287template <template <typename> class TemplatedTestClass>
288struct TestCreator<TemplatedTestClass> {};
289
290// A type list to declare the set of types to instantiate the tests with.
291template <typename... Types> struct TypeList {
292 template <template <typename> class TemplatedTestClass> struct Tests {
293 using type = TestCreator<TemplatedTestClass, Types...>;
294 };
295};
296
297} // namespace internal
298
299// Make TypeList visible in LIBC_NAMESPACE::testing.
300template <typename... Types> using TypeList = internal::TypeList<Types...>;
301
302CString libc_make_test_file_path_func(const char *file_name);
303
304} // namespace testing
305} // namespace LIBC_NAMESPACE
306
307// For TYPED_TEST and TYPED_TEST_F below we need to display which type was used
308// to run the test. The default will return the fully qualified canonical type
309// but it can be difficult to read. We provide the following macro to allow the
310// client to register the type name as they see it in the code.
311#define REGISTER_TYPE_NAME(TYPE) \
312 template <> \
313 constexpr const char * \
314 LIBC_NAMESPACE::testing::internal::GetTypeName<TYPE>() { \
315 return "[ParamType = " #TYPE "]"; \
316 }
317
318#define TYPED_TEST(SuiteName, TestName, TypeList) \
319 static_assert( \
320 LIBC_NAMESPACE::testing::internal::valid_prefix(#SuiteName), \
321 "All LLVM-libc TYPED_TEST suite names must start with 'LlvmLibc'."); \
322 template <typename T> \
323 class SuiteName##_##TestName : public LIBC_NAMESPACE::testing::Test { \
324 public: \
325 using ParamType = T; \
326 char name[256]; \
327 SuiteName##_##TestName() { \
328 addTest(this); \
329 LIBC_NAMESPACE::testing::internal::GenerateName<T>( \
330 name, sizeof(name), #SuiteName "." #TestName); \
331 } \
332 void Run() override; \
333 const char *getName() const override { return name; } \
334 }; \
335 TypeList::Tests<SuiteName##_##TestName>::type \
336 SuiteName##_##TestName##_Instance; \
337 template <typename T> void SuiteName##_##TestName<T>::Run()
338
339#define TYPED_TEST_F(SuiteClass, TestName, TypeList) \
340 static_assert(LIBC_NAMESPACE::testing::internal::valid_prefix(#SuiteClass), \
341 "All LLVM-libc TYPED_TEST_F suite class names must start " \
342 "with 'LlvmLibc'."); \
343 template <typename T> class SuiteClass##_##TestName : public SuiteClass<T> { \
344 public: \
345 using ParamType = T; \
346 char name[256]; \
347 SuiteClass##_##TestName() { \
348 SuiteClass<T>::addTest(this); \
349 LIBC_NAMESPACE::testing::internal::GenerateName<T>( \
350 name, sizeof(name), #SuiteClass "." #TestName); \
351 } \
352 void Run() override; \
353 const char *getName() const override { return name; } \
354 }; \
355 TypeList::Tests<SuiteClass##_##TestName>::type \
356 SuiteClass##_##TestName##_Instance; \
357 template <typename T> void SuiteClass##_##TestName<T>::Run()
358
359#define TEST(SuiteName, TestName) \
360 static_assert(LIBC_NAMESPACE::testing::internal::valid_prefix(#SuiteName), \
361 "All LLVM-libc TEST suite names must start with 'LlvmLibc'."); \
362 class SuiteName##_##TestName : public LIBC_NAMESPACE::testing::Test { \
363 public: \
364 SuiteName##_##TestName() { addTest(this); } \
365 void Run() override; \
366 const char *getName() const override { return #SuiteName "." #TestName; } \
367 }; \
368 SuiteName##_##TestName SuiteName##_##TestName##_Instance; \
369 void SuiteName##_##TestName::Run()
370
371#define TEST_F(SuiteClass, TestName) \
372 static_assert( \
373 LIBC_NAMESPACE::testing::internal::valid_prefix(#SuiteClass), \
374 "All LLVM-libc TEST_F suite class names must start with 'LlvmLibc'."); \
375 class SuiteClass##_##TestName : public SuiteClass { \
376 public: \
377 SuiteClass##_##TestName() { addTest(this); } \
378 void Run() override; \
379 const char *getName() const override { return #SuiteClass "." #TestName; } \
380 }; \
381 SuiteClass##_##TestName SuiteClass##_##TestName##_Instance; \
382 void SuiteClass##_##TestName::Run()
383
384// If RET_OR_EMPTY is the 'return' keyword we perform an early return which
385// corresponds to an assert. If it is empty the execution continues, this
386// corresponds to an expect.
387//
388// The 'else' clause must not be enclosed into braces so that the << operator
389// can be used to fill the Message.
390//
391// TEST is usually implemented as a function performing checking logic and
392// returning a boolean. This expression is responsible for logging the
393// diagnostic in case of failure.
394#define LIBC_TEST_SCAFFOLDING_(TEST, RET_OR_EMPTY) \
395 if (TEST) \
396 ; \
397 else \
398 RET_OR_EMPTY LIBC_NAMESPACE::testing::internal::Failure() = \
399 LIBC_NAMESPACE::testing::internal::Message()
400
401#define LIBC_TEST_BINOP_(COND, LHS, RHS, RET_OR_EMPTY) \
402 LIBC_TEST_SCAFFOLDING_(test(LIBC_NAMESPACE::testing::TestCond::COND, LHS, \
403 RHS, #LHS, #RHS, LIBC_TEST_LOC_()), \
404 RET_OR_EMPTY)
405
406////////////////////////////////////////////////////////////////////////////////
407// Binary operations corresponding to the TestCond enum.
408
409#define EXPECT_EQ(LHS, RHS) LIBC_TEST_BINOP_(EQ, LHS, RHS, )
410#define ASSERT_EQ(LHS, RHS) LIBC_TEST_BINOP_(EQ, LHS, RHS, return)
411
412#define EXPECT_NE(LHS, RHS) LIBC_TEST_BINOP_(NE, LHS, RHS, )
413#define ASSERT_NE(LHS, RHS) LIBC_TEST_BINOP_(NE, LHS, RHS, return)
414
415#define EXPECT_LT(LHS, RHS) LIBC_TEST_BINOP_(LT, LHS, RHS, )
416#define ASSERT_LT(LHS, RHS) LIBC_TEST_BINOP_(LT, LHS, RHS, return)
417
418#define EXPECT_LE(LHS, RHS) LIBC_TEST_BINOP_(LE, LHS, RHS, )
419#define ASSERT_LE(LHS, RHS) LIBC_TEST_BINOP_(LE, LHS, RHS, return)
420
421#define EXPECT_GT(LHS, RHS) LIBC_TEST_BINOP_(GT, LHS, RHS, )
422#define ASSERT_GT(LHS, RHS) LIBC_TEST_BINOP_(GT, LHS, RHS, return)
423
424#define EXPECT_GE(LHS, RHS) LIBC_TEST_BINOP_(GE, LHS, RHS, )
425#define ASSERT_GE(LHS, RHS) LIBC_TEST_BINOP_(GE, LHS, RHS, return)
426
427////////////////////////////////////////////////////////////////////////////////
428// Boolean checks are handled as comparison to the true / false values.
429
430#define EXPECT_TRUE(VAL) EXPECT_EQ(VAL, true)
431#define ASSERT_TRUE(VAL) ASSERT_EQ(VAL, true)
432
433#define EXPECT_FALSE(VAL) EXPECT_EQ(VAL, false)
434#define ASSERT_FALSE(VAL) ASSERT_EQ(VAL, false)
435
436////////////////////////////////////////////////////////////////////////////////
437// String checks.
438
439#define LIBC_TEST_STR_(TEST_FUNC, LHS, RHS, RET_OR_EMPTY) \
440 LIBC_TEST_SCAFFOLDING_(TEST_FUNC(LHS, RHS, #LHS, #RHS, LIBC_TEST_LOC_()), \
441 RET_OR_EMPTY)
442
443#define EXPECT_STREQ(LHS, RHS) LIBC_TEST_STR_(testStrEq, LHS, RHS, )
444#define ASSERT_STREQ(LHS, RHS) LIBC_TEST_STR_(testStrEq, LHS, RHS, return)
445
446#define EXPECT_STRNE(LHS, RHS) LIBC_TEST_STR_(testStrNe, LHS, RHS, )
447#define ASSERT_STRNE(LHS, RHS) LIBC_TEST_STR_(testStrNe, LHS, RHS, return)
448
449////////////////////////////////////////////////////////////////////////////////
450// Subprocess checks.
451
452#ifdef ENABLE_SUBPROCESS_TESTS
453
454#define LIBC_TEST_PROCESS_(TEST_FUNC, FUNC, VALUE, RET_OR_EMPTY) \
455 LIBC_TEST_SCAFFOLDING_( \
456 TEST_FUNC(LIBC_NAMESPACE::testing::Test::createCallable(FUNC), VALUE, \
457 #FUNC, #VALUE, LIBC_TEST_LOC_()), \
458 RET_OR_EMPTY)
459
460#define EXPECT_EXITS(FUNC, EXIT) \
461 LIBC_TEST_PROCESS_(testProcessExits, FUNC, EXIT, )
462#define ASSERT_EXITS(FUNC, EXIT) \
463 LIBC_TEST_PROCESS_(testProcessExits, FUNC, EXIT, return)
464
465#define EXPECT_DEATH(FUNC, SIG) \
466 LIBC_TEST_PROCESS_(testProcessKilled, FUNC, SIG, )
467#define ASSERT_DEATH(FUNC, SIG) \
468 LIBC_TEST_PROCESS_(testProcessKilled, FUNC, SIG, return)
469
470#endif // ENABLE_SUBPROCESS_TESTS
471
472////////////////////////////////////////////////////////////////////////////////
473// Custom matcher checks.
474
475#define LIBC_TEST_MATCH_(MATCHER, MATCH, MATCHER_STR, MATCH_STR, RET_OR_EMPTY) \
476 LIBC_TEST_SCAFFOLDING_(matchAndExplain(MATCHER, MATCH, MATCHER_STR, \
477 MATCH_STR, LIBC_TEST_LOC_()), \
478 RET_OR_EMPTY)
479
480#define EXPECT_THAT(MATCH, MATCHER) \
481 LIBC_TEST_MATCH_(MATCHER, MATCH, #MATCHER, #MATCH, )
482#define ASSERT_THAT(MATCH, MATCHER) \
483 LIBC_TEST_MATCH_(MATCHER, MATCH, #MATCHER, #MATCH, return)
484
485#define WITH_SIGNAL(X) X
486
487#define LIBC_TEST_HAS_MATCHERS() (1)
488
489#endif // LLVM_LIBC_TEST_UNITTEST_LIBCTEST_H
490

source code of libc/test/UnitTest/LibcTest.h