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

org.apache.maven.surefire.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
package org.apache.maven.surefire.testset;

/*
 * 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.
 */

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

import java.util.regex.Pattern;

import static java.io.File.separatorChar;
import static java.util.regex.Pattern.compile;
import static org.apache.maven.shared.utils.StringUtils.isBlank;
import static org.apache.maven.shared.utils.io.MatchPatterns.from;
import static org.apache.maven.shared.utils.io.SelectorUtils.PATTERN_HANDLER_SUFFIX;
import static org.apache.maven.shared.utils.io.SelectorUtils.REGEX_HANDLER_PREFIX;
import static org.apache.maven.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 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 pattern is always unwrapped. */ 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 */ 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 */ 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. */ 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