Home | History | Annotate | Download | only in Support
      1 //===- unittest/Support/ProgramTest.cpp -----------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/Support/CommandLine.h"
     11 #include "llvm/Support/FileSystem.h"
     12 #include "llvm/Support/Path.h"
     13 #include "llvm/Support/Program.h"
     14 #include "gtest/gtest.h"
     15 #include <stdlib.h>
     16 #if defined(__APPLE__)
     17 # include <crt_externs.h>
     18 #elif !defined(_MSC_VER)
     19 // Forward declare environ in case it's not provided by stdlib.h.
     20 extern char **environ;
     21 #endif
     22 
     23 #if defined(LLVM_ON_UNIX)
     24 #include <unistd.h>
     25 void sleep_for(unsigned int seconds) {
     26   sleep(seconds);
     27 }
     28 #elif defined(LLVM_ON_WIN32)
     29 #include <windows.h>
     30 void sleep_for(unsigned int seconds) {
     31   Sleep(seconds * 1000);
     32 }
     33 #else
     34 #error sleep_for is not implemented on your platform.
     35 #endif
     36 
     37 // From TestMain.cpp.
     38 extern const char *TestMainArgv0;
     39 
     40 namespace {
     41 
     42 using namespace llvm;
     43 using namespace sys;
     44 
     45 static cl::opt<std::string>
     46 ProgramTestStringArg1("program-test-string-arg1");
     47 static cl::opt<std::string>
     48 ProgramTestStringArg2("program-test-string-arg2");
     49 
     50 static void CopyEnvironment(std::vector<const char *> &out) {
     51 #ifdef __APPLE__
     52   char **envp = *_NSGetEnviron();
     53 #else
     54   // environ seems to work for Windows and most other Unices.
     55   char **envp = environ;
     56 #endif
     57   while (*envp != nullptr) {
     58     out.push_back(*envp);
     59     ++envp;
     60   }
     61 }
     62 
     63 TEST(ProgramTest, CreateProcessTrailingSlash) {
     64   if (getenv("LLVM_PROGRAM_TEST_CHILD")) {
     65     if (ProgramTestStringArg1 == "has\\\\ trailing\\" &&
     66         ProgramTestStringArg2 == "has\\\\ trailing\\") {
     67       exit(0);  // Success!  The arguments were passed and parsed.
     68     }
     69     exit(1);
     70   }
     71 
     72   std::string my_exe =
     73       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
     74   const char *argv[] = {
     75     my_exe.c_str(),
     76     "--gtest_filter=ProgramTest.CreateProcessTrailingSlash",
     77     "-program-test-string-arg1", "has\\\\ trailing\\",
     78     "-program-test-string-arg2", "has\\\\ trailing\\",
     79     nullptr
     80   };
     81 
     82   // Add LLVM_PROGRAM_TEST_CHILD to the environment of the child.
     83   std::vector<const char *> envp;
     84   CopyEnvironment(envp);
     85   envp.push_back("LLVM_PROGRAM_TEST_CHILD=1");
     86   envp.push_back(nullptr);
     87 
     88   std::string error;
     89   bool ExecutionFailed;
     90   // Redirect stdout and stdin to NUL, but let stderr through.
     91 #ifdef LLVM_ON_WIN32
     92   StringRef nul("NUL");
     93 #else
     94   StringRef nul("/dev/null");
     95 #endif
     96   const StringRef *redirects[] = { &nul, &nul, nullptr };
     97   int rc = ExecuteAndWait(my_exe, argv, &envp[0], redirects,
     98                           /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error,
     99                           &ExecutionFailed);
    100   EXPECT_FALSE(ExecutionFailed) << error;
    101   EXPECT_EQ(0, rc);
    102 }
    103 
    104 TEST(ProgramTest, TestExecuteNoWait) {
    105   using namespace llvm::sys;
    106 
    107   if (getenv("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT")) {
    108     sleep_for(/*seconds*/ 1);
    109     exit(0);
    110   }
    111 
    112   std::string Executable =
    113       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
    114   const char *argv[] = {
    115     Executable.c_str(),
    116     "--gtest_filter=ProgramTest.TestExecuteNoWait",
    117     nullptr
    118   };
    119 
    120   // Add LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT to the environment of the child.
    121   std::vector<const char *> envp;
    122   CopyEnvironment(envp);
    123   envp.push_back("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT=1");
    124   envp.push_back(nullptr);
    125 
    126   std::string Error;
    127   bool ExecutionFailed;
    128   ProcessInfo PI1 = ExecuteNoWait(Executable, argv, &envp[0], nullptr, 0,
    129                                   &Error, &ExecutionFailed);
    130   ASSERT_FALSE(ExecutionFailed) << Error;
    131   ASSERT_NE(PI1.Pid, 0) << "Invalid process id";
    132 
    133   unsigned LoopCount = 0;
    134 
    135   // Test that Wait() with WaitUntilTerminates=true works. In this case,
    136   // LoopCount should only be incremented once.
    137   while (true) {
    138     ++LoopCount;
    139     ProcessInfo WaitResult = Wait(PI1, 0, true, &Error);
    140     ASSERT_TRUE(Error.empty());
    141     if (WaitResult.Pid == PI1.Pid)
    142       break;
    143   }
    144 
    145   EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1";
    146 
    147   ProcessInfo PI2 = ExecuteNoWait(Executable, argv, &envp[0], nullptr, 0,
    148                                   &Error, &ExecutionFailed);
    149   ASSERT_FALSE(ExecutionFailed) << Error;
    150   ASSERT_NE(PI2.Pid, 0) << "Invalid process id";
    151 
    152   // Test that Wait() with SecondsToWait=0 performs a non-blocking wait. In this
    153   // cse, LoopCount should be greater than 1 (more than one increment occurs).
    154   while (true) {
    155     ++LoopCount;
    156     ProcessInfo WaitResult = Wait(PI2, 0, false, &Error);
    157     ASSERT_TRUE(Error.empty());
    158     if (WaitResult.Pid == PI2.Pid)
    159       break;
    160   }
    161 
    162   ASSERT_GT(LoopCount, 1u) << "LoopCount should be >1";
    163 }
    164 
    165 TEST(ProgramTest, TestExecuteAndWaitTimeout) {
    166   using namespace llvm::sys;
    167 
    168   if (getenv("LLVM_PROGRAM_TEST_TIMEOUT")) {
    169     sleep_for(/*seconds*/ 10);
    170     exit(0);
    171   }
    172 
    173   std::string Executable =
    174       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
    175   const char *argv[] = {
    176     Executable.c_str(),
    177     "--gtest_filter=ProgramTest.TestExecuteAndWaitTimeout",
    178     nullptr
    179   };
    180 
    181   // Add LLVM_PROGRAM_TEST_TIMEOUT to the environment of the child.
    182   std::vector<const char *> envp;
    183   CopyEnvironment(envp);
    184   envp.push_back("LLVM_PROGRAM_TEST_TIMEOUT=1");
    185   envp.push_back(nullptr);
    186 
    187   std::string Error;
    188   bool ExecutionFailed;
    189   int RetCode =
    190       ExecuteAndWait(Executable, argv, &envp[0], nullptr, /*secondsToWait=*/1, 0,
    191                      &Error, &ExecutionFailed);
    192   ASSERT_EQ(-2, RetCode);
    193 }
    194 
    195 TEST(ProgramTest, TestExecuteNegative) {
    196   std::string Executable = "i_dont_exist";
    197   const char *argv[] = { Executable.c_str(), nullptr };
    198 
    199   {
    200     std::string Error;
    201     bool ExecutionFailed;
    202     int RetCode = ExecuteAndWait(Executable, argv, nullptr, nullptr, 0, 0,
    203                                  &Error, &ExecutionFailed);
    204     ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or "
    205                                 "positive value indicating the result code";
    206     ASSERT_TRUE(ExecutionFailed);
    207     ASSERT_FALSE(Error.empty());
    208   }
    209 
    210   {
    211     std::string Error;
    212     bool ExecutionFailed;
    213     ProcessInfo PI = ExecuteNoWait(Executable, argv, nullptr, nullptr, 0,
    214                                    &Error, &ExecutionFailed);
    215     ASSERT_EQ(PI.Pid, 0)
    216         << "On error ExecuteNoWait should return an invalid ProcessInfo";
    217     ASSERT_TRUE(ExecutionFailed);
    218     ASSERT_FALSE(Error.empty());
    219   }
    220 
    221 }
    222 
    223 } // end anonymous namespace
    224