Repository: google/googletest
File: googletest/src/gtest.cc (C++)

Code before:
    const auto pattern_matches_name = [&name](const std::string& pattern) {
      return PatternMatchesString(name, pattern.c_str(),
                                  pattern.c_str() + pattern.size());
    };
    return std::any_of(patterns_.begin(), patterns_.end(),
                       pattern_matches_name);
  }

 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;

    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.size() ? positive_filter : kUniversalFilter};
      negative_filter_ = UnitTestFilter{positive_and_negative_filters.back()};
    } else {
      // In case positive filter is empty
      // we do not use kUniversalFilter by design
      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 {
    const std::string& full_name = test_suite_name + "." + test_name.c_str();

    return MatchesName(full_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);

Review comment (bug):
Unfortunately, the original API did not do any validation here -- instead, it just split on the first `-` and ignored others. This would change it to split on all `-` and only consider the first and the last segments if there were more than 2.

Even though it's undefined behavior, I'd retain the original to avoid breaking [inevitable](https://www.hyrumslaw.com/) dependents for now, e.g. by concatenating everything past the first element into the negative filter.
Since we're here, please add a comment like `// TODO: Fail on multiple '-' characters`.





Code after:
    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;

    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: 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);