Merge pull request #3615 from IYP-Programer-Yeah:fix-per-test-filter-processing
PiperOrigin-RevId: 423326942 Change-Id: I913f31960d7917b176c9f390424630708473837a
This commit is contained in:
commit
3d81736c97
@ -725,60 +725,101 @@ static bool PatternMatchesString(const std::string& name_str,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class UnitTestFilter {
|
||||||
|
public:
|
||||||
|
UnitTestFilter() = default;
|
||||||
|
|
||||||
|
// Constructs a filter from a string of patterns separated by `:`.
|
||||||
|
explicit UnitTestFilter(const std::string& filter) {
|
||||||
|
// By design "" filter matches "" string.
|
||||||
|
SplitString(filter, ':', &patterns_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if and only if name matches at least one of the patterns in
|
||||||
|
// the filter.
|
||||||
|
bool MatchesName(const std::string& name) const {
|
||||||
|
return std::any_of(patterns_.begin(), patterns_.end(),
|
||||||
|
[&name](const std::string& pattern) {
|
||||||
|
return PatternMatchesString(
|
||||||
|
name, pattern.c_str(),
|
||||||
|
pattern.c_str() + pattern.size());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> patterns_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PositiveAndNegativeUnitTestFilter {
|
||||||
|
public:
|
||||||
|
// Constructs a positive and a negative filter from a string. The string
|
||||||
|
// contains a positive filter optionally followed by a '-' character and a
|
||||||
|
// negative filter. In case only a negative filter is provided the positive
|
||||||
|
// filter will be assumed "*".
|
||||||
|
// A filter is a list of patterns separated by ':'.
|
||||||
|
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);
|
||||||
|
const auto& positive_filter = positive_and_negative_filters.front();
|
||||||
|
|
||||||
|
if (positive_and_negative_filters.size() > 1) {
|
||||||
|
positive_filter_ = UnitTestFilter(
|
||||||
|
positive_filter.empty() ? kUniversalFilter : positive_filter);
|
||||||
|
|
||||||
|
// TODO(b/214626361): Fail on multiple '-' characters
|
||||||
|
// For the moment to preserve old behavior we concatenate the rest of the
|
||||||
|
// string parts with `-` as separator to generate the negative filter.
|
||||||
|
auto negative_filter_string = positive_and_negative_filters[1];
|
||||||
|
for (std::size_t i = 2; i < positive_and_negative_filters.size(); i++)
|
||||||
|
negative_filter_string =
|
||||||
|
negative_filter_string + '-' + positive_and_negative_filters[i];
|
||||||
|
negative_filter_ = UnitTestFilter(negative_filter_string);
|
||||||
|
} else {
|
||||||
|
// In case we don't have a negative filter and positive filter is ""
|
||||||
|
// we do not use kUniversalFilter by design as opposed to when we have a
|
||||||
|
// negative filter.
|
||||||
|
positive_filter_ = UnitTestFilter(positive_filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if and only if test name (this is generated by appending test
|
||||||
|
// suit name and test name via a '.' character) matches the positive filter
|
||||||
|
// and does not match the negative filter.
|
||||||
|
bool MatchesTest(const std::string& test_suite_name,
|
||||||
|
const std::string& test_name) const {
|
||||||
|
return MatchesName(test_suite_name + "." + test_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if and only if name matches the positive filter and does not
|
||||||
|
// match the negative filter.
|
||||||
|
bool MatchesName(const std::string& name) const {
|
||||||
|
return positive_filter_.MatchesName(name) &&
|
||||||
|
!negative_filter_.MatchesName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UnitTestFilter positive_filter_;
|
||||||
|
UnitTestFilter negative_filter_;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
bool UnitTestOptions::MatchesFilter(const std::string& name_str,
|
bool UnitTestOptions::MatchesFilter(const std::string& name_str,
|
||||||
const char* filter) {
|
const char* filter) {
|
||||||
// The filter is a list of patterns separated by colons (:).
|
return UnitTestFilter(filter).MatchesName(name_str);
|
||||||
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);
|
|
||||||
|
|
||||||
// Check if this pattern matches name_str.
|
|
||||||
if (PatternMatchesString(name_str, pattern, pattern_end)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give up on this pattern. However, if we found a pattern separator (:),
|
|
||||||
// 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
|
||||||
// suite name and the test name.
|
// suite name and the test name.
|
||||||
bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name,
|
bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name,
|
||||||
const std::string& test_name) {
|
const std::string& test_name) {
|
||||||
const std::string& full_name = test_suite_name + "." + test_name.c_str();
|
|
||||||
|
|
||||||
// Split --gtest_filter at '-', if there is one, to separate into
|
// Split --gtest_filter at '-', if there is one, to separate into
|
||||||
// positive filter and negative filter portions
|
// positive filter and negative filter portions
|
||||||
std::string str = GTEST_FLAG_GET(filter);
|
return PositiveAndNegativeUnitTestFilter(GTEST_FLAG_GET(filter))
|
||||||
const char* const p = str.c_str();
|
.MatchesTest(test_suite_name, test_name);
|
||||||
const char* const dash = strchr(p, '-');
|
|
||||||
std::string positive;
|
|
||||||
std::string negative;
|
|
||||||
if (dash == nullptr) {
|
|
||||||
positive = str.c_str(); // Whole string is a positive filter
|
|
||||||
negative = "";
|
|
||||||
} else {
|
|
||||||
positive = std::string(p, dash); // Everything up to the dash
|
|
||||||
negative = std::string(dash + 1); // Everything after the dash
|
|
||||||
if (positive.empty()) {
|
|
||||||
// Treat '-test1' as the same as '*-test1'
|
|
||||||
positive = kUniversalFilter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A filter is a colon-separated list of patterns. It matches a
|
|
||||||
// test if any pattern in it matches the test.
|
|
||||||
return (MatchesFilter(full_name, positive.c_str()) &&
|
|
||||||
!MatchesFilter(full_name, negative.c_str()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GTEST_HAS_SEH
|
#if GTEST_HAS_SEH
|
||||||
@ -5719,9 +5760,9 @@ TestSuite* UnitTestImpl::GetTestSuite(
|
|||||||
auto* const new_test_suite =
|
auto* const new_test_suite =
|
||||||
new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc);
|
new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc);
|
||||||
|
|
||||||
|
const UnitTestFilter death_test_suite_filter(kDeathTestSuiteFilter);
|
||||||
// Is this a death test suite?
|
// Is this a death test suite?
|
||||||
if (internal::UnitTestOptions::MatchesFilter(test_suite_name,
|
if (death_test_suite_filter.MatchesName(test_suite_name)) {
|
||||||
kDeathTestSuiteFilter)) {
|
|
||||||
// Yes. Inserts the test suite after the last death test suite
|
// Yes. Inserts the test suite after the last death test suite
|
||||||
// defined so far. This only works when the test suites haven't
|
// defined so far. This only works when the test suites haven't
|
||||||
// been shuffled. Otherwise we may end up running a death test
|
// been shuffled. Otherwise we may end up running a death test
|
||||||
@ -6054,6 +6095,9 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
|
|||||||
const int32_t shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
|
const int32_t shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
|
||||||
Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
|
Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
|
||||||
|
|
||||||
|
const PositiveAndNegativeUnitTestFilter gtest_flag_filter(
|
||||||
|
GTEST_FLAG_GET(filter));
|
||||||
|
const UnitTestFilter disable_test_filter(kDisableTestFilter);
|
||||||
// num_runnable_tests are the number of tests that will
|
// num_runnable_tests are the number of tests that will
|
||||||
// run across all shards (i.e., match filter and are not disabled).
|
// run across all shards (i.e., match filter and are not disabled).
|
||||||
// num_selected_tests are the number of tests to be run on
|
// num_selected_tests are the number of tests to be run on
|
||||||
@ -6069,14 +6113,13 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
|
|||||||
const std::string test_name(test_info->name());
|
const std::string test_name(test_info->name());
|
||||||
// A test is disabled if test suite name or test name matches
|
// A test is disabled if test suite name or test name matches
|
||||||
// kDisableTestFilter.
|
// kDisableTestFilter.
|
||||||
const bool is_disabled = internal::UnitTestOptions::MatchesFilter(
|
const bool is_disabled =
|
||||||
test_suite_name, kDisableTestFilter) ||
|
disable_test_filter.MatchesName(test_suite_name) ||
|
||||||
internal::UnitTestOptions::MatchesFilter(
|
disable_test_filter.MatchesName(test_name);
|
||||||
test_name, kDisableTestFilter);
|
|
||||||
test_info->is_disabled_ = is_disabled;
|
test_info->is_disabled_ = is_disabled;
|
||||||
|
|
||||||
const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(
|
const bool matches_filter =
|
||||||
test_suite_name, test_name);
|
gtest_flag_filter.MatchesTest(test_suite_name, test_name);
|
||||||
test_info->matches_filter_ = matches_filter;
|
test_info->matches_filter_ = matches_filter;
|
||||||
|
|
||||||
const bool is_runnable =
|
const bool is_runnable =
|
||||||
|
Loading…
Reference in New Issue
Block a user