174679a93SReid Kleckner //===- unittest/Support/ProgramTest.cpp -----------------------------------===//
274679a93SReid Kleckner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
674679a93SReid Kleckner //
774679a93SReid Kleckner //===----------------------------------------------------------------------===//
874679a93SReid Kleckner 
99a67b073SChandler Carruth #include "llvm/Support/Program.h"
10432a3883SNico Weber #include "llvm/Config/llvm-config.h"
1174679a93SReid Kleckner #include "llvm/Support/CommandLine.h"
129a67b073SChandler Carruth #include "llvm/Support/ConvertUTF.h"
13e03dfd9bSRafael Espindola #include "llvm/Support/FileSystem.h"
1474679a93SReid Kleckner #include "llvm/Support/Path.h"
153df88ec3SAndy Yankovsky #include "llvm/Support/Signals.h"
1674679a93SReid Kleckner #include "gtest/gtest.h"
1791d3cfedSDuncan P. N. Exon Smith #include <stdlib.h>
1853673699SSerge Pavlov #include <thread>
19206ddd07SReid Kleckner #if defined(__APPLE__)
20de0c2604SReid Kleckner # include <crt_externs.h>
21206ddd07SReid Kleckner #elif !defined(_MSC_VER)
22de0c2604SReid Kleckner // Forward declare environ in case it's not provided by stdlib.h.
23de0c2604SReid Kleckner extern char **environ;
24de0c2604SReid Kleckner #endif
2574679a93SReid Kleckner 
26d88b9832STareq A. Siraj #if defined(LLVM_ON_UNIX)
27d88b9832STareq A. Siraj #include <unistd.h>
sleep_for(unsigned int seconds)28d88b9832STareq A. Siraj void sleep_for(unsigned int seconds) {
29d88b9832STareq A. Siraj   sleep(seconds);
30d88b9832STareq A. Siraj }
31712e8d29SNico Weber #elif defined(_WIN32)
32d88b9832STareq A. Siraj #include <windows.h>
sleep_for(unsigned int seconds)33d88b9832STareq A. Siraj void sleep_for(unsigned int seconds) {
34d88b9832STareq A. Siraj   Sleep(seconds * 1000);
35d88b9832STareq A. Siraj }
36d88b9832STareq A. Siraj #else
37d88b9832STareq A. Siraj #error sleep_for is not implemented on your platform.
38d88b9832STareq A. Siraj #endif
39d88b9832STareq A. Siraj 
400d802a49SPavel Labath #define ASSERT_NO_ERROR(x)                                                     \
410d802a49SPavel Labath   if (std::error_code ASSERT_NO_ERROR_ec = x) {                                \
420d802a49SPavel Labath     SmallString<128> MessageStorage;                                           \
430d802a49SPavel Labath     raw_svector_ostream Message(MessageStorage);                               \
440d802a49SPavel Labath     Message << #x ": did not return errc::success.\n"                          \
450d802a49SPavel Labath             << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n"          \
460d802a49SPavel Labath             << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n";      \
470d802a49SPavel Labath     GTEST_FATAL_FAILURE_(MessageStorage.c_str());                              \
480d802a49SPavel Labath   } else {                                                                     \
490d802a49SPavel Labath   }
5095012aaaSReid Kleckner // From TestMain.cpp.
5195012aaaSReid Kleckner extern const char *TestMainArgv0;
5295012aaaSReid Kleckner 
5374679a93SReid Kleckner namespace {
5474679a93SReid Kleckner 
5574679a93SReid Kleckner using namespace llvm;
5674679a93SReid Kleckner using namespace sys;
5774679a93SReid Kleckner 
5891d3cfedSDuncan P. N. Exon Smith static cl::opt<std::string>
5974679a93SReid Kleckner ProgramTestStringArg1("program-test-string-arg1");
6091d3cfedSDuncan P. N. Exon Smith static cl::opt<std::string>
6174679a93SReid Kleckner ProgramTestStringArg2("program-test-string-arg2");
6274679a93SReid Kleckner 
6385ca2949SPawel Bylica class ProgramEnvTest : public testing::Test {
6408426e1fSZachary Turner   std::vector<StringRef> EnvTable;
6585ca2949SPawel Bylica   std::vector<std::string> EnvStorage;
6685ca2949SPawel Bylica 
6785ca2949SPawel Bylica protected:
SetUp()6885ca2949SPawel Bylica   void SetUp() override {
6985ca2949SPawel Bylica     auto EnvP = [] {
70712e8d29SNico Weber #if defined(_WIN32)
7185ca2949SPawel Bylica       _wgetenv(L"TMP"); // Populate _wenviron, initially is null
7285ca2949SPawel Bylica       return _wenviron;
7385ca2949SPawel Bylica #elif defined(__APPLE__)
7485ca2949SPawel Bylica       return *_NSGetEnviron();
75de0c2604SReid Kleckner #else
7685ca2949SPawel Bylica       return environ;
77de0c2604SReid Kleckner #endif
7885ca2949SPawel Bylica     }();
7985ca2949SPawel Bylica     ASSERT_TRUE(EnvP);
8085ca2949SPawel Bylica 
8108426e1fSZachary Turner     auto prepareEnvVar = [this](decltype(*EnvP) Var) -> StringRef {
82712e8d29SNico Weber #if defined(_WIN32)
8385ca2949SPawel Bylica       // On Windows convert UTF16 encoded variable to UTF8
8485ca2949SPawel Bylica       auto Len = wcslen(Var);
8585ca2949SPawel Bylica       ArrayRef<char> Ref{reinterpret_cast<char const *>(Var),
8685ca2949SPawel Bylica                          Len * sizeof(*Var)};
8785ca2949SPawel Bylica       EnvStorage.emplace_back();
8885ca2949SPawel Bylica       auto convStatus = convertUTF16ToUTF8String(Ref, EnvStorage.back());
8985ca2949SPawel Bylica       EXPECT_TRUE(convStatus);
9008426e1fSZachary Turner       return EnvStorage.back();
9185ca2949SPawel Bylica #else
9217d266bcSMalcolm Parsons       (void)this;
9308426e1fSZachary Turner       return StringRef(Var);
9485ca2949SPawel Bylica #endif
9585ca2949SPawel Bylica     };
9685ca2949SPawel Bylica 
9785ca2949SPawel Bylica     while (*EnvP != nullptr) {
98*cd0a5889SYuanfang Chen       auto S = prepareEnvVar(*EnvP);
99*cd0a5889SYuanfang Chen       if (!StringRef(S).startswith("GTEST_"))
100*cd0a5889SYuanfang Chen         EnvTable.emplace_back(S);
10185ca2949SPawel Bylica       ++EnvP;
102de0c2604SReid Kleckner     }
103de0c2604SReid Kleckner   }
104de0c2604SReid Kleckner 
TearDown()10585ca2949SPawel Bylica   void TearDown() override {
10685ca2949SPawel Bylica     EnvTable.clear();
10785ca2949SPawel Bylica     EnvStorage.clear();
10885ca2949SPawel Bylica   }
10985ca2949SPawel Bylica 
addEnvVar(StringRef Var)11008426e1fSZachary Turner   void addEnvVar(StringRef Var) { EnvTable.emplace_back(Var); }
11185ca2949SPawel Bylica 
getEnviron() const11208426e1fSZachary Turner   ArrayRef<StringRef> getEnviron() const { return EnvTable; }
11385ca2949SPawel Bylica };
11485ca2949SPawel Bylica 
115712e8d29SNico Weber #ifdef _WIN32
checkSeparators(StringRef Path)116f4d83c56SMartin Storsjö void checkSeparators(StringRef Path) {
117f4d83c56SMartin Storsjö   char UndesiredSeparator = sys::path::get_separator()[0] == '/' ? '\\' : '/';
118f4d83c56SMartin Storsjö   ASSERT_EQ(Path.find(UndesiredSeparator), StringRef::npos);
119f4d83c56SMartin Storsjö }
120f4d83c56SMartin Storsjö 
TEST_F(ProgramEnvTest,CreateProcessLongPath)12185ca2949SPawel Bylica TEST_F(ProgramEnvTest, CreateProcessLongPath) {
122c38deee8SPaul Robinson   if (getenv("LLVM_PROGRAM_TEST_LONG_PATH"))
123c38deee8SPaul Robinson     exit(0);
124c38deee8SPaul Robinson 
125c38deee8SPaul Robinson   // getMainExecutable returns an absolute path; prepend the long-path prefix.
126f4d83c56SMartin Storsjö   SmallString<128> MyAbsExe(
127f4d83c56SMartin Storsjö       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1));
128f4d83c56SMartin Storsjö   checkSeparators(MyAbsExe);
129f4d83c56SMartin Storsjö   // Force a path with backslashes, when we are going to prepend the \\?\
130f4d83c56SMartin Storsjö   // prefix.
131f4d83c56SMartin Storsjö   sys::path::native(MyAbsExe, sys::path::Style::windows_backslash);
132c38deee8SPaul Robinson   std::string MyExe;
133c38deee8SPaul Robinson   if (!StringRef(MyAbsExe).startswith("\\\\?\\"))
134c38deee8SPaul Robinson     MyExe.append("\\\\?\\");
135f4d83c56SMartin Storsjö   MyExe.append(std::string(MyAbsExe.begin(), MyAbsExe.end()));
136c38deee8SPaul Robinson 
13708426e1fSZachary Turner   StringRef ArgV[] = {MyExe,
13808426e1fSZachary Turner                       "--gtest_filter=ProgramEnvTest.CreateProcessLongPath"};
139c38deee8SPaul Robinson 
140c38deee8SPaul Robinson   // Add LLVM_PROGRAM_TEST_LONG_PATH to the environment of the child.
14185ca2949SPawel Bylica   addEnvVar("LLVM_PROGRAM_TEST_LONG_PATH=1");
142c38deee8SPaul Robinson 
143c38deee8SPaul Robinson   // Redirect stdout to a long path.
144c38deee8SPaul Robinson   SmallString<128> TestDirectory;
145c38deee8SPaul Robinson   ASSERT_NO_ERROR(
146c38deee8SPaul Robinson     fs::createUniqueDirectory("program-redirect-test", TestDirectory));
147c38deee8SPaul Robinson   SmallString<256> LongPath(TestDirectory);
148c38deee8SPaul Robinson   LongPath.push_back('\\');
149c38deee8SPaul Robinson   // MAX_PATH = 260
150c38deee8SPaul Robinson   LongPath.append(260 - TestDirectory.size(), 'a');
151c38deee8SPaul Robinson 
152c38deee8SPaul Robinson   std::string Error;
153c38deee8SPaul Robinson   bool ExecutionFailed;
154208eecd5SAlexander Kornienko   Optional<StringRef> Redirects[] = {None, LongPath.str(), None};
15585ca2949SPawel Bylica   int RC = ExecuteAndWait(MyExe, ArgV, getEnviron(), Redirects,
156c38deee8SPaul Robinson     /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error,
157c38deee8SPaul Robinson     &ExecutionFailed);
158c38deee8SPaul Robinson   EXPECT_FALSE(ExecutionFailed) << Error;
159c38deee8SPaul Robinson   EXPECT_EQ(0, RC);
160c38deee8SPaul Robinson 
161c38deee8SPaul Robinson   // Remove the long stdout.
162c38deee8SPaul Robinson   ASSERT_NO_ERROR(fs::remove(Twine(LongPath)));
163c38deee8SPaul Robinson   ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory)));
164c38deee8SPaul Robinson }
165c38deee8SPaul Robinson #endif
166c38deee8SPaul Robinson 
TEST_F(ProgramEnvTest,CreateProcessTrailingSlash)16785ca2949SPawel Bylica TEST_F(ProgramEnvTest, CreateProcessTrailingSlash) {
16874679a93SReid Kleckner   if (getenv("LLVM_PROGRAM_TEST_CHILD")) {
16974679a93SReid Kleckner     if (ProgramTestStringArg1 == "has\\\\ trailing\\" &&
17074679a93SReid Kleckner         ProgramTestStringArg2 == "has\\\\ trailing\\") {
17174679a93SReid Kleckner       exit(0);  // Success!  The arguments were passed and parsed.
17274679a93SReid Kleckner     }
17374679a93SReid Kleckner     exit(1);
17474679a93SReid Kleckner   }
17574679a93SReid Kleckner 
176e03dfd9bSRafael Espindola   std::string my_exe =
177e03dfd9bSRafael Espindola       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
17808426e1fSZachary Turner   StringRef argv[] = {
17908426e1fSZachary Turner       my_exe,
18085ca2949SPawel Bylica       "--gtest_filter=ProgramEnvTest.CreateProcessTrailingSlash",
18108426e1fSZachary Turner       "-program-test-string-arg1",
18208426e1fSZachary Turner       "has\\\\ trailing\\",
18308426e1fSZachary Turner       "-program-test-string-arg2",
18408426e1fSZachary Turner       "has\\\\ trailing\\"};
185de0c2604SReid Kleckner 
186de0c2604SReid Kleckner   // Add LLVM_PROGRAM_TEST_CHILD to the environment of the child.
18785ca2949SPawel Bylica   addEnvVar("LLVM_PROGRAM_TEST_CHILD=1");
188de0c2604SReid Kleckner 
18974679a93SReid Kleckner   std::string error;
19074679a93SReid Kleckner   bool ExecutionFailed;
19174679a93SReid Kleckner   // Redirect stdout and stdin to NUL, but let stderr through.
192712e8d29SNico Weber #ifdef _WIN32
1937c1023adSRafael Espindola   StringRef nul("NUL");
19474679a93SReid Kleckner #else
1957c1023adSRafael Espindola   StringRef nul("/dev/null");
19674679a93SReid Kleckner #endif
197208eecd5SAlexander Kornienko   Optional<StringRef> redirects[] = { nul, nul, None };
19885ca2949SPawel Bylica   int rc = ExecuteAndWait(my_exe, argv, getEnviron(), redirects,
1997c1023adSRafael Espindola                           /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error,
2007c1023adSRafael Espindola                           &ExecutionFailed);
20174679a93SReid Kleckner   EXPECT_FALSE(ExecutionFailed) << error;
20274679a93SReid Kleckner   EXPECT_EQ(0, rc);
20374679a93SReid Kleckner }
20474679a93SReid Kleckner 
TEST_F(ProgramEnvTest,TestExecuteNoWait)20585ca2949SPawel Bylica TEST_F(ProgramEnvTest, TestExecuteNoWait) {
206d88b9832STareq A. Siraj   using namespace llvm::sys;
207d88b9832STareq A. Siraj 
208d88b9832STareq A. Siraj   if (getenv("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT")) {
209d88b9832STareq A. Siraj     sleep_for(/*seconds*/ 1);
210d88b9832STareq A. Siraj     exit(0);
211d88b9832STareq A. Siraj   }
212d88b9832STareq A. Siraj 
213d88b9832STareq A. Siraj   std::string Executable =
214d88b9832STareq A. Siraj       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
21508426e1fSZachary Turner   StringRef argv[] = {Executable,
21608426e1fSZachary Turner                       "--gtest_filter=ProgramEnvTest.TestExecuteNoWait"};
217d88b9832STareq A. Siraj 
218d88b9832STareq A. Siraj   // Add LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT to the environment of the child.
21985ca2949SPawel Bylica   addEnvVar("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT=1");
220d88b9832STareq A. Siraj 
221d88b9832STareq A. Siraj   std::string Error;
222d88b9832STareq A. Siraj   bool ExecutionFailed;
223208eecd5SAlexander Kornienko   ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
224208eecd5SAlexander Kornienko                                   &ExecutionFailed);
225d88b9832STareq A. Siraj   ASSERT_FALSE(ExecutionFailed) << Error;
226c2e23116SReid Kleckner   ASSERT_NE(PI1.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
227d88b9832STareq A. Siraj 
228d88b9832STareq A. Siraj   unsigned LoopCount = 0;
229d88b9832STareq A. Siraj 
230d88b9832STareq A. Siraj   // Test that Wait() with WaitUntilTerminates=true works. In this case,
231d88b9832STareq A. Siraj   // LoopCount should only be incremented once.
232d88b9832STareq A. Siraj   while (true) {
233d88b9832STareq A. Siraj     ++LoopCount;
23407670b3eSZachary Turner     ProcessInfo WaitResult = llvm::sys::Wait(PI1, 0, true, &Error);
235d88b9832STareq A. Siraj     ASSERT_TRUE(Error.empty());
236d88b9832STareq A. Siraj     if (WaitResult.Pid == PI1.Pid)
237d88b9832STareq A. Siraj       break;
238d88b9832STareq A. Siraj   }
239d88b9832STareq A. Siraj 
240d88b9832STareq A. Siraj   EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1";
241d88b9832STareq A. Siraj 
242208eecd5SAlexander Kornienko   ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
243208eecd5SAlexander Kornienko                                   &ExecutionFailed);
244d88b9832STareq A. Siraj   ASSERT_FALSE(ExecutionFailed) << Error;
245c2e23116SReid Kleckner   ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
246d88b9832STareq A. Siraj 
247d88b9832STareq A. Siraj   // Test that Wait() with SecondsToWait=0 performs a non-blocking wait. In this
248d88b9832STareq A. Siraj   // cse, LoopCount should be greater than 1 (more than one increment occurs).
249d88b9832STareq A. Siraj   while (true) {
250d88b9832STareq A. Siraj     ++LoopCount;
25107670b3eSZachary Turner     ProcessInfo WaitResult = llvm::sys::Wait(PI2, 0, false, &Error);
252d88b9832STareq A. Siraj     ASSERT_TRUE(Error.empty());
253d88b9832STareq A. Siraj     if (WaitResult.Pid == PI2.Pid)
254d88b9832STareq A. Siraj       break;
255d88b9832STareq A. Siraj   }
256d88b9832STareq A. Siraj 
257d88b9832STareq A. Siraj   ASSERT_GT(LoopCount, 1u) << "LoopCount should be >1";
258d88b9832STareq A. Siraj }
259d88b9832STareq A. Siraj 
TEST_F(ProgramEnvTest,TestExecuteAndWaitTimeout)26085ca2949SPawel Bylica TEST_F(ProgramEnvTest, TestExecuteAndWaitTimeout) {
261ec1aacafSPeter Collingbourne   using namespace llvm::sys;
262ec1aacafSPeter Collingbourne 
263ec1aacafSPeter Collingbourne   if (getenv("LLVM_PROGRAM_TEST_TIMEOUT")) {
264ec1aacafSPeter Collingbourne     sleep_for(/*seconds*/ 10);
265ec1aacafSPeter Collingbourne     exit(0);
266ec1aacafSPeter Collingbourne   }
267ec1aacafSPeter Collingbourne 
268ec1aacafSPeter Collingbourne   std::string Executable =
269ec1aacafSPeter Collingbourne       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
27008426e1fSZachary Turner   StringRef argv[] = {
27108426e1fSZachary Turner       Executable, "--gtest_filter=ProgramEnvTest.TestExecuteAndWaitTimeout"};
272ec1aacafSPeter Collingbourne 
273ec1aacafSPeter Collingbourne   // Add LLVM_PROGRAM_TEST_TIMEOUT to the environment of the child.
27485ca2949SPawel Bylica  addEnvVar("LLVM_PROGRAM_TEST_TIMEOUT=1");
275ec1aacafSPeter Collingbourne 
276ec1aacafSPeter Collingbourne   std::string Error;
277ec1aacafSPeter Collingbourne   bool ExecutionFailed;
278ec1aacafSPeter Collingbourne   int RetCode =
279208eecd5SAlexander Kornienko       ExecuteAndWait(Executable, argv, getEnviron(), {}, /*secondsToWait=*/1, 0,
280ec1aacafSPeter Collingbourne                      &Error, &ExecutionFailed);
281ec1aacafSPeter Collingbourne   ASSERT_EQ(-2, RetCode);
282ec1aacafSPeter Collingbourne }
283ec1aacafSPeter Collingbourne 
TEST(ProgramTest,TestExecuteNegative)284d88b9832STareq A. Siraj TEST(ProgramTest, TestExecuteNegative) {
285d88b9832STareq A. Siraj   std::string Executable = "i_dont_exist";
28608426e1fSZachary Turner   StringRef argv[] = {Executable};
287d88b9832STareq A. Siraj 
288d88b9832STareq A. Siraj   {
289d88b9832STareq A. Siraj     std::string Error;
290d88b9832STareq A. Siraj     bool ExecutionFailed;
29108426e1fSZachary Turner     int RetCode = ExecuteAndWait(Executable, argv, llvm::None, {}, 0, 0, &Error,
292208eecd5SAlexander Kornienko                                  &ExecutionFailed);
29338ac4093SArchibald Elliott     ASSERT_LT(RetCode, 0) << "On error ExecuteAndWait should return 0 or "
294d88b9832STareq A. Siraj                              "positive value indicating the result code";
295d88b9832STareq A. Siraj     ASSERT_TRUE(ExecutionFailed);
296d88b9832STareq A. Siraj     ASSERT_FALSE(Error.empty());
297d88b9832STareq A. Siraj   }
298d88b9832STareq A. Siraj 
299d88b9832STareq A. Siraj   {
300d88b9832STareq A. Siraj     std::string Error;
301d88b9832STareq A. Siraj     bool ExecutionFailed;
30208426e1fSZachary Turner     ProcessInfo PI = ExecuteNoWait(Executable, argv, llvm::None, {}, 0, &Error,
303208eecd5SAlexander Kornienko                                    &ExecutionFailed);
304c2e23116SReid Kleckner     ASSERT_EQ(PI.Pid, ProcessInfo::InvalidPid)
305d88b9832STareq A. Siraj         << "On error ExecuteNoWait should return an invalid ProcessInfo";
306d88b9832STareq A. Siraj     ASSERT_TRUE(ExecutionFailed);
307d88b9832STareq A. Siraj     ASSERT_FALSE(Error.empty());
308d88b9832STareq A. Siraj   }
30991d3cfedSDuncan P. N. Exon Smith 
310d88b9832STareq A. Siraj }
311d88b9832STareq A. Siraj 
312712e8d29SNico Weber #ifdef _WIN32
3139c359669SRafael Espindola const char utf16le_text[] =
3149c359669SRafael Espindola     "\x6c\x00\x69\x00\x6e\x00\x67\x00\xfc\x00\x69\x00\xe7\x00\x61\x00";
3159c359669SRafael Espindola const char utf16be_text[] =
3169c359669SRafael Espindola     "\x00\x6c\x00\x69\x00\x6e\x00\x67\x00\xfc\x00\x69\x00\xe7\x00\x61";
3179c359669SRafael Espindola #endif
3189c359669SRafael Espindola const char utf8_text[] = "\x6c\x69\x6e\x67\xc3\xbc\x69\xc3\xa7\x61";
3199c359669SRafael Espindola 
TEST(ProgramTest,TestWriteWithSystemEncoding)3209c359669SRafael Espindola TEST(ProgramTest, TestWriteWithSystemEncoding) {
3219c359669SRafael Espindola   SmallString<128> TestDirectory;
3229c359669SRafael Espindola   ASSERT_NO_ERROR(fs::createUniqueDirectory("program-test", TestDirectory));
3239c359669SRafael Espindola   errs() << "Test Directory: " << TestDirectory << '\n';
3249c359669SRafael Espindola   errs().flush();
3259c359669SRafael Espindola   SmallString<128> file_pathname(TestDirectory);
3269c359669SRafael Espindola   path::append(file_pathname, "international-file.txt");
3279c359669SRafael Espindola   // Only on Windows we should encode in UTF16. For other systems, use UTF8
3289c359669SRafael Espindola   ASSERT_NO_ERROR(sys::writeFileWithEncoding(file_pathname.c_str(), utf8_text,
3299c359669SRafael Espindola                                              sys::WEM_UTF16));
3309c359669SRafael Espindola   int fd = 0;
3319c359669SRafael Espindola   ASSERT_NO_ERROR(fs::openFileForRead(file_pathname.c_str(), fd));
332712e8d29SNico Weber #if defined(_WIN32)
3339c359669SRafael Espindola   char buf[18];
3349c359669SRafael Espindola   ASSERT_EQ(::read(fd, buf, 18), 18);
335b7578f9dSPaul Robinson   const char *utf16_text;
3369c359669SRafael Espindola   if (strncmp(buf, "\xfe\xff", 2) == 0) { // UTF16-BE
337b7578f9dSPaul Robinson     utf16_text = utf16be_text;
3389c359669SRafael Espindola   } else if (strncmp(buf, "\xff\xfe", 2) == 0) { // UTF16-LE
339b7578f9dSPaul Robinson     utf16_text = utf16le_text;
3409c359669SRafael Espindola   } else {
3419c359669SRafael Espindola     FAIL() << "Invalid BOM in UTF-16 file";
3429c359669SRafael Espindola   }
343b7578f9dSPaul Robinson   ASSERT_EQ(strncmp(&buf[2], utf16_text, 16), 0);
3449c359669SRafael Espindola #else
3459c359669SRafael Espindola   char buf[10];
3469c359669SRafael Espindola   ASSERT_EQ(::read(fd, buf, 10), 10);
3479c359669SRafael Espindola   ASSERT_EQ(strncmp(buf, utf8_text, 10), 0);
3489c359669SRafael Espindola #endif
3499c359669SRafael Espindola   ::close(fd);
3509c359669SRafael Espindola   ASSERT_NO_ERROR(fs::remove(file_pathname.str()));
3519c359669SRafael Espindola   ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
3529c359669SRafael Espindola }
3539c359669SRafael Espindola 
TEST_F(ProgramEnvTest,TestExecuteAndWaitStatistics)3542e613d2dSSerge Pavlov TEST_F(ProgramEnvTest, TestExecuteAndWaitStatistics) {
3552e613d2dSSerge Pavlov   using namespace llvm::sys;
3562e613d2dSSerge Pavlov 
3572e613d2dSSerge Pavlov   if (getenv("LLVM_PROGRAM_TEST_STATISTICS"))
3582e613d2dSSerge Pavlov     exit(0);
3592e613d2dSSerge Pavlov 
3602e613d2dSSerge Pavlov   std::string Executable =
3612e613d2dSSerge Pavlov       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
3622e613d2dSSerge Pavlov   StringRef argv[] = {
3632e613d2dSSerge Pavlov       Executable, "--gtest_filter=ProgramEnvTest.TestExecuteAndWaitStatistics"};
3642e613d2dSSerge Pavlov 
3652e613d2dSSerge Pavlov   // Add LLVM_PROGRAM_TEST_STATISTICS to the environment of the child.
3662e613d2dSSerge Pavlov   addEnvVar("LLVM_PROGRAM_TEST_STATISTICS=1");
3672e613d2dSSerge Pavlov 
3682e613d2dSSerge Pavlov   std::string Error;
3692e613d2dSSerge Pavlov   bool ExecutionFailed;
3702e613d2dSSerge Pavlov   Optional<ProcessStatistics> ProcStat;
3712e613d2dSSerge Pavlov   int RetCode = ExecuteAndWait(Executable, argv, getEnviron(), {}, 0, 0, &Error,
3722e613d2dSSerge Pavlov                                &ExecutionFailed, &ProcStat);
3732e613d2dSSerge Pavlov   ASSERT_EQ(0, RetCode);
3742e613d2dSSerge Pavlov   ASSERT_TRUE(ProcStat);
3752e613d2dSSerge Pavlov   ASSERT_GE(ProcStat->UserTime, std::chrono::microseconds(0));
3762e613d2dSSerge Pavlov   ASSERT_GE(ProcStat->TotalTime, ProcStat->UserTime);
3772e613d2dSSerge Pavlov }
3782e613d2dSSerge Pavlov 
TEST_F(ProgramEnvTest,TestLockFile)37953673699SSerge Pavlov TEST_F(ProgramEnvTest, TestLockFile) {
38053673699SSerge Pavlov   using namespace llvm::sys;
38153673699SSerge Pavlov 
38253673699SSerge Pavlov   if (const char *LockedFile = getenv("LLVM_PROGRAM_TEST_LOCKED_FILE")) {
38353673699SSerge Pavlov     // Child process.
38453673699SSerge Pavlov     int FD2;
38553673699SSerge Pavlov     ASSERT_NO_ERROR(fs::openFileForReadWrite(LockedFile, FD2,
38653673699SSerge Pavlov                                              fs::CD_OpenExisting, fs::OF_None));
38753673699SSerge Pavlov 
38853673699SSerge Pavlov     std::error_code ErrC = fs::tryLockFile(FD2, std::chrono::seconds(5));
38953673699SSerge Pavlov     ASSERT_NO_ERROR(ErrC);
39053673699SSerge Pavlov     ASSERT_NO_ERROR(fs::unlockFile(FD2));
39153673699SSerge Pavlov     close(FD2);
39253673699SSerge Pavlov     exit(0);
39353673699SSerge Pavlov   }
39453673699SSerge Pavlov 
39553673699SSerge Pavlov   // Create file that will be locked.
39653673699SSerge Pavlov   SmallString<64> LockedFile;
39753673699SSerge Pavlov   int FD1;
39853673699SSerge Pavlov   ASSERT_NO_ERROR(
39953673699SSerge Pavlov       fs::createTemporaryFile("TestLockFile", "temp", FD1, LockedFile));
40053673699SSerge Pavlov 
40153673699SSerge Pavlov   std::string Executable =
40253673699SSerge Pavlov       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
40353673699SSerge Pavlov   StringRef argv[] = {Executable, "--gtest_filter=ProgramEnvTest.TestLockFile"};
40453673699SSerge Pavlov 
40553673699SSerge Pavlov   // Add LLVM_PROGRAM_TEST_LOCKED_FILE to the environment of the child.
40653673699SSerge Pavlov   std::string EnvVar = "LLVM_PROGRAM_TEST_LOCKED_FILE=";
40753673699SSerge Pavlov   EnvVar += LockedFile.str();
40853673699SSerge Pavlov   addEnvVar(EnvVar);
40953673699SSerge Pavlov 
41053673699SSerge Pavlov   // Lock the file.
41153673699SSerge Pavlov   ASSERT_NO_ERROR(fs::tryLockFile(FD1));
41253673699SSerge Pavlov 
41353673699SSerge Pavlov   std::string Error;
41453673699SSerge Pavlov   bool ExecutionFailed;
41553673699SSerge Pavlov   ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
41653673699SSerge Pavlov                                   &ExecutionFailed);
41753673699SSerge Pavlov   ASSERT_FALSE(ExecutionFailed) << Error;
41853673699SSerge Pavlov   ASSERT_TRUE(Error.empty());
41953673699SSerge Pavlov   ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
42053673699SSerge Pavlov 
42153673699SSerge Pavlov   // Wait some time to give the child process a chance to start.
42253673699SSerge Pavlov   std::this_thread::sleep_for(std::chrono::milliseconds(100));
42353673699SSerge Pavlov 
42453673699SSerge Pavlov   ASSERT_NO_ERROR(fs::unlockFile(FD1));
42553673699SSerge Pavlov   ProcessInfo WaitResult = llvm::sys::Wait(PI2, 5 /* seconds */, true, &Error);
42653673699SSerge Pavlov   ASSERT_TRUE(Error.empty());
42753673699SSerge Pavlov   ASSERT_EQ(0, WaitResult.ReturnCode);
42853673699SSerge Pavlov   ASSERT_EQ(WaitResult.Pid, PI2.Pid);
42953673699SSerge Pavlov   sys::fs::remove(LockedFile);
43053673699SSerge Pavlov }
43153673699SSerge Pavlov 
TEST_F(ProgramEnvTest,TestExecuteWithNoStacktraceHandler)4323df88ec3SAndy Yankovsky TEST_F(ProgramEnvTest, TestExecuteWithNoStacktraceHandler) {
4333df88ec3SAndy Yankovsky   using namespace llvm::sys;
4343df88ec3SAndy Yankovsky 
4353df88ec3SAndy Yankovsky   if (getenv("LLVM_PROGRAM_TEST_NO_STACKTRACE_HANDLER")) {
4363df88ec3SAndy Yankovsky     sys::PrintStackTrace(errs());
4373df88ec3SAndy Yankovsky     exit(0);
4383df88ec3SAndy Yankovsky   }
4393df88ec3SAndy Yankovsky 
4403df88ec3SAndy Yankovsky   std::string Executable =
4413df88ec3SAndy Yankovsky       sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
4423df88ec3SAndy Yankovsky   StringRef argv[] = {
4433df88ec3SAndy Yankovsky       Executable,
4443df88ec3SAndy Yankovsky       "--gtest_filter=ProgramEnvTest.TestExecuteWithNoStacktraceHandler"};
4453df88ec3SAndy Yankovsky 
4463df88ec3SAndy Yankovsky   addEnvVar("LLVM_PROGRAM_TEST_NO_STACKTRACE_HANDLER=1");
4473df88ec3SAndy Yankovsky 
4483df88ec3SAndy Yankovsky   std::string Error;
4493df88ec3SAndy Yankovsky   bool ExecutionFailed;
4503df88ec3SAndy Yankovsky   int RetCode = ExecuteAndWait(Executable, argv, getEnviron(), {}, 0, 0, &Error,
4513df88ec3SAndy Yankovsky                                &ExecutionFailed);
4523df88ec3SAndy Yankovsky   EXPECT_FALSE(ExecutionFailed) << Error;
4533df88ec3SAndy Yankovsky   ASSERT_EQ(0, RetCode);
4543df88ec3SAndy Yankovsky }
4553df88ec3SAndy Yankovsky 
45674679a93SReid Kleckner } // end anonymous namespace
457