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