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 != 0) { 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 0 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(0); 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, 0 }; 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 0 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(0); 125 126 std::string Error; 127 bool ExecutionFailed; 128 ProcessInfo PI1 = 129 ExecuteNoWait(Executable, argv, &envp[0], 0, 0, &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 = 148 ExecuteNoWait(Executable, argv, &envp[0], 0, 0, &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, TestExecuteNegative) { 166 std::string Executable = "i_dont_exist"; 167 const char *argv[] = { Executable.c_str(), 0 }; 168 169 { 170 std::string Error; 171 bool ExecutionFailed; 172 int RetCode = 173 ExecuteAndWait(Executable, argv, 0, 0, 0, 0, &Error, &ExecutionFailed); 174 ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or " 175 "positive value indicating the result code"; 176 ASSERT_TRUE(ExecutionFailed); 177 ASSERT_FALSE(Error.empty()); 178 } 179 180 { 181 std::string Error; 182 bool ExecutionFailed; 183 ProcessInfo PI = 184 ExecuteNoWait(Executable, argv, 0, 0, 0, &Error, &ExecutionFailed); 185 ASSERT_EQ(PI.Pid, 0) 186 << "On error ExecuteNoWait should return an invalid ProcessInfo"; 187 ASSERT_TRUE(ExecutionFailed); 188 ASSERT_FALSE(Error.empty()); 189 } 190 191 } 192 193 } // end anonymous namespace 194