Merge pull request #3615 from IYP-Programer-Yeah:fix-per-test-filter-processing
PiperOrigin-RevId: 423326942 Change-Id: I913f31960d7917b176c9f390424630708473837a
This commit is contained in:
		@@ -725,60 +725,101 @@ static bool PatternMatchesString(const std::string& name_str,
 | 
			
		||||
  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,
 | 
			
		||||
                                    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);
 | 
			
		||||
 | 
			
		||||
    // 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;
 | 
			
		||||
  return UnitTestFilter(filter).MatchesName(name_str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if and only if the user-specified filter matches the test
 | 
			
		||||
// suite name and the test name.
 | 
			
		||||
bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_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
 | 
			
		||||
  // positive filter and negative filter portions
 | 
			
		||||
  std::string str = GTEST_FLAG_GET(filter);
 | 
			
		||||
  const char* const p = str.c_str();
 | 
			
		||||
  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()));
 | 
			
		||||
  return PositiveAndNegativeUnitTestFilter(GTEST_FLAG_GET(filter))
 | 
			
		||||
      .MatchesTest(test_suite_name, test_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if GTEST_HAS_SEH
 | 
			
		||||
@@ -5719,9 +5760,9 @@ TestSuite* UnitTestImpl::GetTestSuite(
 | 
			
		||||
  auto* const new_test_suite =
 | 
			
		||||
      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?
 | 
			
		||||
  if (internal::UnitTestOptions::MatchesFilter(test_suite_name,
 | 
			
		||||
                                               kDeathTestSuiteFilter)) {
 | 
			
		||||
  if (death_test_suite_filter.MatchesName(test_suite_name)) {
 | 
			
		||||
    // Yes.  Inserts the test suite after the last death test suite
 | 
			
		||||
    // defined so far.  This only works when the test suites haven't
 | 
			
		||||
    // 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 ?
 | 
			
		||||
      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
 | 
			
		||||
  // run across all shards (i.e., match filter and are not disabled).
 | 
			
		||||
  // 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());
 | 
			
		||||
      // A test is disabled if test suite name or test name matches
 | 
			
		||||
      // kDisableTestFilter.
 | 
			
		||||
      const bool is_disabled = internal::UnitTestOptions::MatchesFilter(
 | 
			
		||||
                                   test_suite_name, kDisableTestFilter) ||
 | 
			
		||||
                               internal::UnitTestOptions::MatchesFilter(
 | 
			
		||||
                                   test_name, kDisableTestFilter);
 | 
			
		||||
      const bool is_disabled =
 | 
			
		||||
          disable_test_filter.MatchesName(test_suite_name) ||
 | 
			
		||||
          disable_test_filter.MatchesName(test_name);
 | 
			
		||||
      test_info->is_disabled_ = is_disabled;
 | 
			
		||||
 | 
			
		||||
      const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(
 | 
			
		||||
          test_suite_name, test_name);
 | 
			
		||||
      const bool matches_filter =
 | 
			
		||||
          gtest_flag_filter.MatchesTest(test_suite_name, test_name);
 | 
			
		||||
      test_info->matches_filter_ = matches_filter;
 | 
			
		||||
 | 
			
		||||
      const bool is_runnable =
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user