Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 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 | |
Chandler Carruth | 9a67b07 | 2017-06-06 11:06:56 +0000 | [diff] [blame] | 10 | #include "llvm/Support/Program.h" |
Nico Weber | 432a388 | 2018-04-30 14:59:11 +0000 | [diff] [blame^] | 11 | #include "llvm/Config/llvm-config.h" |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 12 | #include "llvm/Support/CommandLine.h" |
Chandler Carruth | 9a67b07 | 2017-06-06 11:06:56 +0000 | [diff] [blame] | 13 | #include "llvm/Support/ConvertUTF.h" |
Rafael Espindola | e03dfd9 | 2013-06-26 05:01:35 +0000 | [diff] [blame] | 14 | #include "llvm/Support/FileSystem.h" |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 15 | #include "llvm/Support/Path.h" |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 16 | #include "gtest/gtest.h" |
Duncan P. N. Exon Smith | 91d3cfe | 2016-04-05 20:45:04 +0000 | [diff] [blame] | 17 | #include <stdlib.h> |
Reid Kleckner | 206ddd0 | 2013-04-24 17:50:30 +0000 | [diff] [blame] | 18 | #if defined(__APPLE__) |
Reid Kleckner | de0c260 | 2013-04-23 13:15:51 +0000 | [diff] [blame] | 19 | # include <crt_externs.h> |
Reid Kleckner | 206ddd0 | 2013-04-24 17:50:30 +0000 | [diff] [blame] | 20 | #elif !defined(_MSC_VER) |
Reid Kleckner | de0c260 | 2013-04-23 13:15:51 +0000 | [diff] [blame] | 21 | // Forward declare environ in case it's not provided by stdlib.h. |
| 22 | extern char **environ; |
| 23 | #endif |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 24 | |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 25 | #if defined(LLVM_ON_UNIX) |
| 26 | #include <unistd.h> |
| 27 | void sleep_for(unsigned int seconds) { |
| 28 | sleep(seconds); |
| 29 | } |
Nico Weber | 712e8d2 | 2018-04-29 00:45:03 +0000 | [diff] [blame] | 30 | #elif defined(_WIN32) |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 31 | #include <windows.h> |
| 32 | void sleep_for(unsigned int seconds) { |
| 33 | Sleep(seconds * 1000); |
| 34 | } |
| 35 | #else |
| 36 | #error sleep_for is not implemented on your platform. |
| 37 | #endif |
| 38 | |
Rafael Espindola | 9c35966 | 2014-09-03 20:02:00 +0000 | [diff] [blame] | 39 | #define ASSERT_NO_ERROR(x) \ |
| 40 | if (std::error_code ASSERT_NO_ERROR_ec = x) { \ |
| 41 | SmallString<128> MessageStorage; \ |
| 42 | raw_svector_ostream Message(MessageStorage); \ |
| 43 | Message << #x ": did not return errc::success.\n" \ |
| 44 | << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \ |
| 45 | << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ |
| 46 | GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ |
| 47 | } else { \ |
| 48 | } |
Reid Kleckner | 95012aa | 2013-04-30 04:30:41 +0000 | [diff] [blame] | 49 | // From TestMain.cpp. |
| 50 | extern const char *TestMainArgv0; |
| 51 | |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 52 | namespace { |
| 53 | |
| 54 | using namespace llvm; |
| 55 | using namespace sys; |
| 56 | |
Duncan P. N. Exon Smith | 91d3cfe | 2016-04-05 20:45:04 +0000 | [diff] [blame] | 57 | static cl::opt<std::string> |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 58 | ProgramTestStringArg1("program-test-string-arg1"); |
Duncan P. N. Exon Smith | 91d3cfe | 2016-04-05 20:45:04 +0000 | [diff] [blame] | 59 | static cl::opt<std::string> |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 60 | ProgramTestStringArg2("program-test-string-arg2"); |
| 61 | |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 62 | class ProgramEnvTest : public testing::Test { |
| 63 | std::vector<const char *> EnvTable; |
| 64 | std::vector<std::string> EnvStorage; |
| 65 | |
| 66 | protected: |
| 67 | void SetUp() override { |
| 68 | auto EnvP = [] { |
Nico Weber | 712e8d2 | 2018-04-29 00:45:03 +0000 | [diff] [blame] | 69 | #if defined(_WIN32) |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 70 | _wgetenv(L"TMP"); // Populate _wenviron, initially is null |
| 71 | return _wenviron; |
| 72 | #elif defined(__APPLE__) |
| 73 | return *_NSGetEnviron(); |
Reid Kleckner | de0c260 | 2013-04-23 13:15:51 +0000 | [diff] [blame] | 74 | #else |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 75 | return environ; |
Reid Kleckner | de0c260 | 2013-04-23 13:15:51 +0000 | [diff] [blame] | 76 | #endif |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 77 | }(); |
| 78 | ASSERT_TRUE(EnvP); |
| 79 | |
| 80 | auto prepareEnvVar = [this](decltype(*EnvP) Var) { |
Nico Weber | 712e8d2 | 2018-04-29 00:45:03 +0000 | [diff] [blame] | 81 | #if defined(_WIN32) |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 82 | // On Windows convert UTF16 encoded variable to UTF8 |
| 83 | auto Len = wcslen(Var); |
| 84 | ArrayRef<char> Ref{reinterpret_cast<char const *>(Var), |
| 85 | Len * sizeof(*Var)}; |
| 86 | EnvStorage.emplace_back(); |
| 87 | auto convStatus = convertUTF16ToUTF8String(Ref, EnvStorage.back()); |
| 88 | EXPECT_TRUE(convStatus); |
| 89 | return EnvStorage.back().c_str(); |
| 90 | #else |
Malcolm Parsons | 17d266b | 2017-01-13 17:12:16 +0000 | [diff] [blame] | 91 | (void)this; |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 92 | return Var; |
| 93 | #endif |
| 94 | }; |
| 95 | |
| 96 | while (*EnvP != nullptr) { |
| 97 | EnvTable.emplace_back(prepareEnvVar(*EnvP)); |
| 98 | ++EnvP; |
| 99 | } |
Reid Kleckner | de0c260 | 2013-04-23 13:15:51 +0000 | [diff] [blame] | 100 | } |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 101 | |
| 102 | void TearDown() override { |
| 103 | EnvTable.clear(); |
| 104 | EnvStorage.clear(); |
| 105 | } |
| 106 | |
| 107 | void addEnvVar(const char *Var) { |
| 108 | ASSERT_TRUE(EnvTable.empty() || EnvTable.back()) << "Env table sealed"; |
| 109 | EnvTable.emplace_back(Var); |
| 110 | } |
| 111 | |
| 112 | const char **getEnviron() { |
| 113 | if (EnvTable.back() != nullptr) |
| 114 | EnvTable.emplace_back(nullptr); // Seal table. |
| 115 | return &EnvTable[0]; |
| 116 | } |
| 117 | }; |
Reid Kleckner | de0c260 | 2013-04-23 13:15:51 +0000 | [diff] [blame] | 118 | |
Nico Weber | 712e8d2 | 2018-04-29 00:45:03 +0000 | [diff] [blame] | 119 | #ifdef _WIN32 |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 120 | TEST_F(ProgramEnvTest, CreateProcessLongPath) { |
Paul Robinson | c38deee | 2014-11-24 18:05:29 +0000 | [diff] [blame] | 121 | if (getenv("LLVM_PROGRAM_TEST_LONG_PATH")) |
| 122 | exit(0); |
| 123 | |
| 124 | // getMainExecutable returns an absolute path; prepend the long-path prefix. |
| 125 | std::string MyAbsExe = |
| 126 | sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1); |
| 127 | std::string MyExe; |
| 128 | if (!StringRef(MyAbsExe).startswith("\\\\?\\")) |
| 129 | MyExe.append("\\\\?\\"); |
| 130 | MyExe.append(MyAbsExe); |
| 131 | |
| 132 | const char *ArgV[] = { |
| 133 | MyExe.c_str(), |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 134 | "--gtest_filter=ProgramEnvTest.CreateProcessLongPath", |
Paul Robinson | c38deee | 2014-11-24 18:05:29 +0000 | [diff] [blame] | 135 | nullptr |
| 136 | }; |
| 137 | |
| 138 | // Add LLVM_PROGRAM_TEST_LONG_PATH to the environment of the child. |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 139 | addEnvVar("LLVM_PROGRAM_TEST_LONG_PATH=1"); |
Paul Robinson | c38deee | 2014-11-24 18:05:29 +0000 | [diff] [blame] | 140 | |
| 141 | // Redirect stdout to a long path. |
| 142 | SmallString<128> TestDirectory; |
| 143 | ASSERT_NO_ERROR( |
| 144 | fs::createUniqueDirectory("program-redirect-test", TestDirectory)); |
| 145 | SmallString<256> LongPath(TestDirectory); |
| 146 | LongPath.push_back('\\'); |
| 147 | // MAX_PATH = 260 |
| 148 | LongPath.append(260 - TestDirectory.size(), 'a'); |
Paul Robinson | c38deee | 2014-11-24 18:05:29 +0000 | [diff] [blame] | 149 | |
| 150 | std::string Error; |
| 151 | bool ExecutionFailed; |
Alexander Kornienko | 208eecd | 2017-09-13 17:03:37 +0000 | [diff] [blame] | 152 | Optional<StringRef> Redirects[] = {None, LongPath.str(), None}; |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 153 | int RC = ExecuteAndWait(MyExe, ArgV, getEnviron(), Redirects, |
Paul Robinson | c38deee | 2014-11-24 18:05:29 +0000 | [diff] [blame] | 154 | /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error, |
| 155 | &ExecutionFailed); |
| 156 | EXPECT_FALSE(ExecutionFailed) << Error; |
| 157 | EXPECT_EQ(0, RC); |
| 158 | |
| 159 | // Remove the long stdout. |
| 160 | ASSERT_NO_ERROR(fs::remove(Twine(LongPath))); |
| 161 | ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory))); |
| 162 | } |
| 163 | #endif |
| 164 | |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 165 | TEST_F(ProgramEnvTest, CreateProcessTrailingSlash) { |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 166 | if (getenv("LLVM_PROGRAM_TEST_CHILD")) { |
| 167 | if (ProgramTestStringArg1 == "has\\\\ trailing\\" && |
| 168 | ProgramTestStringArg2 == "has\\\\ trailing\\") { |
| 169 | exit(0); // Success! The arguments were passed and parsed. |
| 170 | } |
| 171 | exit(1); |
| 172 | } |
| 173 | |
Rafael Espindola | e03dfd9 | 2013-06-26 05:01:35 +0000 | [diff] [blame] | 174 | std::string my_exe = |
| 175 | sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1); |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 176 | const char *argv[] = { |
| 177 | my_exe.c_str(), |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 178 | "--gtest_filter=ProgramEnvTest.CreateProcessTrailingSlash", |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 179 | "-program-test-string-arg1", "has\\\\ trailing\\", |
| 180 | "-program-test-string-arg2", "has\\\\ trailing\\", |
Craig Topper | 66f09ad | 2014-06-08 22:29:17 +0000 | [diff] [blame] | 181 | nullptr |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 182 | }; |
Reid Kleckner | de0c260 | 2013-04-23 13:15:51 +0000 | [diff] [blame] | 183 | |
| 184 | // Add LLVM_PROGRAM_TEST_CHILD to the environment of the child. |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 185 | addEnvVar("LLVM_PROGRAM_TEST_CHILD=1"); |
Reid Kleckner | de0c260 | 2013-04-23 13:15:51 +0000 | [diff] [blame] | 186 | |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 187 | std::string error; |
| 188 | bool ExecutionFailed; |
| 189 | // Redirect stdout and stdin to NUL, but let stderr through. |
Nico Weber | 712e8d2 | 2018-04-29 00:45:03 +0000 | [diff] [blame] | 190 | #ifdef _WIN32 |
Rafael Espindola | 7c1023a | 2013-06-13 20:25:38 +0000 | [diff] [blame] | 191 | StringRef nul("NUL"); |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 192 | #else |
Rafael Espindola | 7c1023a | 2013-06-13 20:25:38 +0000 | [diff] [blame] | 193 | StringRef nul("/dev/null"); |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 194 | #endif |
Alexander Kornienko | 208eecd | 2017-09-13 17:03:37 +0000 | [diff] [blame] | 195 | Optional<StringRef> redirects[] = { nul, nul, None }; |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 196 | int rc = ExecuteAndWait(my_exe, argv, getEnviron(), redirects, |
Rafael Espindola | 7c1023a | 2013-06-13 20:25:38 +0000 | [diff] [blame] | 197 | /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error, |
| 198 | &ExecutionFailed); |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 199 | EXPECT_FALSE(ExecutionFailed) << error; |
| 200 | EXPECT_EQ(0, rc); |
| 201 | } |
| 202 | |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 203 | TEST_F(ProgramEnvTest, TestExecuteNoWait) { |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 204 | using namespace llvm::sys; |
| 205 | |
| 206 | if (getenv("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT")) { |
| 207 | sleep_for(/*seconds*/ 1); |
| 208 | exit(0); |
| 209 | } |
| 210 | |
| 211 | std::string Executable = |
| 212 | sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1); |
| 213 | const char *argv[] = { |
| 214 | Executable.c_str(), |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 215 | "--gtest_filter=ProgramEnvTest.TestExecuteNoWait", |
Craig Topper | 66f09ad | 2014-06-08 22:29:17 +0000 | [diff] [blame] | 216 | nullptr |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 217 | }; |
| 218 | |
| 219 | // Add LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT to the environment of the child. |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 220 | addEnvVar("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT=1"); |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 221 | |
| 222 | std::string Error; |
| 223 | bool ExecutionFailed; |
Alexander Kornienko | 208eecd | 2017-09-13 17:03:37 +0000 | [diff] [blame] | 224 | ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error, |
| 225 | &ExecutionFailed); |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 226 | ASSERT_FALSE(ExecutionFailed) << Error; |
Reid Kleckner | c2e2311 | 2016-02-03 21:41:12 +0000 | [diff] [blame] | 227 | ASSERT_NE(PI1.Pid, ProcessInfo::InvalidPid) << "Invalid process id"; |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 228 | |
| 229 | unsigned LoopCount = 0; |
| 230 | |
| 231 | // Test that Wait() with WaitUntilTerminates=true works. In this case, |
| 232 | // LoopCount should only be incremented once. |
| 233 | while (true) { |
| 234 | ++LoopCount; |
Zachary Turner | 07670b3 | 2016-06-29 21:48:26 +0000 | [diff] [blame] | 235 | ProcessInfo WaitResult = llvm::sys::Wait(PI1, 0, true, &Error); |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 236 | ASSERT_TRUE(Error.empty()); |
| 237 | if (WaitResult.Pid == PI1.Pid) |
| 238 | break; |
| 239 | } |
| 240 | |
| 241 | EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1"; |
| 242 | |
Alexander Kornienko | 208eecd | 2017-09-13 17:03:37 +0000 | [diff] [blame] | 243 | ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error, |
| 244 | &ExecutionFailed); |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 245 | ASSERT_FALSE(ExecutionFailed) << Error; |
Reid Kleckner | c2e2311 | 2016-02-03 21:41:12 +0000 | [diff] [blame] | 246 | ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id"; |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 247 | |
| 248 | // Test that Wait() with SecondsToWait=0 performs a non-blocking wait. In this |
| 249 | // cse, LoopCount should be greater than 1 (more than one increment occurs). |
| 250 | while (true) { |
| 251 | ++LoopCount; |
Zachary Turner | 07670b3 | 2016-06-29 21:48:26 +0000 | [diff] [blame] | 252 | ProcessInfo WaitResult = llvm::sys::Wait(PI2, 0, false, &Error); |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 253 | ASSERT_TRUE(Error.empty()); |
| 254 | if (WaitResult.Pid == PI2.Pid) |
| 255 | break; |
| 256 | } |
| 257 | |
| 258 | ASSERT_GT(LoopCount, 1u) << "LoopCount should be >1"; |
| 259 | } |
| 260 | |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 261 | TEST_F(ProgramEnvTest, TestExecuteAndWaitTimeout) { |
Peter Collingbourne | ec1aaca | 2014-05-31 01:36:02 +0000 | [diff] [blame] | 262 | using namespace llvm::sys; |
| 263 | |
| 264 | if (getenv("LLVM_PROGRAM_TEST_TIMEOUT")) { |
| 265 | sleep_for(/*seconds*/ 10); |
| 266 | exit(0); |
| 267 | } |
| 268 | |
| 269 | std::string Executable = |
| 270 | sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1); |
| 271 | const char *argv[] = { |
| 272 | Executable.c_str(), |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 273 | "--gtest_filter=ProgramEnvTest.TestExecuteAndWaitTimeout", |
Craig Topper | 66f09ad | 2014-06-08 22:29:17 +0000 | [diff] [blame] | 274 | nullptr |
Peter Collingbourne | ec1aaca | 2014-05-31 01:36:02 +0000 | [diff] [blame] | 275 | }; |
| 276 | |
| 277 | // Add LLVM_PROGRAM_TEST_TIMEOUT to the environment of the child. |
Pawel Bylica | 85ca294 | 2015-11-04 08:25:20 +0000 | [diff] [blame] | 278 | addEnvVar("LLVM_PROGRAM_TEST_TIMEOUT=1"); |
Peter Collingbourne | ec1aaca | 2014-05-31 01:36:02 +0000 | [diff] [blame] | 279 | |
| 280 | std::string Error; |
| 281 | bool ExecutionFailed; |
| 282 | int RetCode = |
Alexander Kornienko | 208eecd | 2017-09-13 17:03:37 +0000 | [diff] [blame] | 283 | ExecuteAndWait(Executable, argv, getEnviron(), {}, /*secondsToWait=*/1, 0, |
Peter Collingbourne | ec1aaca | 2014-05-31 01:36:02 +0000 | [diff] [blame] | 284 | &Error, &ExecutionFailed); |
| 285 | ASSERT_EQ(-2, RetCode); |
| 286 | } |
| 287 | |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 288 | TEST(ProgramTest, TestExecuteNegative) { |
| 289 | std::string Executable = "i_dont_exist"; |
Craig Topper | 66f09ad | 2014-06-08 22:29:17 +0000 | [diff] [blame] | 290 | const char *argv[] = { Executable.c_str(), nullptr }; |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 291 | |
| 292 | { |
| 293 | std::string Error; |
| 294 | bool ExecutionFailed; |
Alexander Kornienko | 208eecd | 2017-09-13 17:03:37 +0000 | [diff] [blame] | 295 | int RetCode = ExecuteAndWait(Executable, argv, nullptr, {}, 0, 0, &Error, |
| 296 | &ExecutionFailed); |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 297 | ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or " |
| 298 | "positive value indicating the result code"; |
| 299 | ASSERT_TRUE(ExecutionFailed); |
| 300 | ASSERT_FALSE(Error.empty()); |
| 301 | } |
| 302 | |
| 303 | { |
| 304 | std::string Error; |
| 305 | bool ExecutionFailed; |
Alexander Kornienko | 208eecd | 2017-09-13 17:03:37 +0000 | [diff] [blame] | 306 | ProcessInfo PI = ExecuteNoWait(Executable, argv, nullptr, {}, 0, &Error, |
| 307 | &ExecutionFailed); |
Reid Kleckner | c2e2311 | 2016-02-03 21:41:12 +0000 | [diff] [blame] | 308 | ASSERT_EQ(PI.Pid, ProcessInfo::InvalidPid) |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 309 | << "On error ExecuteNoWait should return an invalid ProcessInfo"; |
| 310 | ASSERT_TRUE(ExecutionFailed); |
| 311 | ASSERT_FALSE(Error.empty()); |
| 312 | } |
Duncan P. N. Exon Smith | 91d3cfe | 2016-04-05 20:45:04 +0000 | [diff] [blame] | 313 | |
Tareq A. Siraj | d88b983 | 2013-10-01 14:28:18 +0000 | [diff] [blame] | 314 | } |
| 315 | |
Nico Weber | 712e8d2 | 2018-04-29 00:45:03 +0000 | [diff] [blame] | 316 | #ifdef _WIN32 |
Rafael Espindola | 9c35966 | 2014-09-03 20:02:00 +0000 | [diff] [blame] | 317 | const char utf16le_text[] = |
| 318 | "\x6c\x00\x69\x00\x6e\x00\x67\x00\xfc\x00\x69\x00\xe7\x00\x61\x00"; |
| 319 | const char utf16be_text[] = |
| 320 | "\x00\x6c\x00\x69\x00\x6e\x00\x67\x00\xfc\x00\x69\x00\xe7\x00\x61"; |
| 321 | #endif |
| 322 | const char utf8_text[] = "\x6c\x69\x6e\x67\xc3\xbc\x69\xc3\xa7\x61"; |
| 323 | |
| 324 | TEST(ProgramTest, TestWriteWithSystemEncoding) { |
| 325 | SmallString<128> TestDirectory; |
| 326 | ASSERT_NO_ERROR(fs::createUniqueDirectory("program-test", TestDirectory)); |
| 327 | errs() << "Test Directory: " << TestDirectory << '\n'; |
| 328 | errs().flush(); |
| 329 | SmallString<128> file_pathname(TestDirectory); |
| 330 | path::append(file_pathname, "international-file.txt"); |
| 331 | // Only on Windows we should encode in UTF16. For other systems, use UTF8 |
| 332 | ASSERT_NO_ERROR(sys::writeFileWithEncoding(file_pathname.c_str(), utf8_text, |
| 333 | sys::WEM_UTF16)); |
| 334 | int fd = 0; |
| 335 | ASSERT_NO_ERROR(fs::openFileForRead(file_pathname.c_str(), fd)); |
Nico Weber | 712e8d2 | 2018-04-29 00:45:03 +0000 | [diff] [blame] | 336 | #if defined(_WIN32) |
Rafael Espindola | 9c35966 | 2014-09-03 20:02:00 +0000 | [diff] [blame] | 337 | char buf[18]; |
| 338 | ASSERT_EQ(::read(fd, buf, 18), 18); |
| 339 | if (strncmp(buf, "\xfe\xff", 2) == 0) { // UTF16-BE |
| 340 | ASSERT_EQ(strncmp(&buf[2], utf16be_text, 16), 0); |
| 341 | } else if (strncmp(buf, "\xff\xfe", 2) == 0) { // UTF16-LE |
| 342 | ASSERT_EQ(strncmp(&buf[2], utf16le_text, 16), 0); |
| 343 | } else { |
| 344 | FAIL() << "Invalid BOM in UTF-16 file"; |
| 345 | } |
| 346 | #else |
| 347 | char buf[10]; |
| 348 | ASSERT_EQ(::read(fd, buf, 10), 10); |
| 349 | ASSERT_EQ(strncmp(buf, utf8_text, 10), 0); |
| 350 | #endif |
| 351 | ::close(fd); |
| 352 | ASSERT_NO_ERROR(fs::remove(file_pathname.str())); |
| 353 | ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); |
| 354 | } |
| 355 | |
Reid Kleckner | 74679a9 | 2013-04-22 19:03:55 +0000 | [diff] [blame] | 356 | } // end anonymous namespace |