[libc-commits] [libc] c7453fa - [libc] Replace the use of gtest with a new light weight unittest framework.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Fri Jan 17 16:32:05 PST 2020


Author: Siva Chandra Reddy
Date: 2020-01-17T16:24:53-08:00
New Revision: c7453fad0625be37f4b885c6cc2341fb12a66395

URL: https://github.com/llvm/llvm-project/commit/c7453fad0625be37f4b885c6cc2341fb12a66395
DIFF: https://github.com/llvm/llvm-project/commit/c7453fad0625be37f4b885c6cc2341fb12a66395.diff

LOG: [libc] Replace the use of gtest with a new light weight unittest framework.

Header files included wrongly using <...> are now included using the
internal path names as the new unittest framework allows us to do so.

Reviewers: phosek, abrachet

Differential Revision: https://reviews.llvm.org/D72743

Added: 
    libc/utils/UnitTest/CMakeLists.txt
    libc/utils/UnitTest/Test.cpp
    libc/utils/UnitTest/Test.h

Modified: 
    libc/cmake/modules/LLVMLibCRules.cmake
    libc/src/string/strcat.h
    libc/src/string/strcpy.h
    libc/src/sys/mman/mmap.cpp
    libc/src/sys/mman/mmap.h
    libc/src/sys/mman/munmap.cpp
    libc/src/sys/mman/munmap.h
    libc/test/config/linux/x86_64/syscall_test.cpp
    libc/test/src/errno/errno_test.cpp
    libc/test/src/string/strcat_test.cpp
    libc/test/src/string/strcpy_test.cpp
    libc/test/src/sys/mman/CMakeLists.txt
    libc/test/src/sys/mman/mmap_test.cpp
    libc/utils/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/cmake/modules/LLVMLibCRules.cmake b/libc/cmake/modules/LLVMLibCRules.cmake
index c7aac7a92965..34b10cc421b9 100644
--- a/libc/cmake/modules/LLVMLibCRules.cmake
+++ b/libc/cmake/modules/LLVMLibCRules.cmake
@@ -339,10 +339,9 @@ function(add_libc_unittest target_name)
   target_include_directories(
     ${target_name}
     PRIVATE
-      ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include
-      ${LLVM_MAIN_SRC_DIR}/utils/unittest/googlemock/include
       ${LIBC_SOURCE_DIR}
       ${LIBC_BUILD_DIR}
+      ${LIBC_BUILD_DIR}/include
   )
 
   if(library_deps)
@@ -357,7 +356,7 @@ function(add_libc_unittest target_name)
     gtest
   )
 
-  target_link_libraries(${target_name} PRIVATE gtest_main gtest)
+  target_link_libraries(${target_name} PRIVATE LibcUnitTest LLVMSupport)
 
   add_custom_command(
     TARGET ${target_name}

diff  --git a/libc/src/string/strcat.h b/libc/src/string/strcat.h
index d3023e9757ca..ea88c23e9be5 100644
--- a/libc/src/string/strcat.h
+++ b/libc/src/string/strcat.h
@@ -9,7 +9,7 @@
 #ifndef LLVM_LIBC_SRC_STRING_STRCAT_H
 #define LLVM_LIBC_SRC_STRING_STRCAT_H
 
-#include <string.h>
+#include "include/string.h"
 
 namespace __llvm_libc {
 

diff  --git a/libc/src/string/strcpy.h b/libc/src/string/strcpy.h
index 67710d8c84b2..88cb481f13cd 100644
--- a/libc/src/string/strcpy.h
+++ b/libc/src/string/strcpy.h
@@ -9,7 +9,7 @@
 #ifndef LLVM_LIBC_SRC_STRING_STRCPY_H
 #define LLVM_LIBC_SRC_STRING_STRCPY_H
 
-#include <string.h>
+#include "include/string.h"
 
 namespace __llvm_libc {
 

diff  --git a/libc/src/sys/mman/mmap.cpp b/libc/src/sys/mman/mmap.cpp
index bcf653141760..10ae0c70c98c 100644
--- a/libc/src/sys/mman/mmap.cpp
+++ b/libc/src/sys/mman/mmap.cpp
@@ -7,13 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/sys/mman/mmap.h"
+#include "include/sys/syscall.h" // For syscall numbers.
 #include "src/__support/common.h"
 #include "src/errno/llvmlibc_errno.h"
-
 #include "src/unistd/syscall.h" // For internal syscall function.
 
-#include <sys/syscall.h> // For syscall numbers.
-
 namespace __llvm_libc {
 
 // This function is currently linux only. It has to be refactored suitably if

diff  --git a/libc/src/sys/mman/mmap.h b/libc/src/sys/mman/mmap.h
index f34a5ab76152..11107b06442c 100644
--- a/libc/src/sys/mman/mmap.h
+++ b/libc/src/sys/mman/mmap.h
@@ -9,7 +9,7 @@
 #ifndef LLVM_LIBC_SRC_SYS_MMAN_MMAP_H
 #define LLVM_LIBC_SRC_SYS_MMAN_MMAP_H
 
-#include <sys/mman.h> // For size_t and off_t
+#include "include/sys/mman.h" // For size_t and off_t
 
 namespace __llvm_libc {
 

diff  --git a/libc/src/sys/mman/munmap.cpp b/libc/src/sys/mman/munmap.cpp
index 6a8b4f77769f..d11f53a418c0 100644
--- a/libc/src/sys/mman/munmap.cpp
+++ b/libc/src/sys/mman/munmap.cpp
@@ -7,13 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/sys/mman/munmap.h"
+#include "include/sys/syscall.h" // For syscall numbers.
 #include "src/__support/common.h"
 #include "src/errno/llvmlibc_errno.h"
-
 #include "src/unistd/syscall.h" // For internal syscall function.
 
-#include <sys/syscall.h> // For syscall numbers.
-
 namespace __llvm_libc {
 
 // This function is currently linux only. It has to be refactored suitably if

diff  --git a/libc/src/sys/mman/munmap.h b/libc/src/sys/mman/munmap.h
index 2c01cbd87cd7..20ba50e5d2c7 100644
--- a/libc/src/sys/mman/munmap.h
+++ b/libc/src/sys/mman/munmap.h
@@ -9,7 +9,7 @@
 #ifndef LLVM_LIBC_SRC_SYS_MMAN_MUNMAP_H
 #define LLVM_LIBC_SRC_SYS_MMAN_MUNMAP_H
 
-#include <sys/mman.h> // For size_t
+#include "include/sys/mman.h" // For size_t.
 
 namespace __llvm_libc {
 

diff  --git a/libc/test/config/linux/x86_64/syscall_test.cpp b/libc/test/config/linux/x86_64/syscall_test.cpp
index 6a92142625c6..27628be6a4cd 100644
--- a/libc/test/config/linux/x86_64/syscall_test.cpp
+++ b/libc/test/config/linux/x86_64/syscall_test.cpp
@@ -7,8 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/unistd/syscall.h"
-
-#include "gtest/gtest.h"
+#include "utils/UnitTest/Test.h"
 
 #include <functional>
 

diff  --git a/libc/test/src/errno/errno_test.cpp b/libc/test/src/errno/errno_test.cpp
index 1ca61d5c625d..46f0c2ff882a 100644
--- a/libc/test/src/errno/errno_test.cpp
+++ b/libc/test/src/errno/errno_test.cpp
@@ -7,8 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/errno/llvmlibc_errno.h"
-
-#include "gtest/gtest.h"
+#include "utils/UnitTest/Test.h"
 
 TEST(ErrnoTest, Basic) {
   int test_val = 123;

diff  --git a/libc/test/src/string/strcat_test.cpp b/libc/test/src/string/strcat_test.cpp
index fde432bcec8a..599caf58ab0a 100644
--- a/libc/test/src/string/strcat_test.cpp
+++ b/libc/test/src/string/strcat_test.cpp
@@ -6,25 +6,23 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <string>
-
 #include "src/string/strcat.h"
-#include "gtest/gtest.h"
+#include "utils/UnitTest/Test.h"
 
 TEST(StrCatTest, EmptyDest) {
-  std::string abc = "abc";
+  const char *abc = "abc";
   char dest[4];
 
   dest[0] = '\0';
 
-  char *result = __llvm_libc::strcat(dest, abc.c_str());
+  char *result = __llvm_libc::strcat(dest, abc);
   ASSERT_EQ(dest, result);
-  ASSERT_EQ(std::string(dest), abc);
-  ASSERT_EQ(std::string(dest).size(), abc.size());
+  ASSERT_STREQ(dest, result);
+  ASSERT_STREQ(dest, abc);
 }
 
 TEST(StrCatTest, NonEmptyDest) {
-  std::string abc = "abc";
+  const char *abc = "abc";
   char dest[7];
 
   dest[0] = 'x';
@@ -32,8 +30,8 @@ TEST(StrCatTest, NonEmptyDest) {
   dest[2] = 'z';
   dest[3] = '\0';
 
-  char *result = __llvm_libc::strcat(dest, abc.c_str());
+  char *result = __llvm_libc::strcat(dest, abc);
   ASSERT_EQ(dest, result);
-  ASSERT_EQ(std::string(dest), std::string("xyz") + abc);
-  ASSERT_EQ(std::string(dest).size(), abc.size() + 3);
+  ASSERT_STREQ(dest, result);
+  ASSERT_STREQ(dest, "xyzabc");
 }

diff  --git a/libc/test/src/string/strcpy_test.cpp b/libc/test/src/string/strcpy_test.cpp
index 56f75ac9e5f0..350ff5c57800 100644
--- a/libc/test/src/string/strcpy_test.cpp
+++ b/libc/test/src/string/strcpy_test.cpp
@@ -6,31 +6,29 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <string>
-
 #include "src/string/strcpy.h"
-#include "gtest/gtest.h"
+#include "utils/UnitTest/Test.h"
 
 TEST(StrCpyTest, EmptyDest) {
-  std::string abc = "abc";
+  const char *abc = "abc";
   char dest[4];
 
-  char *result = __llvm_libc::strcpy(dest, abc.c_str());
+  char *result = __llvm_libc::strcpy(dest, abc);
   ASSERT_EQ(dest, result);
-  ASSERT_EQ(std::string(dest), abc);
-  ASSERT_EQ(std::string(dest).size(), abc.size());
+  ASSERT_STREQ(dest, result);
+  ASSERT_STREQ(dest, abc);
 }
 
 TEST(StrCpyTest, OffsetDest) {
-  std::string abc = "abc";
+  const char *abc = "abc";
   char dest[7];
 
   dest[0] = 'x';
   dest[1] = 'y';
   dest[2] = 'z';
 
-  char *result = __llvm_libc::strcpy(dest + 3, abc.c_str());
+  char *result = __llvm_libc::strcpy(dest + 3, abc);
   ASSERT_EQ(dest + 3, result);
-  ASSERT_EQ(std::string(dest), std::string("xyz") + abc);
-  ASSERT_EQ(std::string(dest).size(), abc.size() + 3);
+  ASSERT_STREQ(dest + 3, result);
+  ASSERT_STREQ(dest, "xyzabc");
 }

diff  --git a/libc/test/src/sys/mman/CMakeLists.txt b/libc/test/src/sys/mman/CMakeLists.txt
index b2f378387a6a..3fcc8fff3c29 100644
--- a/libc/test/src/sys/mman/CMakeLists.txt
+++ b/libc/test/src/sys/mman/CMakeLists.txt
@@ -7,6 +7,8 @@ add_libc_unittest(
   SRCS
     mmap_test.cpp
   DEPENDS
+    errno_h
+    sys_mman_h
     mmap
     munmap
     __errno_location

diff  --git a/libc/test/src/sys/mman/mmap_test.cpp b/libc/test/src/sys/mman/mmap_test.cpp
index ab2e6ceb4a93..9cc3abc1b499 100644
--- a/libc/test/src/sys/mman/mmap_test.cpp
+++ b/libc/test/src/sys/mman/mmap_test.cpp
@@ -6,14 +6,12 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "include/errno.h"
+#include "include/sys/mman.h"
 #include "src/errno/llvmlibc_errno.h"
 #include "src/sys/mman/mmap.h"
 #include "src/sys/mman/munmap.h"
-
-#include "gtest/gtest.h"
-
-#include "errno.h"
-#include "sys/mman.h"
+#include "utils/UnitTest/Test.h"
 
 TEST(MMapTest, NoError) {
   size_t alloc_size = 128;

diff  --git a/libc/utils/CMakeLists.txt b/libc/utils/CMakeLists.txt
index 472d08c97d1e..165ce1e0ddbc 100644
--- a/libc/utils/CMakeLists.txt
+++ b/libc/utils/CMakeLists.txt
@@ -1 +1,2 @@
 add_subdirectory(HdrGen)
+add_subdirectory(UnitTest)

diff  --git a/libc/utils/UnitTest/CMakeLists.txt b/libc/utils/UnitTest/CMakeLists.txt
new file mode 100644
index 000000000000..2a1f9723057d
--- /dev/null
+++ b/libc/utils/UnitTest/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_llvm_library(
+  LibcUnitTest
+  Test.cpp
+  Test.h
+)

diff  --git a/libc/utils/UnitTest/Test.cpp b/libc/utils/UnitTest/Test.cpp
new file mode 100644
index 000000000000..4b089060bd34
--- /dev/null
+++ b/libc/utils/UnitTest/Test.cpp
@@ -0,0 +1,229 @@
+//===--------- Implementation of the base class for libc unittests --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Test.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm_libc {
+namespace testing {
+
+// This need not be a class as all it has is a single read-write state variable.
+// But, we make it class as then its implementation can be hidden from the
+// header file.
+class RunContext {
+public:
+  enum RunResult { Result_Pass = 1, Result_Fail = 2 };
+
+  RunResult status() const { return Status; }
+
+  void markFail() { Status = Result_Fail; }
+
+private:
+  RunResult Status = Result_Pass;
+};
+
+namespace internal {
+
+template <typename ValType>
+bool test(RunContext &Ctx, TestCondition Cond, ValType LHS, ValType RHS,
+          const char *LHSStr, const char *RHSStr, const char *File,
+          unsigned long Line) {
+  switch (Cond) {
+  case Cond_EQ:
+    if (LHS == RHS)
+      return true;
+
+    Ctx.markFail();
+    llvm::outs() << File << ":" << Line << ": FAILURE\n"
+                 << "      Expected: " << LHSStr << '\n'
+                 << "      Which is: " << LHS << '\n'
+                 << "To be equal to: " << RHSStr << '\n'
+                 << "      Which is: " << RHS << '\n';
+
+    return false;
+  case Cond_NE:
+    if (LHS != RHS)
+      return true;
+
+    Ctx.markFail();
+    llvm::outs() << File << ":" << Line << ": FAILURE\n"
+                 << "          Expected: " << LHSStr << '\n'
+                 << "          Which is: " << LHS << '\n'
+                 << "To be not equal to: " << RHSStr << '\n'
+                 << "          Which is: " << RHS << '\n';
+    return false;
+  case Cond_LT:
+    if (LHS < RHS)
+      return true;
+
+    Ctx.markFail();
+    llvm::outs() << File << ":" << Line << ": FAILURE\n"
+                 << "       Expected: " << LHSStr << '\n'
+                 << "       Which is: " << LHS << '\n'
+                 << "To be less than: " << RHSStr << '\n'
+                 << "       Which is: " << RHS << '\n';
+    return false;
+  case Cond_LE:
+    if (LHS <= RHS)
+      return true;
+
+    Ctx.markFail();
+    llvm::outs() << File << ":" << Line << ": FAILURE\n"
+                 << "                   Expected: " << LHSStr << '\n'
+                 << "                   Which is: " << LHS << '\n'
+                 << "To be less than or equal to: " << RHSStr << '\n'
+                 << "                   Which is: " << RHS << '\n';
+    return false;
+  case Cond_GT:
+    if (LHS > RHS)
+      return true;
+
+    Ctx.markFail();
+    llvm::outs() << File << ":" << Line << ": FAILURE\n"
+                 << "          Expected: " << LHSStr << '\n'
+                 << "          Which is: " << LHS << '\n'
+                 << "To be greater than: " << RHSStr << '\n'
+                 << "          Which is: " << RHS << '\n';
+    return false;
+  case Cond_GE:
+    if (LHS >= RHS)
+      return true;
+
+    Ctx.markFail();
+    llvm::outs() << File << ":" << Line << ": FAILURE\n"
+                 << "                      Expected: " << LHSStr << '\n'
+                 << "                      Which is: " << LHS << '\n'
+                 << "To be greater than or equal to: " << RHSStr << '\n'
+                 << "                      Which is: " << RHS << '\n';
+    return false;
+  default:
+    Ctx.markFail();
+    llvm::outs() << "Unexpected test condition.\n";
+    return false;
+  }
+}
+
+} // namespace internal
+
+Test *Test::Start = nullptr;
+Test *Test::End = nullptr;
+
+void Test::addTest(Test *T) {
+  if (End == nullptr) {
+    Start = T;
+    End = T;
+    return;
+  }
+
+  End->Next = T;
+  End = T;
+}
+
+int Test::runTests() {
+  int TestCount = 0;
+  int FailCount = 0;
+  for (Test *T = Start; T != nullptr; T = T->Next, ++TestCount) {
+    const char *TestName = T->getName();
+    llvm::outs() << "[ RUN      ] " << TestName << '\n';
+    RunContext Ctx;
+    T->SetUp();
+    T->Run(Ctx);
+    T->TearDown();
+    auto Result = Ctx.status();
+    switch (Result) {
+    case RunContext::Result_Fail:
+      llvm::outs() << "[  FAILED  ] " << TestName << '\n';
+      ++FailCount;
+      break;
+    case RunContext::Result_Pass:
+      llvm::outs() << "[       OK ] " << TestName << '\n';
+      break;
+    }
+  }
+
+  llvm::outs() << "Ran " << TestCount << " tests. "
+               << " PASS: " << TestCount - FailCount << ' '
+               << " FAIL: " << FailCount << '\n';
+
+  return FailCount > 0 ? 1 : 0;
+}
+
+template bool Test::test<char, 0>(RunContext &Ctx, TestCondition Cond, char LHS,
+                                  char RHS, const char *LHSStr,
+                                  const char *RHSStr, const char *File,
+                                  unsigned long Line);
+
+template bool Test::test<short, 0>(RunContext &Ctx, TestCondition Cond,
+                                   short LHS, short RHS, const char *LHSStr,
+                                   const char *RHSStr, const char *File,
+                                   unsigned long Line);
+
+template bool Test::test<int, 0>(RunContext &Ctx, TestCondition Cond, int LHS,
+                                 int RHS, const char *LHSStr,
+                                 const char *RHSStr, const char *File,
+                                 unsigned long Line);
+
+template bool Test::test<long, 0>(RunContext &Ctx, TestCondition Cond, long LHS,
+                                  long RHS, const char *LHSStr,
+                                  const char *RHSStr, const char *File,
+                                  unsigned long Line);
+
+template bool Test::test<long long, 0>(RunContext &Ctx, TestCondition Cond,
+                                       long long LHS, long long RHS,
+                                       const char *LHSStr, const char *RHSStr,
+                                       const char *File, unsigned long Line);
+
+template bool Test::test<unsigned char, 0>(RunContext &Ctx, TestCondition Cond,
+                                           unsigned char LHS, unsigned char RHS,
+                                           const char *LHSStr,
+                                           const char *RHSStr, const char *File,
+                                           unsigned long Line);
+
+template bool
+Test::test<unsigned short, 0>(RunContext &Ctx, TestCondition Cond,
+                              unsigned short LHS, unsigned short RHS,
+                              const char *LHSStr, const char *RHSStr,
+                              const char *File, unsigned long Line);
+
+template bool Test::test<unsigned int, 0>(RunContext &Ctx, TestCondition Cond,
+                                          unsigned int LHS, unsigned int RHS,
+                                          const char *LHSStr,
+                                          const char *RHSStr, const char *File,
+                                          unsigned long Line);
+
+template bool Test::test<unsigned long, 0>(RunContext &Ctx, TestCondition Cond,
+                                           unsigned long LHS, unsigned long RHS,
+                                           const char *LHSStr,
+                                           const char *RHSStr, const char *File,
+                                           unsigned long Line);
+
+template bool Test::test<unsigned long long, 0>(
+    RunContext &Ctx, TestCondition Cond, unsigned long long LHS,
+    unsigned long long RHS, const char *LHSStr, const char *RHSStr,
+    const char *File, unsigned long Line);
+
+bool Test::testStrEq(RunContext &Ctx, const char *LHS, const char *RHS,
+                     const char *LHSStr, const char *RHSStr, const char *File,
+                     unsigned long Line) {
+  return internal::test(Ctx, Cond_EQ, llvm::StringRef(LHS),
+                        llvm::StringRef(RHS), LHSStr, RHSStr, File, Line);
+}
+
+bool Test::testStrNe(RunContext &Ctx, const char *LHS, const char *RHS,
+                     const char *LHSStr, const char *RHSStr, const char *File,
+                     unsigned long Line) {
+  return internal::test(Ctx, Cond_NE, llvm::StringRef(LHS),
+                        llvm::StringRef(RHS), LHSStr, RHSStr, File, Line);
+}
+
+} // namespace testing
+} // namespace llvm_libc
+
+int main() { return llvm_libc::testing::Test::runTests(); }

diff  --git a/libc/utils/UnitTest/Test.h b/libc/utils/UnitTest/Test.h
new file mode 100644
index 000000000000..3bdf6f06c080
--- /dev/null
+++ b/libc/utils/UnitTest/Test.h
@@ -0,0 +1,217 @@
+//===------------------ Base class for libc unittests -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This file should stricly not include any other file. Not even standard
+// library headers.
+
+namespace llvm_libc {
+namespace testing {
+
+// We define our own EnableIf and IsIntegerType traits because we do not want to
+// include even the standard header <type_traits>.
+template <bool B, typename T> struct EnableIf;
+template <typename T> struct EnableIf<true, T> { typedef T Type; };
+
+template <bool B, typename T>
+using EnableIfType = typename EnableIf<B, T>::Type;
+
+template <typename Type> struct IsIntegerType {
+  static const bool Value = false;
+};
+
+template <> struct IsIntegerType<char> { static const bool Value = true; };
+template <> struct IsIntegerType<unsigned char> {
+  static const bool Value = true;
+};
+
+template <> struct IsIntegerType<short> { static const bool Value = true; };
+template <> struct IsIntegerType<unsigned short> {
+  static const bool Value = true;
+};
+
+template <> struct IsIntegerType<int> { static const bool Value = true; };
+template <> struct IsIntegerType<unsigned int> {
+  static const bool Value = true;
+};
+
+template <> struct IsIntegerType<long> { static const bool Value = true; };
+template <> struct IsIntegerType<unsigned long> {
+  static const bool Value = true;
+};
+
+template <> struct IsIntegerType<long long> { static const bool Value = true; };
+template <> struct IsIntegerType<unsigned long long> {
+  static const bool Value = true;
+};
+
+template <typename T> struct IsPointerType;
+
+template <typename T> struct IsPointerType<T *> {
+  static const bool Value = true;
+};
+
+class RunContext;
+
+// Only the following conditions are supported. Notice that we do not have
+// a TRUE or FALSE condition. That is because, C library funtions do not
+// return, but use integral return values to indicate true or false
+// conditions. Hence, it is more appropriate to use the other comparison
+// condtions for such cases.
+enum TestCondition {
+  Cond_None,
+  Cond_EQ,
+  Cond_NE,
+  Cond_LT,
+  Cond_LE,
+  Cond_GT,
+  Cond_GE,
+};
+
+namespace internal {
+
+template <typename ValType>
+bool test(RunContext &Ctx, TestCondition Cond, ValType LHS, ValType RHS,
+          const char *LHSStr, const char *RHSStr, const char *File,
+          unsigned long Line);
+
+} // namespace internal
+
+// NOTE: One should not create instances and call methods on them directly. One
+// should use the macros TEST or TEST_F to write test cases.
+class Test {
+private:
+  Test *Next = nullptr;
+
+public:
+  virtual ~Test() {}
+  virtual void SetUp() {}
+  virtual void TearDown() {}
+
+  static int runTests();
+
+protected:
+  static void addTest(Test *T);
+
+  // We make use of a template function, with |LHS| and |RHS| as explicit
+  // parameters, for enhanced type checking. Other gtest like test unittest
+  // frameworks have a similar functions which takes a boolean argument
+  // instead of the explicit |LHS| and |RHS| arguments. This boolean argument
+  // is the result of the |Cond| operation on |LHS| and |RHS|. Though not bad,
+  // mismatched |LHS| and |RHS| types can potentially succeed because of type
+  // promotion.
+  template <typename ValType,
+            EnableIfType<IsIntegerType<ValType>::Value, ValType> = 0>
+  static bool test(RunContext &Ctx, TestCondition Cond, ValType LHS,
+                   ValType RHS, const char *LHSStr, const char *RHSStr,
+                   const char *File, unsigned long Line) {
+    return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, File, Line);
+  }
+
+  template <typename ValType,
+            EnableIfType<IsPointerType<ValType>::Value, ValType> = nullptr>
+  static bool test(RunContext &Ctx, TestCondition Cond, ValType LHS,
+                   ValType RHS, const char *LHSStr, const char *RHSStr,
+                   const char *File, unsigned long Line) {
+    return internal::test(Ctx, Cond, (unsigned long long)LHS,
+                          (unsigned long long)RHS, LHSStr, RHSStr, File, Line);
+  }
+
+  static bool testStrEq(RunContext &Ctx, const char *LHS, const char *RHS,
+                        const char *LHSStr, const char *RHSStr,
+                        const char *File, unsigned long Line);
+
+  static bool testStrNe(RunContext &Ctx, const char *LHS, const char *RHS,
+                        const char *LHSStr, const char *RHSStr,
+                        const char *File, unsigned long Line);
+
+private:
+  virtual void Run(RunContext &Ctx) = 0;
+  virtual const char *getName() const = 0;
+
+  static Test *Start;
+  static Test *End;
+};
+
+} // namespace testing
+} // namespace llvm_libc
+
+#define TEST(SuiteName, TestName)                                              \
+  class SuiteName##_##TestName : public llvm_libc::testing::Test {             \
+  public:                                                                      \
+    SuiteName##_##TestName() { addTest(this); }                                \
+    void Run(llvm_libc::testing::RunContext &) override;                       \
+    const char *getName() const override { return #SuiteName "." #TestName; }  \
+  };                                                                           \
+  SuiteName##_##TestName SuiteName##_##TestName##_Instance;                    \
+  void SuiteName##_##TestName::Run(llvm_libc::testing::RunContext &Ctx)
+
+#define TEST_F(SuiteClass, TestName)                                           \
+  class SuiteClass##_##TestName : public SuiteClass {                          \
+  public:                                                                      \
+    SuiteClass##_##TestName() { addTest(this); }                               \
+    void Run(llvm_libc::testing::RunContext &) override;                       \
+    const char *getName() const override { return #SuiteClass "." #TestName; } \
+  };                                                                           \
+  SuiteClass##_##TestName SuiteClass##_##TestName##_Instance;                  \
+  void SuiteClass##_##TestName::Run(llvm_libc::testing::RunContext &Ctx)
+
+#define EXPECT_EQ(LHS, RHS)                                                    \
+  llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_EQ, (LHS),      \
+                                 (RHS), #LHS, #RHS, __FILE__, __LINE__)
+#define ASSERT_EQ(LHS, RHS)                                                    \
+  if (!EXPECT_EQ(LHS, RHS))                                                    \
+  return
+
+#define EXPECT_NE(LHS, RHS)                                                    \
+  llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_NE, (LHS),      \
+                                 (RHS), #LHS, #RHS, __FILE__, __LINE__)
+#define ASSERT_NE(LHS, RHS)                                                    \
+  if (!EXPECT_NE(LHS, RHS))                                                    \
+  return
+
+#define EXPECT_LT(LHS, RHS)                                                    \
+  llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_LT, (LHS),      \
+                                 (RHS), #LHS, #RHS, __FILE__, __LINE__)
+#define ASSERT_LT(LHS, RHS)                                                    \
+  if (!EXPECT_LT(LHS, RHS))                                                    \
+  return
+
+#define EXPECT_LE(LHS, RHS)                                                    \
+  llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_LE, (LHS),      \
+                                 (RHS), #LHS, #RHS, __FILE__, __LINE__)
+#define ASSERT_LE(LHS, RHS)                                                    \
+  if (!EXPECT_LE(LHS, RHS))                                                    \
+  return
+
+#define EXPECT_GT(LHS, RHS)                                                    \
+  llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_GT, (LHS),      \
+                                 (RHS), #LHS, #RHS, __FILE__, __LINE__)
+#define ASSERT_GT(LHS, RHS)                                                    \
+  if (!EXPECT_GT(LHS, RHS))                                                    \
+  return
+
+#define EXPECT_GE(LHS, RHS)                                                    \
+  llvm_libc::testing::Test::test(Ctx, llvm_libc::testing::Cond_GE, (LHS),      \
+                                 (RHS), #LHS, #RHS, __FILE__, __LINE__)
+#define ASSERT_GE(LHS, RHS)                                                    \
+  if (!EXPECT_GE(LHS, RHS))                                                    \
+  return
+
+#define EXPECT_STREQ(LHS, RHS)                                                 \
+  llvm_libc::testing::Test::testStrEq(Ctx, (LHS), (RHS), #LHS, #RHS, __FILE__, \
+                                      __LINE__)
+#define ASSERT_STREQ(LHS, RHS)                                                 \
+  if (!EXPECT_STREQ(LHS, RHS))                                                 \
+  return
+
+#define EXPECT_STRNE(LHS, RHS)                                                 \
+  llvm_libc::testing::Test::testStrNe(Ctx, (LHS), (RHS), #LHS, #RHS, __FILE__, \
+                                      __LINE__)
+#define ASSERT_STRNE(LHS, RHS)                                                 \
+  if (!EXPECT_STRNE(LHS, RHS))                                                 \
+  return


        


More information about the libc-commits mailing list