aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Eluard <[email protected]>2013-12-17 05:55:29 -0800
committerJulien Eluard <[email protected]>2013-12-17 05:55:29 -0800
commit82add49bc695e5d46512cd52dc98e889763298f1 (patch)
tree86ef8e478e51f0731352163562e04dc806153625
parentf89c0a958b01ae732ac16c1dfdae15a9715f735a (diff)
parent6be976ede44ea70e9d8317d33c35cef147bb63c1 (diff)
Merge pull request #15 from LarsSommer/master
Merging of enhancement of excluding and including classes. Closes #7.
-rwxr-xr-xREADME.md15
-rwxr-xr-xapi/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java93
-rw-r--r--api/src/test/java/org/semver/jardiff/DifferenceAccumulatingHandlerTest.java299
3 files changed, 390 insertions, 17 deletions
diff --git a/README.md b/README.md
index f01a9a6..969ea64 100755
--- a/README.md
+++ b/README.md
@@ -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" ) );
+ }
+}