mirror of
https://github.com/google/googletest.git
synced 2026-11-09 22:59:53 +08:00
fix(death-tests): escape ':' and '-' in threadsafe child filters
Typed-test names like std::string put ':' into --gtest_filter, which splits patterns so the child matches nothing and death tests falsely pass. Escape filter metacharacters and parse filters with unescaped delimiters only. Fixes #5105
This commit is contained in:
parent
4267679b68
commit
309a7df795
@ -738,6 +738,29 @@ int WindowsDeathTest::Wait() {
|
||||
return status();
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
// Keep in sync with EscapeGTestFilterLiteral in gtest.cc — death-test child
|
||||
// filters must treat ':' and '-' in typed-test names as literals (#5105).
|
||||
std::string EscapeDeathTestFilterLiteral(const std::string& str) {
|
||||
std::string out;
|
||||
out.reserve(str.size());
|
||||
for (char c : str) {
|
||||
if (c == '\\' || c == ':' || c == '-') {
|
||||
out.push_back('\\');
|
||||
}
|
||||
out.push_back(c);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string DeathTestFilterFlag(const TestInfo* info) {
|
||||
return std::string("--") + GTEST_FLAG_PREFIX_ + "filter=" +
|
||||
EscapeDeathTestFilterLiteral(info->test_suite_name()) + "." +
|
||||
EscapeDeathTestFilterLiteral(info->name());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// The AssumeRole process for a Windows death test. It creates a child
|
||||
// process with the same executable as the current process to run the
|
||||
// death test. The child process is given the --gtest_filter and
|
||||
@ -775,9 +798,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
||||
FALSE, // The initial state is non-signalled.
|
||||
nullptr)); // The even is unnamed.
|
||||
GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr);
|
||||
const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
|
||||
"filter=" + info->test_suite_name() + "." +
|
||||
info->name();
|
||||
const std::string filter_flag = DeathTestFilterFlag(info);
|
||||
const std::string internal_flag =
|
||||
std::string("--") + GTEST_FLAG_PREFIX_ +
|
||||
"internal_run_death_test=" + file_ + "|" + StreamableToString(line_) +
|
||||
@ -969,9 +990,7 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
|
||||
FlushInfoLog();
|
||||
|
||||
// Build the child process command line.
|
||||
const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
|
||||
"filter=" + info->test_suite_name() + "." +
|
||||
info->name();
|
||||
const std::string filter_flag = DeathTestFilterFlag(info);
|
||||
const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
|
||||
kInternalRunDeathTestFlag + "=" + file_ +
|
||||
"|" + StreamableToString(line_) + "|" +
|
||||
@ -1369,9 +1388,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
|
||||
// it be closed when the child process does an exec:
|
||||
GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
|
||||
|
||||
const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
|
||||
"filter=" + info->test_suite_name() + "." +
|
||||
info->name();
|
||||
const std::string filter_flag = DeathTestFilterFlag(info);
|
||||
const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
|
||||
"internal_run_death_test=" + file_ + "|" +
|
||||
StreamableToString(line_) + "|" +
|
||||
|
||||
@ -828,7 +828,7 @@ class UnitTestFilter {
|
||||
explicit UnitTestFilter(const std::string& filter) {
|
||||
// By design "" filter matches "" string.
|
||||
std::vector<std::string> all_patterns;
|
||||
SplitString(filter, ':', &all_patterns);
|
||||
SplitStringUnescaped(filter, ':', &all_patterns);
|
||||
const auto exact_match_patterns_begin = std::partition(
|
||||
all_patterns.begin(), all_patterns.end(), &IsGlobPattern);
|
||||
|
||||
@ -868,8 +868,10 @@ class PositiveAndNegativeUnitTestFilter {
|
||||
explicit PositiveAndNegativeUnitTestFilter(const std::string& filter) {
|
||||
std::vector<std::string> positive_and_negative_filters;
|
||||
|
||||
// NOTE: `SplitString` always returns a non-empty container.
|
||||
SplitString(filter, '-', &positive_and_negative_filters);
|
||||
// NOTE: `SplitStringUnescaped` always returns a non-empty container.
|
||||
// Death-test filters escape literal '-' as "\-" so typed-test names with
|
||||
// hyphens are not treated as a negative filter (#5105).
|
||||
SplitStringUnescaped(filter, '-', &positive_and_negative_filters);
|
||||
const auto& positive_filter = positive_and_negative_filters.front();
|
||||
|
||||
if (positive_and_negative_filters.size() > 1) {
|
||||
@ -1335,6 +1337,28 @@ void SplitString(const ::std::string& str, char delimiter,
|
||||
dest->swap(parsed);
|
||||
}
|
||||
|
||||
// Like SplitString, but treats "\<delimiter>" as a literal delimiter character
|
||||
// (backslash is consumed). Used for --gtest_filter parsing.
|
||||
static void SplitStringUnescaped(const ::std::string& str, char delimiter,
|
||||
::std::vector<std::string>* dest) {
|
||||
dest->clear();
|
||||
std::string current;
|
||||
for (size_t i = 0; i < str.size(); ++i) {
|
||||
if (str[i] == '\\' && i + 1 < str.size()) {
|
||||
current.push_back(str[++i]);
|
||||
continue;
|
||||
}
|
||||
if (str[i] == delimiter) {
|
||||
dest->push_back(current);
|
||||
current.clear();
|
||||
continue;
|
||||
}
|
||||
current.push_back(str[i]);
|
||||
}
|
||||
dest->push_back(current);
|
||||
}
|
||||
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Constructs an empty Message.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user