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