diff options
author | Julien Eluard <[email protected]> | 2013-12-17 05:55:29 -0800 |
---|---|---|
committer | Julien Eluard <[email protected]> | 2013-12-17 05:55:29 -0800 |
commit | 82add49bc695e5d46512cd52dc98e889763298f1 (patch) | |
tree | 86ef8e478e51f0731352163562e04dc806153625 | |
parent | f89c0a958b01ae732ac16c1dfdae15a9715f735a (diff) | |
parent | 6be976ede44ea70e9d8317d33c35cef147bb63c1 (diff) |
Merge pull request #15 from LarsSommer/master
Merging of enhancement of excluding and including classes. Closes #7.
-rwxr-xr-x | README.md | 15 | ||||
-rwxr-xr-x | api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java | 93 | ||||
-rw-r--r-- | api/src/test/java/org/semver/jardiff/DifferenceAccumulatingHandlerTest.java | 299 |
3 files changed, 390 insertions, 17 deletions
@@ -56,9 +56,11 @@ Options: --check,-c Check the compatibility of two jars. --diff,-d Show the differences between two jars. --excludes EXCLUDE;... Semicolon separated list of full qualified class names + or partly qualified class names with wild cards to be excluded. --help,-h Show this help and exit. --includes INCLUDE;... Semicolon separated list of full qualified class names + or partly qualified class names with wild cards to be included. --infer,-i Infer the version of the new jar based on the previous jar. @@ -82,6 +84,19 @@ Class org.project.MyClass2 Changed Field field2 removed: final ``` +### Excludes / Includes + +In- or exclude classes for the validation by specifying a fully qualified +class name or using wild cards. There are two wild cards: `*` and `**`. +`*` is a wild card for an arbitrary number of characters but at most one +folder hierarchy. +`**` is a wild card for an arbitrary number of characters and an arbitrary +number of folder hierarchies. + +``` +% java -jar semver.jar --excludes **/MyClass; org/**/MyClass; org/**/*Class; +``` + ### Check Check compatibility type between two JARs. diff --git a/api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java b/api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java index 4cf6cc3..e78c5ea 100755 --- a/api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java +++ b/api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java @@ -20,6 +20,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.annotation.Nonnull; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.osjava.jardiff.AbstractDiffHandler; import org.osjava.jardiff.ClassInfo; @@ -209,23 +211,80 @@ public final class DifferenceAccumulatingHandler extends AbstractDiffHandler { * * @return */ - private boolean isClassConsidered(final String className) { - for (final String exclude : this.excludes) { - if (className.startsWith(exclude)) { - return false; - } - } - - if (!this.includes.isEmpty()) { - for (final String include : this.includes) { - if (className.startsWith(include)) { - return true; - } - } - return false; - } - return true; - } + protected boolean isClassConsidered( final String className ) { + for ( String exclude : this.excludes ) { + if ( exclude.contains( "/**/" ) ) { + exclude = exclude.replaceAll( "/\\*\\*/", "{0,1}**/" ); + } + if ( exclude.contains( "/*/" ) ) { + exclude = exclude.replaceAll( "/\\*/", "{0,1}*/{0,1}" ); + } + Pattern excludePattern = simplifyRegularExpression( exclude, false ); + + Matcher excludeMatcher = excludePattern.matcher( className ); + + while ( excludeMatcher.find() ) { + return false; + } + } + if ( !this.includes.isEmpty() ) { + for ( String include : this.includes ) { + if ( include.contains( "/**/" ) ) { + include = include.replaceAll( "/\\*\\*/", "{0,1}**/" ); + } + if ( include.contains( "/*/" ) ) { + include = include.replaceAll( "/\\*/", "{0,1}*/{0,1}" ); + } + Pattern includePattern = simplifyRegularExpression( include, false ); + Matcher includeMatcher = includePattern.matcher( className ); + + while ( includeMatcher.find() ) { + return false; + } + } + } + return true; + } + + /** + * + * Simplifies the given regular expression by the following pattern:<br> + * All substrings not containing "{0,1}", "*" and "?" get surrounded by "\\Q" and "\\E". Then all occurrences of + * "**" are replaced by ".*", "*" with "[^/]*" and all occurrences of "?" are replaced by "." In the end a "$" will + * be appended. + * + * @param regEx the regular expression which is in a simple form. + * @return the simple regular expression converted to a normal regular expression. + */ + private static Pattern simplifyRegularExpression( final String regEx, final boolean caseSensitive ) { + final StringBuilder strBuild = new StringBuilder(); + final Pattern p = Pattern.compile( "\\{0,1\\}|\\*|\\?|[[^*^?^{^}]|^]+", Pattern.CASE_INSENSITIVE ); + final Matcher m = p.matcher( regEx ); + + while ( m.find() ) { + final String token = m.group(); + if ( token.equals( "*" ) || token.equals( "?" ) ) { //$NON-NLS-1$ //$NON-NLS-2$ + strBuild.append( token ); + } else if ( token.equals( "{0,1}" ) ) { + strBuild.append( "/" ); + strBuild.append( token ); + } else { + // Surround all tokens that are not "*" or "?" with "\\Q" and \\E" + strBuild.append( "\\Q" ).append( token ).append( "\\E" ); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + // Replace all "*" and "?" with .* and .+ + strBuild.append( "$" ); + String result = strBuild.toString(); + result = result.replaceAll( "(?<!\\*)\\*(?!\\*)", "[^/]*" ); + result = result.replaceAll( "[\\*][\\s]*[\\*]", ".\\*" ); + result = result.replaceAll( "\\?", "." ); + if ( caseSensitive ) { + return Pattern.compile( result ); + } else { + return Pattern.compile( result, Pattern.CASE_INSENSITIVE ); + } + } public Delta getDelta() { return new Delta(this.differences); diff --git a/api/src/test/java/org/semver/jardiff/DifferenceAccumulatingHandlerTest.java b/api/src/test/java/org/semver/jardiff/DifferenceAccumulatingHandlerTest.java new file mode 100644 index 0000000..47b1247 --- /dev/null +++ b/api/src/test/java/org/semver/jardiff/DifferenceAccumulatingHandlerTest.java @@ -0,0 +1,299 @@ +/** + * Copyright 2012 Julien Eluard This project includes software developed by Julien Eluard: https://github.com/jeluard/ + * + * Licensed 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.semver.jardiff; + + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; + + +public class DifferenceAccumulatingHandlerTest { + + @Test + public void shouldClassBeNotConsideredWithTwoPlaceholdersBeforeAndBehind() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "**/java/**" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeConsideredWithOnePlaceholderBeforeAndBehind() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "*/java/*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeNotConsideredWithTwoPlaceholderAfter() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "java/**" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeConsideredWithTwoPlaceholderBefore() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "**/java" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeConsideredWithOnePlaceholderAfter() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "java/*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeConsideredWithOnePlaceholderBefore() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "*/java" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeNotConsideredWithTwoPlaceholderInside() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "de/**/java/**" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeNotConsideredWithOnePlaceholderInside() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "de/*/java/**" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeConsideredWithOnePlaceholderInside() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "de/*/classImpl" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeConsideredWithTwoPlaceholderInsideAndSpecificEnd() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "java/**/Impl" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassNotBeConsideredWithOnePlaceholderInsideAndSpecificEnd() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "java/*/*Impl" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeConsideredWithOnePlaceholderInsideAndSpecificEnd() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "test/*/*Impl" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl" ) ); + } + + @Test + public void shouldClassBeConsideredWithTwoPlaceholderInsidePlusHashAndUnspecificEnd3() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "test/*/*Impl/*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/Impl2/code" ) ); + } + + @Test + public void shouldClassNotBeConsideredWithTwoPlaceholderInsidePlusHashAndUnspecificEnd2() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "java/*/*Impl/*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl/code" ) ); + } + + @Test + public void shouldClassBeConsideredWithTwoPlaceholderInsidePlusHashAndUnspecificEnd() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "test/*/*Impl/*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl/code/Implem" ) ); + } + + @Test + public void shouldClassNotBeConsideredWithTwoPlaceholderInsidePlusHashAndUnspecificEnd() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "java/*/*Impl/*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl/code" ) ); + } + + @Test + public void shouldClassNotBeConsideredWithOnePlaceholderInsideAndUnspecificEnd() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "java/*/*Impl*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/classImpl2" ) ); + } + + @Test + public void shouldClassNotBeConsideredWithTwoPlaceholderInsideAndUnspecificEnd() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "java/**/Impl*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/Impl" ) ); + } + + @Test + public void shouldClassNotBeConsideredWithTwoPlaceholderInsideAndUnspecificEndWithNoUseOfPlaceholders() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "regex/**/Impl*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/Impl" ) ); + } + + @Test + public void shouldClassBeConsideredWithTwoPlaceholderInsideAndUnspecificEndWithNoUseOfPlaceholders() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "regex/**/Impl*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should be considered: ", true, new DifferenceAccumulatingHandler( inclusionSet, + exclusionSet ).isClassConsidered( "de/test/java/regex/test" ) ); + } + + @Test + public void shouldClassNotBeConsideredWithTwoPlaceholderInsideAndUnspecificEndWith() { + + List<String> inclusions = new ArrayList<String>(); + Set<String> inclusionSet = new HashSet<String>( inclusions ); + List<String> exclusions = new ArrayList<String>(); + exclusions.add( "test/**/Impl*" ); + Set<String> exclusionSet = new HashSet<String>( exclusions ); + + Assert.assertEquals( "Class should not be considered: ", false, new DifferenceAccumulatingHandler( + inclusionSet, exclusionSet ).isClassConsidered( "de/test/java/regex/Impl" ) ); + } +} |