2013-04-23 03:03:55 +08:00
|
|
|
//===- unittest/Support/ProgramTest.cpp -----------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2013-04-23 03:03:55 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-06 19:06:56 +08:00
|
|
|
#include "llvm/Support/Program.h"
|
2018-04-30 22:59:11 +08:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
2013-04-23 03:03:55 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2017-06-06 19:06:56 +08:00
|
|
|
#include "llvm/Support/ConvertUTF.h"
|
2013-06-26 13:01:35 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2013-04-23 03:03:55 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2022-02-08 04:37:38 +08:00
|
|
|
#include "llvm/Support/Signals.h"
|
2013-04-23 03:03:55 +08:00
|
|
|
#include "gtest/gtest.h"
|
2016-04-06 04:45:04 +08:00
|
|
|
#include <stdlib.h>
|
2020-04-23 00:00:12 +08:00
|
|
|
#include <thread>
|
2013-04-25 01:50:30 +08:00
|
|
|
#if defined(__APPLE__)
|
2013-04-23 21:15:51 +08:00
|
|
|
# include <crt_externs.h>
|
2013-04-25 01:50:30 +08:00
|
|
|
#elif !defined(_MSC_VER)
|
2013-04-23 21:15:51 +08:00
|
|
|
// Forward declare environ in case it's not provided by stdlib.h.
|
|
|
|
extern char **environ;
|
|
|
|
#endif
|
2013-04-23 03:03:55 +08:00
|
|
|
|
2013-10-01 22:28:18 +08:00
|
|
|
#if defined(LLVM_ON_UNIX)
|
|
|
|
#include <unistd.h>
|
|
|
|
void sleep_for(unsigned int seconds) {
|
|
|
|
sleep(seconds);
|
|
|
|
}
|
2018-04-29 08:45:03 +08:00
|
|
|
#elif defined(_WIN32)
|
2013-10-01 22:28:18 +08:00
|
|
|
#include <windows.h>
|
|
|
|
void sleep_for(unsigned int seconds) {
|
|
|
|
Sleep(seconds * 1000);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#error sleep_for is not implemented on your platform.
|
|
|
|
#endif
|
|
|
|
|
2019-08-14 21:59:04 +08:00
|
|
|
#define ASSERT_NO_ERROR(x) \
|
|
|
|
if (std::error_code ASSERT_NO_ERROR_ec = x) { \
|
|
|
|
SmallString<128> MessageStorage; \
|
|
|
|
raw_svector_ostream Message(MessageStorage); \
|
|
|
|
Message << #x ": did not return errc::success.\n" \
|
|
|
|
<< "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
|
|
|
|
<< "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
|
|
|
|
GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
|
|
|
|
} else { \
|
|
|
|
}
|
2013-04-30 12:30:41 +08:00
|
|
|
// From TestMain.cpp.
|
|
|
|
extern const char *TestMainArgv0;
|
|
|
|
|
2013-04-23 03:03:55 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace sys;
|
|
|
|
|
2016-04-06 04:45:04 +08:00
|
|
|
static cl::opt<std::string>
|
2013-04-23 03:03:55 +08:00
|
|
|
ProgramTestStringArg1("program-test-string-arg1");
|
2016-04-06 04:45:04 +08:00
|
|
|
static cl::opt<std::string>
|
2013-04-23 03:03:55 +08:00
|
|
|
ProgramTestStringArg2("program-test-string-arg2");
|
|
|
|
|
2015-11-04 16:25:20 +08:00
|
|
|
class ProgramEnvTest : public testing::Test {
|
2018-06-13 01:43:52 +08:00
|
|
|
std::vector<StringRef> EnvTable;
|
2015-11-04 16:25:20 +08:00
|
|
|
std::vector<std::string> EnvStorage;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void SetUp() override {
|
|
|
|
auto EnvP = [] {
|
2018-04-29 08:45:03 +08:00
|
|
|
#if defined(_WIN32)
|
2015-11-04 16:25:20 +08:00
|
|
|
_wgetenv(L"TMP"); // Populate _wenviron, initially is null
|
|
|
|
return _wenviron;
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
return *_NSGetEnviron();
|
2013-04-23 21:15:51 +08:00
|
|
|
#else
|
2015-11-04 16:25:20 +08:00
|
|
|
return environ;
|
2013-04-23 21:15:51 +08:00
|
|
|
#endif
|
2015-11-04 16:25:20 +08:00
|
|
|
}();
|
|
|
|
ASSERT_TRUE(EnvP);
|
|
|
|
|
2018-06-13 01:43:52 +08:00
|
|
|
auto prepareEnvVar = [this](decltype(*EnvP) Var) -> StringRef {
|
2018-04-29 08:45:03 +08:00
|
|
|
#if defined(_WIN32)
|
2015-11-04 16:25:20 +08:00
|
|
|
// On Windows convert UTF16 encoded variable to UTF8
|
|
|
|
auto Len = wcslen(Var);
|
|
|
|
ArrayRef<char> Ref{reinterpret_cast<char const *>(Var),
|
|
|
|
Len * sizeof(*Var)};
|
|
|
|
EnvStorage.emplace_back();
|
|
|
|
auto convStatus = convertUTF16ToUTF8String(Ref, EnvStorage.back());
|
|
|
|
EXPECT_TRUE(convStatus);
|
2018-06-13 01:43:52 +08:00
|
|
|
return EnvStorage.back();
|
2015-11-04 16:25:20 +08:00
|
|
|
#else
|
2017-01-14 01:12:16 +08:00
|
|
|
(void)this;
|
2018-06-13 01:43:52 +08:00
|
|
|
return StringRef(Var);
|
2015-11-04 16:25:20 +08:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
while (*EnvP != nullptr) {
|
[Reland][lit] Use sharding for GoogleTest format
This helps lit unit test performance by a lot, especially on windows. The performance gain comes from launching one gtest executable for many subtests instead of one (this is the current situation).
The shards are executed by the test runner and the results are stored in the
json format supported by the GoogleTest. Later in the test reporting stage,
all test results in the json file are retrieved to continue the test results
summary etc.
On my Win10 desktop, before this patch: `check-clang-unit`: 177s, `check-llvm-unit`: 38s; after this patch: `check-clang-unit`: 37s, `check-llvm-unit`: 11s.
On my Linux machine, before this patch: `check-clang-unit`: 46s, `check-llvm-unit`: 8s; after this patch: `check-clang-unit`: 7s, `check-llvm-unit`: 4s.
Reviewed By: yln, rnk, abrachet
Differential Revision: https://reviews.llvm.org/D122251
2022-04-13 03:09:34 +08:00
|
|
|
auto S = prepareEnvVar(*EnvP);
|
|
|
|
if (!StringRef(S).startswith("GTEST_"))
|
|
|
|
EnvTable.emplace_back(S);
|
2015-11-04 16:25:20 +08:00
|
|
|
++EnvP;
|
|
|
|
}
|
2013-04-23 21:15:51 +08:00
|
|
|
}
|
2015-11-04 16:25:20 +08:00
|
|
|
|
|
|
|
void TearDown() override {
|
|
|
|
EnvTable.clear();
|
|
|
|
EnvStorage.clear();
|
|
|
|
}
|
|
|
|
|
2018-06-13 01:43:52 +08:00
|
|
|
void addEnvVar(StringRef Var) { EnvTable.emplace_back(Var); }
|
2015-11-04 16:25:20 +08:00
|
|
|
|
2018-06-13 01:43:52 +08:00
|
|
|
ArrayRef<StringRef> getEnviron() const { return EnvTable; }
|
2015-11-04 16:25:20 +08:00
|
|
|
};
|
2013-04-23 21:15:51 +08:00
|
|
|
|
2018-04-29 08:45:03 +08:00
|
|
|
#ifdef _WIN32
|
2021-10-05 18:17:36 +08:00
|
|
|
void checkSeparators(StringRef Path) {
|
|
|
|
char UndesiredSeparator = sys::path::get_separator()[0] == '/' ? '\\' : '/';
|
|
|
|
ASSERT_EQ(Path.find(UndesiredSeparator), StringRef::npos);
|
|
|
|
}
|
|
|
|
|
2015-11-04 16:25:20 +08:00
|
|
|
TEST_F(ProgramEnvTest, CreateProcessLongPath) {
|
2014-11-25 02:05:29 +08:00
|
|
|
if (getenv("LLVM_PROGRAM_TEST_LONG_PATH"))
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
// getMainExecutable returns an absolute path; prepend the long-path prefix.
|
2021-10-05 18:17:36 +08:00
|
|
|
SmallString<128> MyAbsExe(
|
|
|
|
sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1));
|
|
|
|
checkSeparators(MyAbsExe);
|
|
|
|
// Force a path with backslashes, when we are going to prepend the \\?\
|
|
|
|
// prefix.
|
|
|
|
sys::path::native(MyAbsExe, sys::path::Style::windows_backslash);
|
2014-11-25 02:05:29 +08:00
|
|
|
std::string MyExe;
|
|
|
|
if (!StringRef(MyAbsExe).startswith("\\\\?\\"))
|
|
|
|
MyExe.append("\\\\?\\");
|
2021-10-05 18:17:36 +08:00
|
|
|
MyExe.append(std::string(MyAbsExe.begin(), MyAbsExe.end()));
|
2014-11-25 02:05:29 +08:00
|
|
|
|
2018-06-13 01:43:52 +08:00
|
|
|
StringRef ArgV[] = {MyExe,
|
|
|
|
"--gtest_filter=ProgramEnvTest.CreateProcessLongPath"};
|
2014-11-25 02:05:29 +08:00
|
|
|
|
|
|
|
// Add LLVM_PROGRAM_TEST_LONG_PATH to the environment of the child.
|
2015-11-04 16:25:20 +08:00
|
|
|
addEnvVar("LLVM_PROGRAM_TEST_LONG_PATH=1");
|
2014-11-25 02:05:29 +08:00
|
|
|
|
|
|
|
// Redirect stdout to a long path.
|
|
|
|
SmallString<128> TestDirectory;
|
|
|
|
ASSERT_NO_ERROR(
|
|
|
|
fs::createUniqueDirectory("program-redirect-test", TestDirectory));
|
|
|
|
SmallString<256> LongPath(TestDirectory);
|
|
|
|
LongPath.push_back('\\');
|
|
|
|
// MAX_PATH = 260
|
|
|
|
LongPath.append(260 - TestDirectory.size(), 'a');
|
|
|
|
|
|
|
|
std::string Error;
|
|
|
|
bool ExecutionFailed;
|
2017-09-14 01:03:37 +08:00
|
|
|
Optional<StringRef> Redirects[] = {None, LongPath.str(), None};
|
2015-11-04 16:25:20 +08:00
|
|
|
int RC = ExecuteAndWait(MyExe, ArgV, getEnviron(), Redirects,
|
2014-11-25 02:05:29 +08:00
|
|
|
/*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error,
|
|
|
|
&ExecutionFailed);
|
|
|
|
EXPECT_FALSE(ExecutionFailed) << Error;
|
|
|
|
EXPECT_EQ(0, RC);
|
|
|
|
|
|
|
|
// Remove the long stdout.
|
|
|
|
ASSERT_NO_ERROR(fs::remove(Twine(LongPath)));
|
|
|
|
ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory)));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-11-04 16:25:20 +08:00
|
|
|
TEST_F(ProgramEnvTest, CreateProcessTrailingSlash) {
|
2013-04-23 03:03:55 +08:00
|
|
|
if (getenv("LLVM_PROGRAM_TEST_CHILD")) {
|
|
|
|
if (ProgramTestStringArg1 == "has\\\\ trailing\\" &&
|
|
|
|
ProgramTestStringArg2 == "has\\\\ trailing\\") {
|
|
|
|
exit(0); // Success! The arguments were passed and parsed.
|
|
|
|
}
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2013-06-26 13:01:35 +08:00
|
|
|
std::string my_exe =
|
|
|
|
sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
|
2018-06-13 01:43:52 +08:00
|
|
|
StringRef argv[] = {
|
|
|
|
my_exe,
|
|
|
|
"--gtest_filter=ProgramEnvTest.CreateProcessTrailingSlash",
|
|
|
|
"-program-test-string-arg1",
|
|
|
|
"has\\\\ trailing\\",
|
|
|
|
"-program-test-string-arg2",
|
|
|
|
"has\\\\ trailing\\"};
|
2013-04-23 21:15:51 +08:00
|
|
|
|
|
|
|
// Add LLVM_PROGRAM_TEST_CHILD to the environment of the child.
|
2015-11-04 16:25:20 +08:00
|
|
|
addEnvVar("LLVM_PROGRAM_TEST_CHILD=1");
|
2013-04-23 21:15:51 +08:00
|
|
|
|
2013-04-23 03:03:55 +08:00
|
|
|
std::string error;
|
|
|
|
bool ExecutionFailed;
|
|
|
|
// Redirect stdout and stdin to NUL, but let stderr through.
|
2018-04-29 08:45:03 +08:00
|
|
|
#ifdef _WIN32
|
2013-06-14 04:25:38 +08:00
|
|
|
StringRef nul("NUL");
|
2013-04-23 03:03:55 +08:00
|
|
|
#else
|
2013-06-14 04:25:38 +08:00
|
|
|
StringRef nul("/dev/null");
|
2013-04-23 03:03:55 +08:00
|
|
|
#endif
|
2017-09-14 01:03:37 +08:00
|
|
|
Optional<StringRef> redirects[] = { nul, nul, None };
|
2015-11-04 16:25:20 +08:00
|
|
|
int rc = ExecuteAndWait(my_exe, argv, getEnviron(), redirects,
|
2013-06-14 04:25:38 +08:00
|
|
|
/*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error,
|
|
|
|
&ExecutionFailed);
|
2013-04-23 03:03:55 +08:00
|
|
|
EXPECT_FALSE(ExecutionFailed) << error;
|
|
|
|
EXPECT_EQ(0, rc);
|
|
|
|
}
|
|
|
|
|
2015-11-04 16:25:20 +08:00
|
|
|
TEST_F(ProgramEnvTest, TestExecuteNoWait) {
|
2013-10-01 22:28:18 +08:00
|
|
|
using namespace llvm::sys;
|
|
|
|
|
|
|
|
if (getenv("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT")) {
|
|
|
|
sleep_for(/*seconds*/ 1);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Executable =
|
|
|
|
sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
|
2018-06-13 01:43:52 +08:00
|
|
|
StringRef argv[] = {Executable,
|
|
|
|
"--gtest_filter=ProgramEnvTest.TestExecuteNoWait"};
|
2013-10-01 22:28:18 +08:00
|
|
|
|
|
|
|
// Add LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT to the environment of the child.
|
2015-11-04 16:25:20 +08:00
|
|
|
addEnvVar("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT=1");
|
2013-10-01 22:28:18 +08:00
|
|
|
|
|
|
|
std::string Error;
|
|
|
|
bool ExecutionFailed;
|
2017-09-14 01:03:37 +08:00
|
|
|
ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
|
|
|
|
&ExecutionFailed);
|
2013-10-01 22:28:18 +08:00
|
|
|
ASSERT_FALSE(ExecutionFailed) << Error;
|
2016-02-04 05:41:12 +08:00
|
|
|
ASSERT_NE(PI1.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
|
2013-10-01 22:28:18 +08:00
|
|
|
|
|
|
|
unsigned LoopCount = 0;
|
|
|
|
|
|
|
|
// Test that Wait() with WaitUntilTerminates=true works. In this case,
|
|
|
|
// LoopCount should only be incremented once.
|
|
|
|
while (true) {
|
|
|
|
++LoopCount;
|
2016-06-30 05:48:26 +08:00
|
|
|
ProcessInfo WaitResult = llvm::sys::Wait(PI1, 0, true, &Error);
|
2013-10-01 22:28:18 +08:00
|
|
|
ASSERT_TRUE(Error.empty());
|
|
|
|
if (WaitResult.Pid == PI1.Pid)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1";
|
|
|
|
|
2017-09-14 01:03:37 +08:00
|
|
|
ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
|
|
|
|
&ExecutionFailed);
|
2013-10-01 22:28:18 +08:00
|
|
|
ASSERT_FALSE(ExecutionFailed) << Error;
|
2016-02-04 05:41:12 +08:00
|
|
|
ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
|
2013-10-01 22:28:18 +08:00
|
|
|
|
|
|
|
// Test that Wait() with SecondsToWait=0 performs a non-blocking wait. In this
|
|
|
|
// cse, LoopCount should be greater than 1 (more than one increment occurs).
|
|
|
|
while (true) {
|
|
|
|
++LoopCount;
|
2016-06-30 05:48:26 +08:00
|
|
|
ProcessInfo WaitResult = llvm::sys::Wait(PI2, 0, false, &Error);
|
2013-10-01 22:28:18 +08:00
|
|
|
ASSERT_TRUE(Error.empty());
|
|
|
|
if (WaitResult.Pid == PI2.Pid)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT_GT(LoopCount, 1u) << "LoopCount should be >1";
|
|
|
|
}
|
|
|
|
|
2015-11-04 16:25:20 +08:00
|
|
|
TEST_F(ProgramEnvTest, TestExecuteAndWaitTimeout) {
|
2014-05-31 09:36:02 +08:00
|
|
|
using namespace llvm::sys;
|
|
|
|
|
|
|
|
if (getenv("LLVM_PROGRAM_TEST_TIMEOUT")) {
|
|
|
|
sleep_for(/*seconds*/ 10);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Executable =
|
|
|
|
sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
|
2018-06-13 01:43:52 +08:00
|
|
|
StringRef argv[] = {
|
|
|
|
Executable, "--gtest_filter=ProgramEnvTest.TestExecuteAndWaitTimeout"};
|
2014-05-31 09:36:02 +08:00
|
|
|
|
|
|
|
// Add LLVM_PROGRAM_TEST_TIMEOUT to the environment of the child.
|
2015-11-04 16:25:20 +08:00
|
|
|
addEnvVar("LLVM_PROGRAM_TEST_TIMEOUT=1");
|
2014-05-31 09:36:02 +08:00
|
|
|
|
|
|
|
std::string Error;
|
|
|
|
bool ExecutionFailed;
|
|
|
|
int RetCode =
|
2017-09-14 01:03:37 +08:00
|
|
|
ExecuteAndWait(Executable, argv, getEnviron(), {}, /*secondsToWait=*/1, 0,
|
2014-05-31 09:36:02 +08:00
|
|
|
&Error, &ExecutionFailed);
|
|
|
|
ASSERT_EQ(-2, RetCode);
|
|
|
|
}
|
|
|
|
|
2013-10-01 22:28:18 +08:00
|
|
|
TEST(ProgramTest, TestExecuteNegative) {
|
|
|
|
std::string Executable = "i_dont_exist";
|
2018-06-13 01:43:52 +08:00
|
|
|
StringRef argv[] = {Executable};
|
2013-10-01 22:28:18 +08:00
|
|
|
|
|
|
|
{
|
|
|
|
std::string Error;
|
|
|
|
bool ExecutionFailed;
|
2018-06-13 01:43:52 +08:00
|
|
|
int RetCode = ExecuteAndWait(Executable, argv, llvm::None, {}, 0, 0, &Error,
|
2017-09-14 01:03:37 +08:00
|
|
|
&ExecutionFailed);
|
2022-01-21 21:14:58 +08:00
|
|
|
ASSERT_LT(RetCode, 0) << "On error ExecuteAndWait should return 0 or "
|
|
|
|
"positive value indicating the result code";
|
2013-10-01 22:28:18 +08:00
|
|
|
ASSERT_TRUE(ExecutionFailed);
|
|
|
|
ASSERT_FALSE(Error.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::string Error;
|
|
|
|
bool ExecutionFailed;
|
2018-06-13 01:43:52 +08:00
|
|
|
ProcessInfo PI = ExecuteNoWait(Executable, argv, llvm::None, {}, 0, &Error,
|
2017-09-14 01:03:37 +08:00
|
|
|
&ExecutionFailed);
|
2016-02-04 05:41:12 +08:00
|
|
|
ASSERT_EQ(PI.Pid, ProcessInfo::InvalidPid)
|
2013-10-01 22:28:18 +08:00
|
|
|
<< "On error ExecuteNoWait should return an invalid ProcessInfo";
|
|
|
|
ASSERT_TRUE(ExecutionFailed);
|
|
|
|
ASSERT_FALSE(Error.empty());
|
|
|
|
}
|
2016-04-06 04:45:04 +08:00
|
|
|
|
2013-10-01 22:28:18 +08:00
|
|
|
}
|
|
|
|
|
2018-04-29 08:45:03 +08:00
|
|
|
#ifdef _WIN32
|
2014-09-04 04:02:00 +08:00
|
|
|
const char utf16le_text[] =
|
|
|
|
"\x6c\x00\x69\x00\x6e\x00\x67\x00\xfc\x00\x69\x00\xe7\x00\x61\x00";
|
|
|
|
const char utf16be_text[] =
|
|
|
|
"\x00\x6c\x00\x69\x00\x6e\x00\x67\x00\xfc\x00\x69\x00\xe7\x00\x61";
|
|
|
|
#endif
|
|
|
|
const char utf8_text[] = "\x6c\x69\x6e\x67\xc3\xbc\x69\xc3\xa7\x61";
|
|
|
|
|
|
|
|
TEST(ProgramTest, TestWriteWithSystemEncoding) {
|
|
|
|
SmallString<128> TestDirectory;
|
|
|
|
ASSERT_NO_ERROR(fs::createUniqueDirectory("program-test", TestDirectory));
|
|
|
|
errs() << "Test Directory: " << TestDirectory << '\n';
|
|
|
|
errs().flush();
|
|
|
|
SmallString<128> file_pathname(TestDirectory);
|
|
|
|
path::append(file_pathname, "international-file.txt");
|
|
|
|
// Only on Windows we should encode in UTF16. For other systems, use UTF8
|
|
|
|
ASSERT_NO_ERROR(sys::writeFileWithEncoding(file_pathname.c_str(), utf8_text,
|
|
|
|
sys::WEM_UTF16));
|
|
|
|
int fd = 0;
|
|
|
|
ASSERT_NO_ERROR(fs::openFileForRead(file_pathname.c_str(), fd));
|
2018-04-29 08:45:03 +08:00
|
|
|
#if defined(_WIN32)
|
2014-09-04 04:02:00 +08:00
|
|
|
char buf[18];
|
|
|
|
ASSERT_EQ(::read(fd, buf, 18), 18);
|
2021-04-09 23:03:44 +08:00
|
|
|
const char *utf16_text;
|
2014-09-04 04:02:00 +08:00
|
|
|
if (strncmp(buf, "\xfe\xff", 2) == 0) { // UTF16-BE
|
2021-04-09 23:03:44 +08:00
|
|
|
utf16_text = utf16be_text;
|
2014-09-04 04:02:00 +08:00
|
|
|
} else if (strncmp(buf, "\xff\xfe", 2) == 0) { // UTF16-LE
|
2021-04-09 23:03:44 +08:00
|
|
|
utf16_text = utf16le_text;
|
2014-09-04 04:02:00 +08:00
|
|
|
} else {
|
|
|
|
FAIL() << "Invalid BOM in UTF-16 file";
|
|
|
|
}
|
2021-04-09 23:03:44 +08:00
|
|
|
ASSERT_EQ(strncmp(&buf[2], utf16_text, 16), 0);
|
2014-09-04 04:02:00 +08:00
|
|
|
#else
|
|
|
|
char buf[10];
|
|
|
|
ASSERT_EQ(::read(fd, buf, 10), 10);
|
|
|
|
ASSERT_EQ(strncmp(buf, utf8_text, 10), 0);
|
|
|
|
#endif
|
|
|
|
::close(fd);
|
|
|
|
ASSERT_NO_ERROR(fs::remove(file_pathname.str()));
|
|
|
|
ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
|
|
|
|
}
|
|
|
|
|
2020-04-23 14:04:52 +08:00
|
|
|
TEST_F(ProgramEnvTest, TestExecuteAndWaitStatistics) {
|
|
|
|
using namespace llvm::sys;
|
|
|
|
|
|
|
|
if (getenv("LLVM_PROGRAM_TEST_STATISTICS"))
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
std::string Executable =
|
|
|
|
sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
|
|
|
|
StringRef argv[] = {
|
|
|
|
Executable, "--gtest_filter=ProgramEnvTest.TestExecuteAndWaitStatistics"};
|
|
|
|
|
|
|
|
// Add LLVM_PROGRAM_TEST_STATISTICS to the environment of the child.
|
|
|
|
addEnvVar("LLVM_PROGRAM_TEST_STATISTICS=1");
|
|
|
|
|
|
|
|
std::string Error;
|
|
|
|
bool ExecutionFailed;
|
|
|
|
Optional<ProcessStatistics> ProcStat;
|
|
|
|
int RetCode = ExecuteAndWait(Executable, argv, getEnviron(), {}, 0, 0, &Error,
|
|
|
|
&ExecutionFailed, &ProcStat);
|
|
|
|
ASSERT_EQ(0, RetCode);
|
|
|
|
ASSERT_TRUE(ProcStat);
|
|
|
|
ASSERT_GE(ProcStat->UserTime, std::chrono::microseconds(0));
|
|
|
|
ASSERT_GE(ProcStat->TotalTime, ProcStat->UserTime);
|
|
|
|
}
|
|
|
|
|
2020-04-23 00:00:12 +08:00
|
|
|
TEST_F(ProgramEnvTest, TestLockFile) {
|
|
|
|
using namespace llvm::sys;
|
|
|
|
|
|
|
|
if (const char *LockedFile = getenv("LLVM_PROGRAM_TEST_LOCKED_FILE")) {
|
|
|
|
// Child process.
|
|
|
|
int FD2;
|
|
|
|
ASSERT_NO_ERROR(fs::openFileForReadWrite(LockedFile, FD2,
|
|
|
|
fs::CD_OpenExisting, fs::OF_None));
|
|
|
|
|
|
|
|
std::error_code ErrC = fs::tryLockFile(FD2, std::chrono::seconds(5));
|
|
|
|
ASSERT_NO_ERROR(ErrC);
|
|
|
|
ASSERT_NO_ERROR(fs::unlockFile(FD2));
|
|
|
|
close(FD2);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create file that will be locked.
|
|
|
|
SmallString<64> LockedFile;
|
|
|
|
int FD1;
|
|
|
|
ASSERT_NO_ERROR(
|
|
|
|
fs::createTemporaryFile("TestLockFile", "temp", FD1, LockedFile));
|
|
|
|
|
|
|
|
std::string Executable =
|
|
|
|
sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
|
|
|
|
StringRef argv[] = {Executable, "--gtest_filter=ProgramEnvTest.TestLockFile"};
|
|
|
|
|
|
|
|
// Add LLVM_PROGRAM_TEST_LOCKED_FILE to the environment of the child.
|
|
|
|
std::string EnvVar = "LLVM_PROGRAM_TEST_LOCKED_FILE=";
|
|
|
|
EnvVar += LockedFile.str();
|
|
|
|
addEnvVar(EnvVar);
|
|
|
|
|
|
|
|
// Lock the file.
|
|
|
|
ASSERT_NO_ERROR(fs::tryLockFile(FD1));
|
|
|
|
|
|
|
|
std::string Error;
|
|
|
|
bool ExecutionFailed;
|
|
|
|
ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
|
|
|
|
&ExecutionFailed);
|
|
|
|
ASSERT_FALSE(ExecutionFailed) << Error;
|
|
|
|
ASSERT_TRUE(Error.empty());
|
|
|
|
ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
|
|
|
|
|
|
|
|
// Wait some time to give the child process a chance to start.
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
|
|
|
|
ASSERT_NO_ERROR(fs::unlockFile(FD1));
|
|
|
|
ProcessInfo WaitResult = llvm::sys::Wait(PI2, 5 /* seconds */, true, &Error);
|
|
|
|
ASSERT_TRUE(Error.empty());
|
|
|
|
ASSERT_EQ(0, WaitResult.ReturnCode);
|
|
|
|
ASSERT_EQ(WaitResult.Pid, PI2.Pid);
|
|
|
|
sys::fs::remove(LockedFile);
|
|
|
|
}
|
|
|
|
|
2022-02-08 04:37:38 +08:00
|
|
|
TEST_F(ProgramEnvTest, TestExecuteWithNoStacktraceHandler) {
|
|
|
|
using namespace llvm::sys;
|
|
|
|
|
|
|
|
if (getenv("LLVM_PROGRAM_TEST_NO_STACKTRACE_HANDLER")) {
|
|
|
|
sys::PrintStackTrace(errs());
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Executable =
|
|
|
|
sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
|
|
|
|
StringRef argv[] = {
|
|
|
|
Executable,
|
|
|
|
"--gtest_filter=ProgramEnvTest.TestExecuteWithNoStacktraceHandler"};
|
|
|
|
|
|
|
|
addEnvVar("LLVM_PROGRAM_TEST_NO_STACKTRACE_HANDLER=1");
|
|
|
|
|
|
|
|
std::string Error;
|
|
|
|
bool ExecutionFailed;
|
|
|
|
int RetCode = ExecuteAndWait(Executable, argv, getEnviron(), {}, 0, 0, &Error,
|
|
|
|
&ExecutionFailed);
|
|
|
|
EXPECT_FALSE(ExecutionFailed) << Error;
|
|
|
|
ASSERT_EQ(0, RetCode);
|
|
|
|
}
|
|
|
|
|
2013-04-23 03:03:55 +08:00
|
|
|
} // end anonymous namespace
|