• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.testing.local;
6 
7 import org.junit.runner.Description;
8 import org.junit.runner.manipulation.Filter;
9 
10 import java.util.HashSet;
11 import java.util.Set;
12 import java.util.regex.Matcher;
13 import java.util.regex.Pattern;
14 
15 /** Filters tests based on a googletest-style filter string. */
16 class GtestFilter extends Filter {
17 
18     private final String mFilterString;
19 
20     private final Set<Pattern> mPositiveRegexes;
21     private final Set<Pattern> mNegativeRegexes;
22 
23     private static final Pattern ASTERISK = Pattern.compile("\\*");
24     private static final Pattern COLON = Pattern.compile(":");
25     private static final Pattern DASH = Pattern.compile("-");
26     private static final Pattern DOLLAR = Pattern.compile("\\$");
27     private static final Pattern PERIOD = Pattern.compile("\\.");
28     private static final Pattern OPEN_BRACKET = Pattern.compile("\\[");
29     private static final Pattern CLOSED_BRACKET = Pattern.compile("\\]");
30 
31     // Matches a test that can have an SDK version in the name: org.class.testInvalidMinidump[28]
32     private static final Pattern GTEST_NAME_REGEX = Pattern.compile("(.*)?\\[\\d+\\]$");
33 
34     /**
35      *  Creates the filter and converts the provided googletest-style filter
36      *  string into positive and negative regexes.
37      */
GtestFilter(String filterString)38     public GtestFilter(String filterString) {
39         mFilterString = filterString;
40         String[] filterStrings = DASH.split(filterString, 2);
41         mPositiveRegexes = generatePatternSet(filterStrings[0]);
42         if (filterStrings.length == 2) {
43             mNegativeRegexes = generatePatternSet(filterStrings[1]);
44         } else {
45             mNegativeRegexes = new HashSet<Pattern>();
46         }
47     }
48 
generatePatternSet(String filterString)49     private Set<Pattern> generatePatternSet(String filterString) {
50         Set<Pattern> patterns = new HashSet<Pattern>();
51         String[] filterStrings = COLON.split(filterString);
52         for (String f : filterStrings) {
53             if (f.isEmpty()) continue;
54 
55             String sanitized = PERIOD.matcher(f).replaceAll(Matcher.quoteReplacement("\\."));
56             sanitized = DOLLAR.matcher(sanitized).replaceAll(Matcher.quoteReplacement("\\$"));
57             sanitized = ASTERISK.matcher(sanitized).replaceAll(".*");
58             sanitized = OPEN_BRACKET.matcher(sanitized).replaceAll(Matcher.quoteReplacement("\\["));
59             sanitized =
60                     CLOSED_BRACKET.matcher(sanitized).replaceAll(Matcher.quoteReplacement("\\]"));
61             patterns.add(Pattern.compile(sanitized));
62         }
63         return patterns;
64     }
65 
66     /**
67      *  Determines whether or not a test with the provided description should
68      *  run based on the configured positive and negative regexes.
69      *
70      *  A test should run if:
71      *    - it's just a class, OR
72      *    - it doesn't match any of the negative regexes, AND
73      *    - either:
74      *      - there are no configured positive regexes, OR
75      *      - it matches at least one of the positive regexes.
76      */
77     @Override
shouldRun(Description description)78     public boolean shouldRun(Description description) {
79         if (description.getMethodName() == null) return true;
80 
81         String gtestSdkName = description.getClassName() + "." + description.getMethodName();
82         String gtestName = description.getClassName() + "." + description.getMethodName();
83         // Use regex to get test name without sdk appended to make filtering more intuitive.
84         // Some tests may not have an sdk version.
85         Matcher gtestNameMatcher = GTEST_NAME_REGEX.matcher(gtestName);
86         if (gtestNameMatcher.find()) {
87             gtestName = gtestNameMatcher.group(1);
88         }
89 
90         for (Pattern p : mNegativeRegexes) {
91             if (p.matcher(gtestName).matches() || p.matcher(gtestSdkName).matches()) return false;
92         }
93 
94         if (mPositiveRegexes.isEmpty()) return true;
95 
96         for (Pattern p : mPositiveRegexes) {
97             if (p.matcher(gtestName).matches() || p.matcher(gtestSdkName).matches()) return true;
98         }
99 
100         return false;
101     }
102 
103     /** Returns a description of this filter. */
104     @Override
describe()105     public String describe() {
106         return "gtest-filter: " + mFilterString;
107     }
108 }
109