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 /** 16 * Filters tests based on a googletest-style filter string. 17 */ 18 class GtestFilter extends Filter { 19 20 private final String mFilterString; 21 22 private final Set<Pattern> mPositiveRegexes; 23 private final Set<Pattern> mNegativeRegexes; 24 25 private static final Pattern ASTERISK = Pattern.compile("\\*"); 26 private static final Pattern COLON = Pattern.compile(":"); 27 private static final Pattern DASH = Pattern.compile("-"); 28 private static final Pattern DOLLAR = Pattern.compile("\\$"); 29 private static final Pattern PERIOD = Pattern.compile("\\."); 30 private static final Pattern OPEN_BRACKET = Pattern.compile("\\["); 31 private static final Pattern CLOSED_BRACKET = Pattern.compile("\\]"); 32 33 /** 34 * Creates the filter and converts the provided googletest-style filter 35 * string into positive and negative regexes. 36 */ GtestFilter(String filterString)37 public GtestFilter(String filterString) { 38 mFilterString = filterString; 39 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 gtestName = description.getClassName() + "." + description.getMethodName(); 82 for (Pattern p : mNegativeRegexes) { 83 if (p.matcher(gtestName).matches()) return false; 84 } 85 86 if (mPositiveRegexes.isEmpty()) return true; 87 88 for (Pattern p : mPositiveRegexes) { 89 if (p.matcher(gtestName).matches()) return true; 90 } 91 92 return false; 93 } 94 95 /** 96 * Returns a description of this filter. 97 */ 98 @Override describe()99 public String describe() { 100 return "gtest-filter: " + mFilterString; 101 } 102 103 } 104 105