diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc index 15472f1a7..c091335ae 100644 --- a/googletest/src/gtest-death-test.cc +++ b/googletest/src/gtest-death-test.cc @@ -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_) + "|" + diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index d66756e88..323c95e17 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -828,7 +828,7 @@ class UnitTestFilter { explicit UnitTestFilter(const std::string& filter) { // By design "" filter matches "" string. std::vector 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 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 "\" as a literal delimiter character +// (backslash is consumed). Used for --gtest_filter parsing. +static void SplitStringUnescaped(const ::std::string& str, char delimiter, + ::std::vector* 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.