Add support for --gtest_flagfile

This commit is contained in:
kosak 2015-07-17 21:56:19 +00:00
parent 0928adbfea
commit 195610d30c
8 changed files with 246 additions and 108 deletions

View File

@ -587,6 +587,11 @@ inline std::string GetPrefixUntilComma(const char* str) {
return comma == NULL ? str : std::string(str, comma);
}
// Splits a given string on a given delimiter, populating a given
// vector with the fields.
void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest);
// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
// registers a list of type-parameterized tests with Google Test. The
// return value is insignificant - we just need to return something

View File

@ -1403,6 +1403,14 @@ GTEST_API_ std::string GetCapturedStderr();
#endif // GTEST_HAS_STREAM_REDIRECTION
// Returns a path to temporary directory.
GTEST_API_ std::string TempDir();
// Returns the size (in bytes) of a file.
GTEST_API_ size_t GetFileSize(FILE* file);
// Reads the entire content of a file as a string.
GTEST_API_ std::string ReadEntireFile(FILE* file);
#if GTEST_HAS_DEATH_TEST

View File

@ -1204,26 +1204,6 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
return true;
}
// Splits a given string on a given delimiter, populating a given
// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
// ::std::string, so we can use it here.
static void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest) {
::std::vector< ::std::string> parsed;
::std::string::size_type pos = 0;
while (::testing::internal::AlwaysTrue()) {
const ::std::string::size_type colon = str.find(delimiter, pos);
if (colon == ::std::string::npos) {
parsed.push_back(str.substr(pos));
break;
} else {
parsed.push_back(str.substr(pos, colon - pos));
pos = colon + 1;
}
}
dest->swap(parsed);
}
# if GTEST_OS_WINDOWS
// Recreates the pipe and event handles from the provided parameters,
// signals the event, and returns a file descriptor wrapped around the pipe

View File

@ -100,6 +100,7 @@ const char kShuffleFlag[] = "shuffle";
const char kStackTraceDepthFlag[] = "stack_trace_depth";
const char kStreamResultToFlag[] = "stream_result_to";
const char kThrowOnFailureFlag[] = "throw_on_failure";
const char kFlagfileFlag[] = "flagfile";
// A valid random seed must be in [1, kMaxRandomSeed].
const int kMaxRandomSeed = 99999;

View File

@ -962,12 +962,6 @@ class CapturedStream {
}
private:
// Reads the entire content of a file as an std::string.
static std::string ReadEntireFile(FILE* file);
// Returns the size (in bytes) of a file.
static size_t GetFileSize(FILE* file);
const int fd_; // A stream to capture.
int uncaptured_fd_;
// Name of the temporary file holding the stderr output.
@ -976,35 +970,6 @@ class CapturedStream {
GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
};
// Returns the size (in bytes) of a file.
size_t CapturedStream::GetFileSize(FILE* file) {
fseek(file, 0, SEEK_END);
return static_cast<size_t>(ftell(file));
}
// Reads the entire content of a file as a string.
std::string CapturedStream::ReadEntireFile(FILE* file) {
const size_t file_size = GetFileSize(file);
char* const buffer = new char[file_size];
size_t bytes_last_read = 0; // # of bytes read in the last fread()
size_t bytes_read = 0; // # of bytes read so far
fseek(file, 0, SEEK_SET);
// Keeps reading the file until we cannot read further or the
// pre-determined file size is reached.
do {
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
bytes_read += bytes_last_read;
} while (bytes_last_read > 0 && bytes_read < file_size);
const std::string content(buffer, bytes_read);
delete[] buffer;
return content;
}
GTEST_DISABLE_MSC_WARNINGS_POP_()
static CapturedStream* g_captured_stderr = NULL;
@ -1051,6 +1016,51 @@ std::string GetCapturedStderr() {
#endif // GTEST_HAS_STREAM_REDIRECTION
std::string TempDir() {
#if GTEST_OS_WINDOWS_MOBILE
return "\\temp\\";
#elif GTEST_OS_WINDOWS
const char* temp_dir = posix::GetEnv("TEMP");
if (temp_dir == NULL || temp_dir[0] == '\0')
return "\\temp\\";
else if (temp_dir[strlen(temp_dir) - 1] == '\\')
return temp_dir;
else
return std::string(temp_dir) + "\\";
#elif GTEST_OS_LINUX_ANDROID
return "/sdcard/";
#else
return "/tmp/";
#endif // GTEST_OS_WINDOWS_MOBILE
}
size_t GetFileSize(FILE* file) {
fseek(file, 0, SEEK_END);
return static_cast<size_t>(ftell(file));
}
std::string ReadEntireFile(FILE* file) {
const size_t file_size = GetFileSize(file);
char* const buffer = new char[file_size];
size_t bytes_last_read = 0; // # of bytes read in the last fread()
size_t bytes_read = 0; // # of bytes read so far
fseek(file, 0, SEEK_SET);
// Keeps reading the file until we cannot read further or the
// pre-determined file size is reached.
do {
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
bytes_read += bytes_last_read;
} while (bytes_last_read > 0 && bytes_read < file_size);
const std::string content(buffer, bytes_read);
delete[] buffer;
return content;
}
#if GTEST_HAS_DEATH_TEST
// A copy of all command line arguments. Set by InitGoogleTest().

View File

@ -295,6 +295,11 @@ GTEST_DEFINE_bool_(
"if exceptions are enabled or exit the program with a non-zero code "
"otherwise.");
GTEST_DEFINE_string_(
flagfile,
internal::StringFromGTestEnv("flagfile", ""),
"This flag specifies the flagfile to read command-line flags from.");
namespace internal {
// Generates a random number from [0, range), using a Linear
@ -905,6 +910,23 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest) {
::std::vector< ::std::string> parsed;
::std::string::size_type pos = 0;
while (::testing::internal::AlwaysTrue()) {
const ::std::string::size_type colon = str.find(delimiter, pos);
if (colon == ::std::string::npos) {
parsed.push_back(str.substr(pos));
break;
} else {
parsed.push_back(str.substr(pos, colon - pos));
pos = colon + 1;
}
}
dest->swap(parsed);
}
} // namespace internal
// Constructs an empty Message.
@ -5178,6 +5200,56 @@ static const char kColorEncodedHelpMessage[] =
"(not one in your own code or tests), please report it to\n"
"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
bool ParseGoogleTestFlag(const char* const arg) {
return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
&GTEST_FLAG(also_run_disabled_tests)) ||
ParseBoolFlag(arg, kBreakOnFailureFlag,
&GTEST_FLAG(break_on_failure)) ||
ParseBoolFlag(arg, kCatchExceptionsFlag,
&GTEST_FLAG(catch_exceptions)) ||
ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
ParseStringFlag(arg, kDeathTestStyleFlag,
&GTEST_FLAG(death_test_style)) ||
ParseBoolFlag(arg, kDeathTestUseFork,
&GTEST_FLAG(death_test_use_fork)) ||
ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
ParseStringFlag(arg, kInternalRunDeathTestFlag,
&GTEST_FLAG(internal_run_death_test)) ||
ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
ParseInt32Flag(arg, kStackTraceDepthFlag,
&GTEST_FLAG(stack_trace_depth)) ||
ParseStringFlag(arg, kStreamResultToFlag,
&GTEST_FLAG(stream_result_to)) ||
ParseBoolFlag(arg, kThrowOnFailureFlag,
&GTEST_FLAG(throw_on_failure));
}
void LoadFlagsFromFile(const std::string& path) {
FILE* flagfile = posix::FOpen(path.c_str(), "r");
if (!flagfile) {
fprintf(stderr,
"Unable to open file \"%s\"\n",
GTEST_FLAG(flagfile).c_str());
fflush(stderr);
exit(EXIT_FAILURE);
}
std::string contents(ReadEntireFile(flagfile));
posix::FClose(flagfile);
std::vector<std::string> lines;
SplitString(contents, '\n', &lines);
for (size_t i = 0; i < lines.size(); ++i) {
if (lines[i].empty())
continue;
if (!ParseGoogleTestFlag(lines[i].c_str()))
g_help_flag = true;
}
}
// Parses the command line for Google Test flags, without initializing
// other parts of Google Test. The type parameter CharType can be
// instantiated to either char or wchar_t.
@ -5191,35 +5263,22 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
using internal::ParseInt32Flag;
using internal::ParseStringFlag;
// Do we see a Google Test flag?
if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
&GTEST_FLAG(also_run_disabled_tests)) ||
ParseBoolFlag(arg, kBreakOnFailureFlag,
&GTEST_FLAG(break_on_failure)) ||
ParseBoolFlag(arg, kCatchExceptionsFlag,
&GTEST_FLAG(catch_exceptions)) ||
ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
ParseStringFlag(arg, kDeathTestStyleFlag,
&GTEST_FLAG(death_test_style)) ||
ParseBoolFlag(arg, kDeathTestUseFork,
&GTEST_FLAG(death_test_use_fork)) ||
ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
ParseStringFlag(arg, kInternalRunDeathTestFlag,
&GTEST_FLAG(internal_run_death_test)) ||
ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
ParseInt32Flag(arg, kStackTraceDepthFlag,
&GTEST_FLAG(stack_trace_depth)) ||
ParseStringFlag(arg, kStreamResultToFlag,
&GTEST_FLAG(stream_result_to)) ||
ParseBoolFlag(arg, kThrowOnFailureFlag,
&GTEST_FLAG(throw_on_failure))
) {
// Yes. Shift the remainder of the argv list left by one. Note
bool remove_flag = false;
if (ParseGoogleTestFlag(arg)) {
remove_flag = true;
} else if (ParseStringFlag(arg, kFlagfileFlag, &GTEST_FLAG(flagfile))) {
LoadFlagsFromFile(GTEST_FLAG(flagfile));
remove_flag = true;
} else if (arg_string == "--help" || arg_string == "-h" ||
arg_string == "-?" || arg_string == "/?" ||
HasGoogleTestFlagPrefix(arg)) {
// Both help flag and unrecognized Google Test flags (excluding
// internal ones) trigger help display.
g_help_flag = true;
}
if (remove_flag) {
// Shift the remainder of the argv list left by one. Note
// that argv has (*argc + 1) elements, the last one always being
// NULL. The following loop moves the trailing NULL element as
// well.
@ -5233,12 +5292,6 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
// We also need to decrement the iterator as we just removed
// an element.
i--;
} else if (arg_string == "--help" || arg_string == "-h" ||
arg_string == "-?" || arg_string == "/?" ||
HasGoogleTestFlagPrefix(arg)) {
// Both help flag and unrecognized Google Test flags (excluding
// internal ones) trigger help display.
g_help_flag = true;
}
}

View File

@ -514,24 +514,6 @@ class DirectoryCreationTest : public Test {
posix::RmDir(testdata_path_.c_str());
}
std::string TempDir() const {
#if GTEST_OS_WINDOWS_MOBILE
return "\\temp\\";
#elif GTEST_OS_WINDOWS
const char* temp_dir = posix::GetEnv("TEMP");
if (temp_dir == NULL || temp_dir[0] == '\0')
return "\\temp\\";
else if (temp_dir[strlen(temp_dir) - 1] == '\\')
return temp_dir;
else
return std::string(temp_dir) + "\\";
#elif GTEST_OS_LINUX_ANDROID
return "/sdcard/";
#else
return "/tmp/";
#endif // GTEST_OS_WINDOWS_MOBILE
}
void CreateTextFile(const char* filename) {
FILE* f = posix::FOpen(filename, "w");
fprintf(f, "text\n");

View File

@ -6345,6 +6345,105 @@ TEST_F(InitGoogleTestTest, WideStrings) {
}
# endif // GTEST_OS_WINDOWS
class FlagfileTest : public InitGoogleTestTest {
public:
virtual void SetUp() {
InitGoogleTestTest::SetUp();
testdata_path_.Set(internal::FilePath(
internal::TempDir() + internal::GetCurrentExecutableName().string() +
"_flagfile_test"));
testing::internal::posix::RmDir(testdata_path_.c_str());
EXPECT_TRUE(testdata_path_.CreateFolder());
}
virtual void TearDown() {
testing::internal::posix::RmDir(testdata_path_.c_str());
InitGoogleTestTest::TearDown();
}
internal::FilePath CreateFlagfile(const char* contents) {
internal::FilePath file_path(internal::FilePath::GenerateUniqueFileName(
testdata_path_, internal::FilePath("unique"), "txt"));
FILE* f = testing::internal::posix::FOpen(file_path.c_str(), "w");
fprintf(f, "%s", contents);
fclose(f);
return file_path;
}
private:
internal::FilePath testdata_path_;
};
// Tests an empty flagfile.
TEST_F(FlagfileTest, Empty) {
internal::FilePath flagfile_path(CreateFlagfile(""));
std::string flagfile_flag =
std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str();
const char* argv[] = {
"foo.exe",
flagfile_flag.c_str(),
NULL
};
const char* argv2[] = {
"foo.exe",
NULL
};
GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false);
}
// Tests passing a non-empty --gtest_filter flag via --gtest_flagfile.
TEST_F(FlagfileTest, FilterNonEmpty) {
internal::FilePath flagfile_path(CreateFlagfile(
"--" GTEST_FLAG_PREFIX_ "filter=abc"));
std::string flagfile_flag =
std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str();
const char* argv[] = {
"foo.exe",
flagfile_flag.c_str(),
NULL
};
const char* argv2[] = {
"foo.exe",
NULL
};
GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false);
}
// Tests passing several flags via --gtest_flagfile.
TEST_F(FlagfileTest, SeveralFlags) {
internal::FilePath flagfile_path(CreateFlagfile(
"--" GTEST_FLAG_PREFIX_ "filter=abc\n"
"--" GTEST_FLAG_PREFIX_ "break_on_failure\n"
"--" GTEST_FLAG_PREFIX_ "list_tests"));
std::string flagfile_flag =
std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str();
const char* argv[] = {
"foo.exe",
flagfile_flag.c_str(),
NULL
};
const char* argv2[] = {
"foo.exe",
NULL
};
Flags expected_flags;
expected_flags.break_on_failure = true;
expected_flags.filter = "abc";
expected_flags.list_tests = true;
GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false);
}
// Tests current_test_info() in UnitTest.
class CurrentTestInfoTest : public Test {
protected: