[libc-commits] [libc] 1e8960c - [libc] Add rule named `add_libc_hermetic_test` which adds a hermetic test.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Mon Apr 24 15:44:28 PDT 2023


Author: Siva Chandra Reddy
Date: 2023-04-24T22:43:59Z
New Revision: 1e8960c7a588c117bf703221ce656aeb034219c5

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

LOG: [libc] Add rule named `add_libc_hermetic_test` which adds a hermetic test.

A convenience wrapper name `add_libc_test` is also added which adds both
a unit test and a hermetic test. The ctype tests have been switched over
to use add_libc_test.

Reviewed By: jhuber6

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

Added: 
    libc/test/UnitTest/HermeticTestUtils.cpp
    libc/test/UnitTest/LibcDeathTestExecutors.cpp

Modified: 
    libc/CMakeLists.txt
    libc/cmake/modules/LLVMLibCTestRules.cmake
    libc/test/CMakeLists.txt
    libc/test/UnitTest/CMakeLists.txt
    libc/test/UnitTest/LibcTest.cpp
    libc/test/UnitTest/LibcTest.h
    libc/test/UnitTest/LibcTestMain.cpp
    libc/test/src/ctype/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index 958de3b30ad20..da669a1d5e58e 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -75,11 +75,15 @@ option(LLVM_LIBC_ENABLE_LINTING "Enables linting of libc source files" OFF)
 option(LIBC_GPU_BUILD "Build libc for the GPU. All CPU build options will be ignored." OFF)
 set(LIBC_TARGET_TRIPLE "" CACHE STRING "The target triple for the libc build.")
 
+set(LIBC_ENABLE_UNITTESTS ON)
+set(LIBC_ENABLE_HERMETIC_TESTS ON)
+
 # Defines LIBC_TARGET_ARCHITECTURE and associated macros.
 include(LLVMLibCArchitectures)
 
 if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
   include(prepare_libc_gpu_build)
+  set(LIBC_ENABLE_UNITTESTS OFF)
 endif()
 
 include(LLVMLibCCheckMPFR)

diff  --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index c7689749b84d2..a059ac2134acb 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -77,7 +77,7 @@ function(create_libc_unittest fq_target_name)
 
   cmake_parse_arguments(
     "LIBC_UNITTEST"
-    "NO_RUN_POSTBUILD;NO_LIBC_UNITTEST_TEST_MAIN" # Optional arguments
+    "NO_RUN_POSTBUILD" # Optional arguments
     "SUITE;CXX_STANDARD" # Single value arguments
     "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;LINK_LIBRARIES;FLAGS" # Multi-value arguments
     ${ARGN}
@@ -179,11 +179,7 @@ function(create_libc_unittest fq_target_name)
   )
 
   # LibcUnitTest should not depend on anything in LINK_LIBRARIES.
-  if(NO_LIBC_UNITTEST_TEST_MAIN)
-    list(APPEND link_libraries LibcUnitTest)
-  else()
-    list(APPEND link_libraries LibcUnitTest LibcUnitTestMain)
-  endif()
+  list(APPEND link_libraries LibcTestMain LibcUnitTest)
 
   target_link_libraries(${fq_build_target_name} PRIVATE ${link_libraries})
 
@@ -386,6 +382,8 @@ function(add_libc_fuzzer target_name)
 
 endfunction(add_libc_fuzzer)
 
+# DEPRECATED: Use add_hermetic_test instead.
+#
 # Rule to add an integration test. An integration test is like a unit test
 # but does not use the system libc. Not even the startup objects from the
 # system libc are linked in to the final executable. The final exe is fully
@@ -544,3 +542,158 @@ function(add_integration_test test_name)
   )
   add_dependencies(${INTEGRATION_TEST_SUITE} ${fq_target_name})
 endfunction(add_integration_test)
+
+set(LIBC_HERMETIC_TEST_COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_DEFAULT}
+    -fpie -ffreestanding -fno-exceptions -fno-rtti)
+# The GPU build requires overriding the default CMake triple and architecture.
+if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU)
+  list(APPEND LIBC_HERMETIC_TEST_COMPILE_OPTIONS
+       -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto --target=${LIBC_GPU_TARGET_TRIPLE})
+elseif(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
+  get_nvptx_compile_options(nvptx_options ${LIBC_GPU_TARGET_ARCHITECTURE})
+  list(APPEND ${nvptx_options} --target=${LIBC_GPU_TARGET_TRIPLE})
+endif()
+
+# Rule to add a hermetic test. A hermetic test is one whose executable is fully
+# statically linked and consists of pieces drawn only from LLVM's libc. Nothing,
+# including the startup objects, come from the system libc.
+#
+# Usage:
+#   add_libc_hermetic_test(
+#     <target name>
+#     SUITE <the suite to which the test should belong>
+#     SRCS <src1.cpp> [src2.cpp ...]
+#     HDRS [hdr1.cpp ...]
+#     DEPENDS <list of entrypoint or other object targets>
+#     ARGS <list of command line arguments to be passed to the test>
+#     ENV <list of environment variables to set before running the test>
+#     COMPILE_OPTIONS <list of special compile options for the test>
+#     LOADER_ARGS <list of special args to loaders (like the GPU loader)>
+#   )
+function(add_libc_hermetic_test test_name)
+  if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1)
+    message(VERBOSE "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.")
+    return()
+  endif()
+  cmake_parse_arguments(
+    "HERMETIC_TEST"
+    "" # No optional arguments
+    "SUITE" # Single value arguments
+    "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LOADER_ARGS" # Multi-value arguments
+    ${ARGN}
+  )
+
+  if(NOT HERMETIC_TEST_SUITE)
+    message(FATAL_ERROR "SUITE not specified for ${fq_target_name}")
+  endif()
+  if(NOT HERMETIC_TEST_SRCS)
+    message(FATAL_ERROR "The SRCS list for add_integration_test is missing.")
+  endif()
+
+  get_fq_target_name(${test_name} fq_target_name)
+  get_fq_target_name(${test_name}.libc fq_libc_target_name)
+
+  get_fq_deps_list(fq_deps_list ${HERMETIC_TEST_DEPENDS})
+  list(APPEND fq_deps_list
+      # Hermetic tests use the platform's startup object. So, their deps also
+      # have to be collected.
+      libc.startup.${LIBC_TARGET_OS}.crt1
+      # We always add the memory functions objects. This is because the
+      # compiler's codegen can emit calls to the C memory functions.
+      libc.src.string.bcmp
+      libc.src.string.bzero
+      libc.src.string.memcmp
+      libc.src.string.memcpy
+      libc.src.string.memmove
+      libc.src.string.memset
+  )
+  list(REMOVE_DUPLICATES fq_deps_list)
+
+  # TODO: Instead of gathering internal object files from entrypoints,
+  # collect the object files with public names of entrypoints.
+  get_object_files_for_test(
+      link_object_files skipped_entrypoints_list ${fq_deps_list})
+  if(skipped_entrypoints_list)
+    set(msg "Skipping unittest ${fq_target_name} as it has missing deps: "
+            "${skipped_entrypoints_list}.")
+    message(STATUS ${msg})
+    return()
+  endif()
+  list(REMOVE_DUPLICATES link_object_files)
+
+  # Make a library of all deps
+  add_library(
+    ${fq_target_name}.__libc__
+    STATIC
+    EXCLUDE_FROM_ALL
+    ${link_object_files}
+  )
+  set_target_properties(${fq_target_name}.__libc__
+      PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+  set_target_properties(${fq_target_name}.__libc__
+      PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc)
+
+  set(fq_build_target_name ${fq_target_name}.__build__)
+  add_executable(
+    ${fq_build_target_name}
+    EXCLUDE_FROM_ALL
+    # The NVIDIA 'nvlink' linker does not currently support static libraries.
+    $<$<BOOL:${LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX}>:${link_object_files}>
+    ${HERMETIC_TEST_SRCS}
+    ${HERMETIC_TEST_HDRS}
+  )
+  set_target_properties(${fq_build_target_name}
+    PROPERTIES
+      RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+      #OUTPUT_NAME ${fq_target_name}
+  )
+  target_include_directories(
+    ${fq_build_target_name}
+    PRIVATE
+      ${LIBC_SOURCE_DIR}
+      ${LIBC_BUILD_DIR}
+      ${LIBC_BUILD_DIR}/include
+  )
+  target_compile_options(${fq_build_target_name}
+      PRIVATE ${LIBC_HERMETIC_TEST_COMPILE_OPTIONS} ${HERMETIC_TEST_COMPILE_OPTIONS})
+
+  target_link_options(${fq_build_target_name} PRIVATE -nostdlib -static)
+  target_link_libraries(
+    ${fq_build_target_name}
+    libc.startup.${LIBC_TARGET_OS}.crt1
+    LibcTestMain LibcHermeticTest
+    # The NVIDIA 'nvlink' linker does not currently support static libraries.
+    $<$<NOT:$<BOOL:${LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX}>>:${fq_target_name}.__libc__>)
+  add_dependencies(${fq_build_target_name}
+                   LibcHermeticTest
+                   ${HERMETIC_TEST_DEPENDS})
+
+  # Tests on the GPU require an external loader utility to launch the kernel.
+  if(TARGET libc.utils.gpu.loader)
+    add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)
+    get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")
+  endif()
+
+  set(test_cmd ${HERMETIC_TEST_ENV}
+      $<$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_GPU}>:${gpu_loader_exe}> ${HERMETIC_TEST_LOADER_ARGS}
+      $<TARGET_FILE:${fq_build_target_name}> ${HERMETIC_TEST_ARGS})
+  add_custom_target(
+    ${fq_target_name}
+    COMMAND ${test_cmd}
+    COMMAND_EXPAND_LISTS
+    COMMENT "Running hermetic test ${fq_target_name}"
+  )
+
+  add_dependencies(${HERMETIC_TEST_SUITE} ${fq_target_name})
+  add_dependencies(libc-hermetic-tests ${fq_target_name})
+endfunction(add_libc_hermetic_test)
+
+# A convenience function to add both a unit test as well as a hermetic test.
+function(add_libc_test test_name)
+  if(LIBC_ENABLE_UNITTESTS)
+    add_libc_unittest(${test_name}.__unit__ ${ARGN})
+  endif()
+  if(LIBC_ENABLE_HERMETIC_TESTS)
+    add_libc_hermetic_test(${test_name}.__hermetic__ ${ARGN})
+  endif()
+endfunction(add_libc_test)

diff  --git a/libc/test/CMakeLists.txt b/libc/test/CMakeLists.txt
index 710f1138a6f2b..333873a07b22a 100644
--- a/libc/test/CMakeLists.txt
+++ b/libc/test/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_custom_target(check-libc)
 add_custom_target(libc-unit-tests)
-add_dependencies(check-libc libc-unit-tests)
+add_custom_target(libc-hermetic-tests)
+add_dependencies(check-libc libc-unit-tests libc-hermetic-tests)
 
 add_custom_target(exhaustive-check-libc)
 add_custom_target(libc-long-running-tests)

diff  --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt
index f3d5a2b191943..389a59c4401a2 100644
--- a/libc/test/UnitTest/CMakeLists.txt
+++ b/libc/test/UnitTest/CMakeLists.txt
@@ -1,5 +1,4 @@
-set(libc_unit_test_srcs
-  ExecuteFunction.h
+set(libc_test_srcs_common
   Test.h
   LibcTest.cpp
   LibcTest.h
@@ -7,32 +6,47 @@ set(libc_unit_test_srcs
   TestLogger.h
 )
 
+set(libc_death_test_srcs ExecuteFunction.h)
 if(${LIBC_TARGET_OS} STREQUAL "linux")
-  list(APPEND libc_unit_test_srcs ExecuteFunctionUnix.cpp)
+  list(APPEND libc_death_test_srcs 
+       LibcDeathTestExecutors.cpp ExecuteFunctionUnix.cpp)
 endif()
 
 add_library(
   LibcUnitTest
-  ${libc_unit_test_srcs}
+  ${libc_test_srcs_common}
+  ${libc_death_test_srcs}
 )
 
-target_include_directories(LibcUnitTest PUBLIC ${LIBC_SOURCE_DIR})
-add_dependencies(
-  LibcUnitTest
-  libc.src.__support.CPP.string
-  libc.src.__support.CPP.string_view
-  libc.src.__support.CPP.type_traits
-  libc.src.__support.OSUtil.osutil
-  libc.src.__support.uint128)
+add_library(
+  LibcHermeticTest
+  ${libc_test_srcs_common}
+  HermeticTestUtils.cpp
+)
+
+foreach(lib LibcUnitTest LibcHermeticTest)
+  target_include_directories(${lib} PUBLIC ${LIBC_SOURCE_DIR})
+  target_compile_options(${lib} PRIVATE ${LIBC_HERMETIC_TEST_COMPILE_OPTIONS}
+                         -fno-exceptions -fno-rtti)
+  add_dependencies(${lib}
+    libc.src.__support.CPP.string
+    libc.src.__support.CPP.string_view
+    libc.src.__support.CPP.type_traits
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.uint128
+  )
+endforeach()
+
+target_compile_options(LibcHermeticTest PRIVATE -ffreestanding -nostdlib -nostdlib++)
 
 add_library(
-  LibcUnitTestMain
+  LibcTestMain
   LibcTestMain.cpp
 )
 
-target_include_directories(LibcUnitTestMain PUBLIC ${LIBC_SOURCE_DIR})
-add_dependencies(LibcUnitTestMain LibcUnitTest)
-target_link_libraries(LibcUnitTestMain PUBLIC LibcUnitTest)
+target_include_directories(LibcTestMain PUBLIC ${LIBC_SOURCE_DIR})
+target_compile_options(LibcTestMain PRIVATE -fno-exceptions -fno-rtti)
+add_dependencies(LibcTestMain LibcUnitTest)
 
 add_header_library(
   string_utils

diff  --git a/libc/test/UnitTest/HermeticTestUtils.cpp b/libc/test/UnitTest/HermeticTestUtils.cpp
new file mode 100644
index 0000000000000..ea819c4174371
--- /dev/null
+++ b/libc/test/UnitTest/HermeticTestUtils.cpp
@@ -0,0 +1,91 @@
+//===-- Implementation of libc death test executors -----------------------===//
+//
+// 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 <stddef.h>
+#include <stdint.h>
+
+namespace __llvm_libc {
+
+int bcmp(const void *lhs, const void *rhs, size_t count);
+void bzero(void *ptr, size_t count);
+int memcmp(const void *lhs, const void *rhs, size_t count);
+void *memcpy(void *__restrict, const void *__restrict, size_t);
+void *memmove(void *dst, const void *src, size_t count);
+void *memset(void *ptr, int value, size_t count);
+
+} // namespace __llvm_libc
+
+namespace {
+
+// Integration tests cannot use the SCUDO standalone allocator as SCUDO pulls
+// various other parts of the libc. Since SCUDO development does not use
+// LLVM libc build rules, it is very hard to keep track or pull all that SCUDO
+// requires. Hence, as a work around for this problem, we use a simple allocator
+// which just hands out continuous blocks from a statically allocated chunk of
+// memory.
+static uint8_t memory[16384];
+static uint8_t *ptr = memory;
+
+} // anonymous namespace
+
+extern "C" {
+
+// Hermetic tests rely on the following memory functions. This is because the
+// compiler code generation can emit calls to them. We want to map the external
+// entrypoint to the internal implementation of the function used for testing.
+// This is done manually as not all targets support aliases.
+
+int bcmp(const void *lhs, const void *rhs, size_t count) {
+  return __llvm_libc::bcmp(lhs, rhs, count);
+}
+void bzero(void *ptr, size_t count) { __llvm_libc::bzero(ptr, count); }
+int memcmp(const void *lhs, const void *rhs, size_t count) {
+  return __llvm_libc::memcmp(lhs, rhs, count);
+}
+void *memcpy(void *__restrict dst, const void *__restrict src, size_t count) {
+  return __llvm_libc::memcpy(dst, src, count);
+}
+void *memmove(void *dst, const void *src, size_t count) {
+  return __llvm_libc::memmove(dst, src, count);
+}
+void *memset(void *ptr, int value, size_t count) {
+  return __llvm_libc::memset(ptr, value, count);
+}
+
+void *malloc(size_t s) {
+  void *mem = ptr;
+  ptr += s;
+  return mem;
+}
+
+void free(void *) {}
+
+void *realloc(void *ptr, size_t s) {
+  free(ptr);
+  return malloc(s);
+}
+
+// The unit test framework uses pure virtual functions. Since hermetic tests
+// cannot depend C++ runtime libraries, implement dummy functions to support
+// the virtual function runtime.
+void __cxa_pure_virtual() {
+  // A pure virtual being called is an error so we just trap.
+  __builtin_trap();
+}
+
+// Integration tests are linked with -nostdlib. BFD linker expects
+// __dso_handle when -nostdlib is used.
+void *__dso_handle = nullptr;
+
+} // extern "C"
+
+void operator delete(void *) {
+  // The libc runtime should not use the global delete operator. Hence,
+  // we just trap here to catch any such accidental usages.
+  __builtin_trap();
+}

diff  --git a/libc/test/UnitTest/LibcDeathTestExecutors.cpp b/libc/test/UnitTest/LibcDeathTestExecutors.cpp
new file mode 100644
index 0000000000000..c756a8dbe0302
--- /dev/null
+++ b/libc/test/UnitTest/LibcDeathTestExecutors.cpp
@@ -0,0 +1,102 @@
+//===-- Implementation of libc death test executors -----------------------===//
+//
+// 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 "LibcTest.h"
+
+#include "test/UnitTest/ExecuteFunction.h"
+#include "test/UnitTest/TestLogger.h"
+
+#include <cassert>
+
+namespace __llvm_libc {
+namespace testing {
+
+bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal,
+                             const char *LHSStr, const char *RHSStr,
+                             const char *File, unsigned long Line) {
+  testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500);
+
+  if (const char *error = Result.get_error()) {
+    Ctx->markFail();
+    tlog << File << ":" << Line << ": FAILURE\n" << error << '\n';
+    return false;
+  }
+
+  if (Result.timed_out()) {
+    Ctx->markFail();
+    tlog << File << ":" << Line << ": FAILURE\n"
+         << "Process timed out after " << 500 << " milliseconds.\n";
+    return false;
+  }
+
+  if (Result.exited_normally()) {
+    Ctx->markFail();
+    tlog << File << ":" << Line << ": FAILURE\n"
+         << "Expected " << LHSStr
+         << " to be killed by a signal\nBut it exited normally!\n";
+    return false;
+  }
+
+  int KilledBy = Result.get_fatal_signal();
+  assert(KilledBy != 0 && "Not killed by any signal");
+  if (Signal == -1 || KilledBy == Signal)
+    return true;
+
+  using testutils::signal_as_string;
+  Ctx->markFail();
+  tlog << File << ":" << Line << ": FAILURE\n"
+       << "              Expected: " << LHSStr << '\n'
+       << "To be killed by signal: " << Signal << '\n'
+       << "              Which is: " << signal_as_string(Signal) << '\n'
+       << "  But it was killed by: " << KilledBy << '\n'
+       << "              Which is: " << signal_as_string(KilledBy) << '\n';
+  return false;
+}
+
+bool Test::testProcessExits(testutils::FunctionCaller *Func, int ExitCode,
+                            const char *LHSStr, const char *RHSStr,
+                            const char *File, unsigned long Line) {
+  testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500);
+
+  if (const char *error = Result.get_error()) {
+    Ctx->markFail();
+    tlog << File << ":" << Line << ": FAILURE\n" << error << '\n';
+    return false;
+  }
+
+  if (Result.timed_out()) {
+    Ctx->markFail();
+    tlog << File << ":" << Line << ": FAILURE\n"
+         << "Process timed out after " << 500 << " milliseconds.\n";
+    return false;
+  }
+
+  if (!Result.exited_normally()) {
+    Ctx->markFail();
+    tlog << File << ":" << Line << ": FAILURE\n"
+         << "Expected " << LHSStr << '\n'
+         << "to exit with exit code " << ExitCode << '\n'
+         << "But it exited abnormally!\n";
+    return false;
+  }
+
+  int ActualExit = Result.get_exit_code();
+  if (ActualExit == ExitCode)
+    return true;
+
+  Ctx->markFail();
+  tlog << File << ":" << Line << ": FAILURE\n"
+       << "Expected exit code of: " << LHSStr << '\n'
+       << "             Which is: " << ActualExit << '\n'
+       << "       To be equal to: " << RHSStr << '\n'
+       << "             Which is: " << ExitCode << '\n';
+  return false;
+}
+
+} // namespace testing
+} // namespace __llvm_libc

diff  --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp
index b3a7fc18dfda2..dabfe2b6bd8a0 100644
--- a/libc/test/UnitTest/LibcTest.cpp
+++ b/libc/test/UnitTest/LibcTest.cpp
@@ -11,28 +11,11 @@
 #include "src/__support/CPP/string.h"
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/UInt128.h"
-#include "test/UnitTest/ExecuteFunction.h"
 #include "test/UnitTest/TestLogger.h"
-#include <cassert>
 
 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 {
 
 // When the value is UInt128 or __uint128_t, show its hexadecimal digits.
@@ -149,6 +132,12 @@ bool test(RunContext *Ctx, TestCondition Cond, ValType LHS, ValType RHS,
 Test *Test::Start = nullptr;
 Test *Test::End = nullptr;
 
+int argc = 0;
+char **argv = nullptr;
+char **envp = nullptr;
+
+using internal::RunContext;
+
 void Test::addTest(Test *T) {
   if (End == nullptr) {
     Start = T;
@@ -326,90 +315,5 @@ bool Test::testMatch(bool MatchResult, MatcherBase &Matcher, const char *LHSStr,
   return false;
 }
 
-#ifdef ENABLE_SUBPROCESS_TESTS
-
-bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal,
-                             const char *LHSStr, const char *RHSStr,
-                             const char *File, unsigned long Line) {
-  testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500);
-
-  if (const char *error = Result.get_error()) {
-    Ctx->markFail();
-    tlog << File << ":" << Line << ": FAILURE\n" << error << '\n';
-    return false;
-  }
-
-  if (Result.timed_out()) {
-    Ctx->markFail();
-    tlog << File << ":" << Line << ": FAILURE\n"
-         << "Process timed out after " << 500 << " milliseconds.\n";
-    return false;
-  }
-
-  if (Result.exited_normally()) {
-    Ctx->markFail();
-    tlog << File << ":" << Line << ": FAILURE\n"
-         << "Expected " << LHSStr
-         << " to be killed by a signal\nBut it exited normally!\n";
-    return false;
-  }
-
-  int KilledBy = Result.get_fatal_signal();
-  assert(KilledBy != 0 && "Not killed by any signal");
-  if (Signal == -1 || KilledBy == Signal)
-    return true;
-
-  using testutils::signal_as_string;
-  Ctx->markFail();
-  tlog << File << ":" << Line << ": FAILURE\n"
-       << "              Expected: " << LHSStr << '\n'
-       << "To be killed by signal: " << Signal << '\n'
-       << "              Which is: " << signal_as_string(Signal) << '\n'
-       << "  But it was killed by: " << KilledBy << '\n'
-       << "              Which is: " << signal_as_string(KilledBy) << '\n';
-  return false;
-}
-
-bool Test::testProcessExits(testutils::FunctionCaller *Func, int ExitCode,
-                            const char *LHSStr, const char *RHSStr,
-                            const char *File, unsigned long Line) {
-  testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500);
-
-  if (const char *error = Result.get_error()) {
-    Ctx->markFail();
-    tlog << File << ":" << Line << ": FAILURE\n" << error << '\n';
-    return false;
-  }
-
-  if (Result.timed_out()) {
-    Ctx->markFail();
-    tlog << File << ":" << Line << ": FAILURE\n"
-         << "Process timed out after " << 500 << " milliseconds.\n";
-    return false;
-  }
-
-  if (!Result.exited_normally()) {
-    Ctx->markFail();
-    tlog << File << ":" << Line << ": FAILURE\n"
-         << "Expected " << LHSStr << '\n'
-         << "to exit with exit code " << ExitCode << '\n'
-         << "But it exited abnormally!\n";
-    return false;
-  }
-
-  int ActualExit = Result.get_exit_code();
-  if (ActualExit == ExitCode)
-    return true;
-
-  Ctx->markFail();
-  tlog << File << ":" << Line << ": FAILURE\n"
-       << "Expected exit code of: " << LHSStr << '\n'
-       << "             Which is: " << ActualExit << '\n'
-       << "       To be equal to: " << RHSStr << '\n'
-       << "             Which is: " << ExitCode << '\n';
-  return false;
-}
-
-#endif // ENABLE_SUBPROCESS_TESTS
 } // namespace testing
 } // namespace __llvm_libc

diff  --git a/libc/test/UnitTest/LibcTest.h b/libc/test/UnitTest/LibcTest.h
index a1343e2520f78..73683770f2d46 100644
--- a/libc/test/UnitTest/LibcTest.h
+++ b/libc/test/UnitTest/LibcTest.h
@@ -23,8 +23,6 @@
 namespace __llvm_libc {
 namespace testing {
 
-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 boolean values, but use integral return values to indicate true or
@@ -42,6 +40,18 @@ enum TestCondition {
 
 namespace internal {
 
+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;
+};
+
 template <typename ValType>
 bool test(RunContext *Ctx, TestCondition Cond, ValType LHS, ValType RHS,
           const char *LHSStr, const char *RHSStr, const char *File,
@@ -65,9 +75,9 @@ template <typename T> struct Matcher : public MatcherBase {
 class Test {
 private:
   Test *Next = nullptr;
-  RunContext *Ctx = nullptr;
+  internal::RunContext *Ctx = nullptr;
 
-  void setContext(RunContext *C) { Ctx = C; }
+  void setContext(internal::RunContext *C) { Ctx = C; }
 
 public:
   virtual ~Test() {}
@@ -161,6 +171,10 @@ class Test {
   static Test *End;
 };
 
+extern int argc;
+extern char **argv;
+extern char **envp;
+
 namespace internal {
 
 constexpr bool same_prefix(char const *lhs, char const *rhs, int const len) {

diff  --git a/libc/test/UnitTest/LibcTestMain.cpp b/libc/test/UnitTest/LibcTestMain.cpp
index 46e19dd027365..756d1196bc365 100644
--- a/libc/test/UnitTest/LibcTestMain.cpp
+++ b/libc/test/UnitTest/LibcTestMain.cpp
@@ -12,7 +12,11 @@ static const char *getTestFilter(int argc, char *argv[]) {
   return argc > 1 ? argv[1] : nullptr;
 }
 
-int main(int argc, char *argv[]) {
+extern "C" int main(int argc, char **argv, char **envp) {
+  __llvm_libc::testing::argc = argc;
+  __llvm_libc::testing::argv = argv;
+  __llvm_libc::testing::envp = envp;
+
   const char *TestFilter = getTestFilter(argc, argv);
   return __llvm_libc::testing::Test::runTests(TestFilter);
 }

diff  --git a/libc/test/src/ctype/CMakeLists.txt b/libc/test/src/ctype/CMakeLists.txt
index 34377aefc0ecd..0621f83c2bae7 100644
--- a/libc/test/src/ctype/CMakeLists.txt
+++ b/libc/test/src/ctype/CMakeLists.txt
@@ -1,159 +1,159 @@
-add_custom_target(libc_ctype_unittests)
+add_custom_target(libc-ctype-tests)
 
-add_libc_unittest(
+add_libc_test(
   isalnum_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isalnum_test.cpp
   DEPENDS
     libc.src.ctype.isalnum
 )
 
-add_libc_unittest(
+add_libc_test(
   isalpha_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isalpha_test.cpp
   DEPENDS
     libc.src.ctype.isalpha
 )
 
-add_libc_unittest(
+add_libc_test(
   isascii_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isascii_test.cpp
   DEPENDS
     libc.src.ctype.isascii
 )
 
-add_libc_unittest(
+add_libc_test(
   isblank_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isblank_test.cpp
   DEPENDS
     libc.src.ctype.isblank
 )
 
-add_libc_unittest(
+add_libc_test(
   iscntrl_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     iscntrl_test.cpp
   DEPENDS
     libc.src.ctype.iscntrl
 )
 
-add_libc_unittest(
+add_libc_test(
   isdigit_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isdigit_test.cpp
   DEPENDS
     libc.src.ctype.isdigit
 )
 
-add_libc_unittest(
+add_libc_test(
   isgraph_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isgraph_test.cpp
   DEPENDS
     libc.src.ctype.isgraph
 )
 
-add_libc_unittest(
+add_libc_test(
   islower_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     islower_test.cpp
   DEPENDS
     libc.src.ctype.islower
 )
 
-add_libc_unittest(
+add_libc_test(
   isprint_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isprint_test.cpp
   DEPENDS
     libc.src.ctype.isprint
 )
 
-add_libc_unittest(
+add_libc_test(
   ispunct_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     ispunct_test.cpp
   DEPENDS
     libc.src.ctype.ispunct
 )
 
-add_libc_unittest(
+add_libc_test(
   isspace_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isspace_test.cpp
   DEPENDS
     libc.src.ctype.isspace
 )
 
-add_libc_unittest(
+add_libc_test(
   isupper_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isupper_test.cpp
   DEPENDS
     libc.src.ctype.isupper
 )
 
-add_libc_unittest(
+add_libc_test(
   isxdigit_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     isxdigit_test.cpp
   DEPENDS
     libc.src.ctype.isxdigit
 )
 
-add_libc_unittest(
+add_libc_test(
   toascii_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     toascii_test.cpp
   DEPENDS
     libc.src.ctype.toascii
 )
 
-add_libc_unittest(
+add_libc_test(
   tolower_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     tolower_test.cpp
   DEPENDS
     libc.src.ctype.tolower
 )
 
-add_libc_unittest(
+add_libc_test(
   toupper_test
   SUITE
-    libc_ctype_unittests
+    libc-ctype-tests
   SRCS
     toupper_test.cpp
   DEPENDS


        


More information about the libc-commits mailing list