Commit fd873f6d authored by dmcardle's avatar dmcardle Committed by Dino Radaković
Browse files

Googletest export

Use linear-time string globbing in UnitTestOptions::MatchesFilter.

Algorithm is based on https://research.swtch.com/glob.

Closes #3227

PiperOrigin-RevId: 355222440
parent f4e7727c
...@@ -394,13 +394,6 @@ class GTEST_API_ UnitTestOptions { ...@@ -394,13 +394,6 @@ class GTEST_API_ UnitTestOptions {
// Functions for processing the gtest_filter flag. // Functions for processing the gtest_filter flag.
// Returns true if and only if the wildcard pattern matches the string.
// The first ':' or '\0' character in pattern marks the end of it.
//
// This recursive algorithm isn't very efficient, but is clear and
// works well enough for matching test names, which are short.
static bool PatternMatchesString(const char *pattern, const char *str);
// Returns true if and only if the user-specified filter matches the test // Returns true if and only if the user-specified filter matches the test
// suite name and the test name. // suite name and the test name.
static bool FilterMatchesTest(const std::string& test_suite_name, static bool FilterMatchesTest(const std::string& test_suite_name,
......
...@@ -646,47 +646,82 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() { ...@@ -646,47 +646,82 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
return result.string(); return result.string();
} }
// Returns true if and only if the wildcard pattern matches the string. // Returns true if and only if the wildcard pattern matches the string. Each
// The first ':' or '\0' character in pattern marks the end of it. // pattern consists of regular characters, single-character wildcards (?), and
// multi-character wildcards (*).
// //
// This recursive algorithm isn't very efficient, but is clear and // This function implements a linear-time string globbing algorithm based on
// works well enough for matching test names, which are short. // https://research.swtch.com/glob.
bool UnitTestOptions::PatternMatchesString(const char *pattern, static bool PatternMatchesString(const std::string& name_str,
const char *str) { const char* pattern, const char* pattern_end) {
switch (*pattern) { const char* name = name_str.c_str();
case '\0': const char* const name_begin = name;
case ':': // Either ':' or '\0' marks the end of the pattern. const char* const name_end = name + name_str.size();
return *str == '\0';
case '?': // Matches any single character. const char* pattern_next = pattern;
return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); const char* name_next = name;
case '*': // Matches any string (possibly empty) of characters.
return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || while (pattern < pattern_end || name < name_end) {
PatternMatchesString(pattern + 1, str); if (pattern < pattern_end) {
default: // Non-special character. Matches itself. switch (*pattern) {
return *pattern == *str && default: // Match an ordinary character.
PatternMatchesString(pattern + 1, str + 1); if (name < name_end && *name == *pattern) {
} ++pattern;
} ++name;
continue;
bool UnitTestOptions::MatchesFilter( }
const std::string& name, const char* filter) { break;
const char *cur_pattern = filter; case '?': // Match any single character.
for (;;) { if (name < name_end) {
if (PatternMatchesString(cur_pattern, name.c_str())) { ++pattern;
return true; ++name;
continue;
}
break;
case '*':
// Match zero or more characters. Start by skipping over the wildcard
// and matching zero characters from name. If that fails, restart and
// match one more character than the last attempt.
pattern_next = pattern;
name_next = name + 1;
++pattern;
continue;
}
}
// Failed to match a character. Restart if possible.
if (name_begin < name_next && name_next <= name_end) {
pattern = pattern_next;
name = name_next;
continue;
} }
return false;
}
return true;
}
// Finds the next pattern in the filter. bool UnitTestOptions::MatchesFilter(const std::string& name_str,
cur_pattern = strchr(cur_pattern, ':'); const char* filter) {
// The filter is a list of patterns separated by colons (:).
const char* pattern = filter;
while (true) {
// Find the bounds of this pattern.
const char* const next_sep = strchr(pattern, ':');
const char* const pattern_end =
next_sep != nullptr ? next_sep : pattern + strlen(pattern);
// Returns if no more pattern can be found. // Check if this pattern matches name_str.
if (cur_pattern == nullptr) { if (PatternMatchesString(name_str, pattern, pattern_end)) {
return false; return true;
} }
// Skips the pattern separater (the ':' character). // Give up on this pattern. However, if we found a pattern separator (:),
cur_pattern++; // advance to the next pattern (skipping over the separator) and restart.
if (next_sep == nullptr) {
return false;
}
pattern = next_sep + 1;
} }
return true;
} }
// Returns true if and only if the user-specified filter matches the test // Returns true if and only if the user-specified filter matches the test
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment