All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.maven.surefire.api.testset.ResolvedTest Maven / Gradle / Ivy

Go to download

API used in Surefire and Failsafe MOJO, Booter, Common and test framework providers.

There is a newer version: 3.5.2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.maven.surefire.api.testset;

import java.util.regex.Pattern;

import org.apache.maven.surefire.shared.utils.StringUtils;
import org.apache.maven.surefire.shared.utils.io.MatchPatterns;

import static java.io.File.separatorChar;
import static java.util.regex.Pattern.compile;
import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;
import static org.apache.maven.surefire.shared.utils.io.MatchPatterns.from;
import static org.apache.maven.surefire.shared.utils.io.SelectorUtils.PATTERN_HANDLER_SUFFIX;
import static org.apache.maven.surefire.shared.utils.io.SelectorUtils.REGEX_HANDLER_PREFIX;
import static org.apache.maven.surefire.shared.utils.io.SelectorUtils.matchPath;

/**
 * Single pattern test filter resolved from multi pattern filter -Dtest=MyTest#test,AnotherTest#otherTest.
 * @deprecated will be renamed to ResolvedTestPattern
 */
// will be renamed to ResolvedTestPattern
@Deprecated
public final class ResolvedTest {
    /**
     * Type of patterns in ResolvedTest constructor.
     */
    public enum Type {
        CLASS,
        METHOD
    }

    private static final String CLASS_FILE_EXTENSION = ".class";

    private static final String JAVA_FILE_EXTENSION = ".java";

    private static final String WILDCARD_PATH_PREFIX = "**/";

    private static final String WILDCARD_FILENAME_POSTFIX = ".*";

    private final String classPattern;

    private final String methodPattern;

    private final boolean isRegexTestClassPattern;

    private final boolean isRegexTestMethodPattern;

    private final String description;

    private final ClassMatcher classMatcher = new ClassMatcher();

    private final MethodMatcher methodMatcher = new MethodMatcher();

    /**
     * '*' means zero or more characters
* '?' means one and only one character * The pattern %regex[] prefix and suffix does not appear. The regex pattern is always * unwrapped by the caller. * * @param classPattern test class file pattern * @param methodPattern test method * @param isRegex {@code true} if pattern is regex */ public ResolvedTest(String classPattern, String methodPattern, boolean isRegex) { classPattern = tryBlank(classPattern); methodPattern = tryBlank(methodPattern); description = description(classPattern, methodPattern, isRegex); if (isRegex && classPattern != null) { classPattern = wrapRegex(classPattern); } if (isRegex && methodPattern != null) { methodPattern = wrapRegex(methodPattern); } this.classPattern = reformatClassPattern(classPattern, isRegex); this.methodPattern = methodPattern; isRegexTestClassPattern = isRegex; isRegexTestMethodPattern = isRegex; methodMatcher.sanityCheck(); } /** * The regex {@code pattern} is always unwrapped. * * @param type class or method * @param pattern pattern or regex * @param isRegex {@code true} if pattern is regex */ public ResolvedTest(Type type, String pattern, boolean isRegex) { pattern = tryBlank(pattern); final boolean isClass = type == Type.CLASS; description = description(isClass ? pattern : null, !isClass ? pattern : null, isRegex); if (isRegex && pattern != null) { pattern = wrapRegex(pattern); } classPattern = isClass ? reformatClassPattern(pattern, isRegex) : null; methodPattern = !isClass ? pattern : null; isRegexTestClassPattern = isRegex && isClass; isRegexTestMethodPattern = isRegex && !isClass; methodMatcher.sanityCheck(); } /** * Test class file pattern, e.g. org/**/Cat*.class
, or null if not any * and {@link #hasTestClassPattern()} returns false. * Other examples: org/animals/Cat*, org/animals/Ca?.class, %regex[Cat.class|Dog.*]
*
* '*' means zero or more characters
* '?' means one and only one character * * @return class pattern or regex */ public String getTestClassPattern() { return classPattern; } public boolean hasTestClassPattern() { return classPattern != null; } /** * Test method, e.g. "realTestMethod".
, or null if not any and {@link #hasTestMethodPattern()} returns false. * Other examples: test* or testSomethin? or %regex[testOne|testTwo] or %ant[testOne|testTwo]
*
* '*' means zero or more characters
* '?' means one and only one character * * @return method pattern or regex */ public String getTestMethodPattern() { return methodPattern; } public boolean hasTestMethodPattern() { return methodPattern != null; } public boolean isRegexTestClassPattern() { return isRegexTestClassPattern; } public boolean isRegexTestMethodPattern() { return isRegexTestMethodPattern; } public boolean isEmpty() { return classPattern == null && methodPattern == null; } public boolean matchAsInclusive(String testClassFile, String methodName) { testClassFile = tryBlank(testClassFile); methodName = tryBlank(methodName); return isEmpty() || alwaysInclusiveQuietly(testClassFile) || match(testClassFile, methodName); } public boolean matchAsExclusive(String testClassFile, String methodName) { testClassFile = tryBlank(testClassFile); methodName = tryBlank(methodName); return !isEmpty() && canMatchExclusive(testClassFile, methodName) && match(testClassFile, methodName); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ResolvedTest that = (ResolvedTest) o; return (classPattern == null ? that.classPattern == null : classPattern.equals(that.classPattern)) && (methodPattern == null ? that.methodPattern == null : methodPattern.equals(that.methodPattern)); } @Override public int hashCode() { int result = classPattern != null ? classPattern.hashCode() : 0; result = 31 * result + (methodPattern != null ? methodPattern.hashCode() : 0); return result; } @Override public String toString() { return isEmpty() ? "" : description; } private static String description(String clazz, String method, boolean isRegex) { String description; if (clazz == null && method == null) { description = null; } else if (clazz == null) { description = "#" + method; } else if (method == null) { description = clazz; } else { description = clazz + "#" + method; } return isRegex && description != null ? wrapRegex(description) : description; } private boolean canMatchExclusive(String testClassFile, String methodName) { return canMatchExclusiveMethods(testClassFile, methodName) || canMatchExclusiveClasses(testClassFile, methodName) || canMatchExclusiveAll(testClassFile, methodName); } private boolean canMatchExclusiveMethods(String testClassFile, String methodName) { return testClassFile == null && methodName != null && classPattern == null && methodPattern != null; } private boolean canMatchExclusiveClasses(String testClassFile, String methodName) { return testClassFile != null && methodName == null && classPattern != null && methodPattern == null; } private boolean canMatchExclusiveAll(String testClassFile, String methodName) { return testClassFile != null && methodName != null && (classPattern != null || methodPattern != null); } /** * Prevents {@link #match(String, String)} from throwing NPE in situations when inclusive returns true. * * @param testClassFile path to class file * @return {@code true} if examined class in null and class pattern exists */ private boolean alwaysInclusiveQuietly(String testClassFile) { return testClassFile == null && classPattern != null; } private boolean match(String testClassFile, String methodName) { return matchClass(testClassFile) && matchMethod(methodName); } private boolean matchClass(String testClassFile) { return classPattern == null || classMatcher.matchTestClassFile(testClassFile); } private boolean matchMethod(String methodName) { return methodPattern == null || methodName == null || methodMatcher.matchMethodName(methodName); } private static String tryBlank(String s) { if (s == null) { return null; } else { String trimmed = s.trim(); return StringUtils.isEmpty(trimmed) ? null : trimmed; } } private static String reformatClassPattern(String s, boolean isRegex) { if (s != null && !isRegex) { String path = convertToPath(s); path = fromFullyQualifiedClass(path); if (path != null && !path.startsWith(WILDCARD_PATH_PREFIX)) { path = WILDCARD_PATH_PREFIX + path; } return path; } else { return s; } } private static String convertToPath(String className) { if (isBlank(className)) { return null; } else { if (className.endsWith(JAVA_FILE_EXTENSION)) { className = className.substring(0, className.length() - JAVA_FILE_EXTENSION.length()) + CLASS_FILE_EXTENSION; } return className; } } static String wrapRegex(String unwrapped) { return REGEX_HANDLER_PREFIX + unwrapped + PATTERN_HANDLER_SUFFIX; } static String fromFullyQualifiedClass(String cls) { if (cls.endsWith(CLASS_FILE_EXTENSION)) { String className = cls.substring(0, cls.length() - CLASS_FILE_EXTENSION.length()); return className.replace('.', '/') + CLASS_FILE_EXTENSION; } else if (!cls.contains("/")) { if (cls.endsWith(WILDCARD_FILENAME_POSTFIX)) { String clsName = cls.substring(0, cls.length() - WILDCARD_FILENAME_POSTFIX.length()); return clsName.contains(".") ? clsName.replace('.', '/') + WILDCARD_FILENAME_POSTFIX : cls; } else { return cls.replace('.', '/'); } } else { return cls; } } private final class ClassMatcher { private volatile MatchPatterns cache; boolean matchTestClassFile(String testClassFile) { return ResolvedTest.this.isRegexTestClassPattern() ? matchClassRegexPatter(testClassFile) : matchClassPatter(testClassFile); } private MatchPatterns of(String... sources) { if (cache == null) { try { checkIllegalCharacters(sources); cache = from(sources); } catch (IllegalArgumentException e) { throwSanityError(e); } } return cache; } private boolean matchClassPatter(String testClassFile) { // @todo We have to use File.separator only because the MatchPatterns is using it internally - cannot // override. String classPattern = ResolvedTest.this.classPattern; if (separatorChar != '/') { testClassFile = testClassFile.replace('/', separatorChar); classPattern = classPattern.replace('/', separatorChar); } if (classPattern.endsWith(WILDCARD_FILENAME_POSTFIX) || classPattern.endsWith(CLASS_FILE_EXTENSION)) { return of(classPattern).matches(testClassFile, true); } else { String[] classPatterns = {classPattern + CLASS_FILE_EXTENSION, classPattern}; return of(classPatterns).matches(testClassFile, true); } } private boolean matchClassRegexPatter(String testClassFile) { String realFile = separatorChar == '/' ? testClassFile : testClassFile.replace('/', separatorChar); return of(classPattern).matches(realFile, true); } } private final class MethodMatcher { private volatile Pattern cache; boolean matchMethodName(String methodName) { if (ResolvedTest.this.isRegexTestMethodPattern()) { fetchCache(); return cache.matcher(methodName).matches(); } else { return matchPath(ResolvedTest.this.methodPattern, methodName); } } void sanityCheck() { if (ResolvedTest.this.isRegexTestMethodPattern() && ResolvedTest.this.hasTestMethodPattern()) { try { checkIllegalCharacters(ResolvedTest.this.methodPattern); fetchCache(); } catch (IllegalArgumentException e) { throwSanityError(e); } } } private void fetchCache() { if (cache == null) { int from = REGEX_HANDLER_PREFIX.length(); int to = ResolvedTest.this.methodPattern.length() - PATTERN_HANDLER_SUFFIX.length(); String pattern = ResolvedTest.this.methodPattern.substring(from, to); cache = compile(pattern); } } } private static void checkIllegalCharacters(String... expressions) { for (String expression : expressions) { if (expression.contains("#")) { throw new IllegalArgumentException("Extra '#' in regex: " + expression); } } } private static void throwSanityError(IllegalArgumentException e) { throw new IllegalArgumentException( "%regex[] usage rule violation, valid regex rules:\n" + " * # - " + "where both regex can be individually evaluated as a regex\n" + " * you may use at most 1 '#' to in one regex filter. " + e.getLocalizedMessage(), e); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy