Skip to content

Commit

Permalink
Issue #40: Refactor the pattern components into separate class (Patte…
Browse files Browse the repository at this point in the history
…rn is not a valid key in hashmaps)

Also restructure testing infrastructure
  • Loading branch information
uschindler committed Apr 11, 2015
1 parent a29c91f commit 1020ac4
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 41 deletions.
25 changes: 16 additions & 9 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,10 @@
</condition>
<echo level="warn" taskname="check-ivy" message="${ivy.version-message}"/>
<ivy:cachepath pathid="path.main-build" conf="build" log="${ivy.logging}"/>
<ivy:cachepath pathid="path.main-bundle" conf="bundle" log="${ivy.logging}"/>
<ivy:cachepath pathid="path.test" conf="test" log="${ivy.logging}"/>
<path id="path.main-run">
<path refid="path.main-build"/>
<path refid="path.main-bundle"/>
<pathelement path="build/main"/>
</path>
<path id="path.tools-build" refid="path.main-run"/>
Expand All @@ -174,13 +175,20 @@
<pathelement path="build/tools"/>
</path>
<path id="path.junit-build">
<path refid="path.test"/>
<path refid="path.main-run"/>
<path refid="path.test"/>
</path>
<path id="path.junit-run">
<path refid="path.junit-build"/>
<pathelement path="build/test"/>
</path>
<path id="path.all">
<path refid="path.main-build"/>
<path refid="path.test"/>
<pathelement path="build/main"/>
<pathelement path="build/tools"/>
<pathelement path="build/test"/>
</path>
</target>

<target name="-install-tasks" depends="-init" unless="installed.tasks">
Expand Down Expand Up @@ -422,11 +430,7 @@

<target name="-check-myself" depends="compile,compile-tools,compile-test,-install-forbiddenapi-task">
<forbiddenapis internalRuntimeForbidden="true" failOnUnsupportedJava="false">
<classpath>
<path refid="path.main-run"/>
<path refid="path.junit-run"/>
<path refid="path.tools-run"/>
</classpath>
<classpath refid="path.all"/>
<fileset dir="build/main"/>
<fileset dir="build/tools"/>
<fileset dir="build/test"/>
Expand Down Expand Up @@ -488,11 +492,14 @@

<target name="-junit" depends="compile-test">
<mkdir dir="${test-results-dir}"/>
<junit haltonfailure="yes" includeantruntime="no">
<junit haltonfailure="yes" fork="yes" forkmode="once">
<classpath refid="path.junit-run"/>
<formatter type="brief" usefile="false" />
<formatter type="xml"/>
<batchtest fork="no" todir="${test-results-dir}">
<assertions>
<enable package="de.thetaphi.forbiddenapis"/>
</assertions>
<batchtest todir="${test-results-dir}">
<fileset dir="src/test/java" includes="**/*Test.java"/>
</batchtest>
</junit>
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public static String binaryToInternal(String clazz) {
return clazz.replace('.', '/');
}

/** Returns true is a string is a glob pattern */
public static boolean isGlob(String s) {
return s.indexOf('*') >= 0 || s.indexOf('?') >= 0;
}
Expand Down Expand Up @@ -88,7 +89,7 @@ public static Pattern glob2Pattern(String glob) {
regex.append(c);
}
}
return Pattern.compile(regex.toString());
return Pattern.compile(regex.toString(), 0);
}

}
5 changes: 2 additions & 3 deletions src/main/java/de/thetaphi/forbiddenapis/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -80,7 +79,7 @@ public abstract class Checker implements RelatedClassLookup {
// key is the internal name (slashed):
final Map<String,String> forbiddenClasses = new HashMap<String,String>();
// key is pattern to binary class name:
final Map<Pattern,String> forbiddenClassPatterns = new LinkedHashMap<Pattern,String>();
final Set<ClassPatternRule> forbiddenClassPatterns = new LinkedHashSet<ClassPatternRule>();
// descriptors (not internal names) of all annotations that suppress:
final Set<String> suppressAnnotations = new HashSet<String>();

Expand Down Expand Up @@ -282,7 +281,7 @@ private void addSignature(final String line, final String defaultMessage, final
if (method != null || field != null) {
throw new ParseException(String.format(Locale.ENGLISH, "Class level glob pattern cannot be combined with methods/fields: %s", signature));
}
forbiddenClassPatterns.put(AsmUtils.glob2Pattern(clazz), printout);
forbiddenClassPatterns.add(new ClassPatternRule(clazz, printout));
} else {
final ClassSignature c;
try {
Expand Down
67 changes: 67 additions & 0 deletions src/main/java/de/thetaphi/forbiddenapis/ClassPatternRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package de.thetaphi.forbiddenapis;

/*
* (C) Copyright Uwe Schindler (Generics Policeman) and others.
*
* 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.
*/

import java.util.regex.Pattern;

public final class ClassPatternRule {

public final Pattern pattern;
public final String printout;

public ClassPatternRule(String glob, String printout) {
if (glob == null || printout == null) {
throw new NullPointerException();
}
this.pattern = AsmUtils.glob2Pattern(glob);
assert this.pattern.flags() == 0 : "the pattern should have no flags (must be case-sensitive,...)";
this.printout = printout;
}

public boolean matches(String className) {
return pattern.matcher(className).matches();
}

// equals() / hashcode() use the string representation of pattern for comparisons
// (Pattern unfortunately does not implement equals/hashCode)

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + pattern.pattern().hashCode();
result = prime * result + printout.hashCode();
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
ClassPatternRule other = (ClassPatternRule) obj;
if (!pattern.pattern().equals(other.pattern.pattern())) return false;
if (!printout.equals(other.printout)) return false;
return true;
}

@Override
public String toString() {
return "ClassPatternRule [pattern=" + pattern + ", printout=" + printout + "]";
}

}
11 changes: 5 additions & 6 deletions src/main/java/de/thetaphi/forbiddenapis/ClassScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
Expand Down Expand Up @@ -58,7 +57,7 @@ final class ClassScanner extends ClassVisitor {
// key is the internal name (slashed):
final Map<String,String> forbiddenClasses;
// key is pattern to binary class name:
final Map<Pattern,String> forbiddenClassPatterns;
final Iterable<ClassPatternRule> forbiddenClassPatterns;
// descriptors (not internal names) of all annotations that suppress:
final Set<String> suppressAnnotations;

Expand All @@ -76,7 +75,7 @@ final class ClassScanner extends ClassVisitor {
boolean classSuppressed = false;

public ClassScanner(RelatedClassLookup lookup,
final Map<String,String> forbiddenClasses, final Map<Pattern,String> forbiddenClassPatterns,
final Map<String,String> forbiddenClasses, final Iterable<ClassPatternRule> forbiddenClassPatterns,
final Map<String,String> forbiddenMethods, final Map<String,String> forbiddenFields,
final Set<String> suppressAnnotations,
final boolean internalRuntimeForbidden) {
Expand Down Expand Up @@ -115,9 +114,9 @@ String checkClassUse(Type type, String what, boolean deep) {
return String.format(Locale.ENGLISH, "Forbidden %s use: %s", what, printout);
}
final String binaryClassName = type.getClassName();
for (final Map.Entry<Pattern,String> pat : forbiddenClassPatterns.entrySet()) {
if (pat.getKey().matcher(binaryClassName).matches()) {
return String.format(Locale.ENGLISH, "Forbidden %s use: %s", what, pat.getValue());
for (final ClassPatternRule r : forbiddenClassPatterns) {
if (r.matches(binaryClassName)) {
return String.format(Locale.ENGLISH, "Forbidden %s use: %s", what, r.printout);
}
}
if (deep && internalRuntimeForbidden) {
Expand Down
4 changes: 2 additions & 2 deletions src/test/antunit/TestClassDeclaration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

<target name="testForbiddenExtends">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
java.lang.Object @ Every class is not allowed!
</forbiddenapis>
Expand All @@ -31,7 +31,7 @@

<target name="testForbiddenInterfaces">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis dir="${antunit.tools.classes}" classpathref="path.main-run">
<forbiddenapis dir="${antunit.tools.classes}" classpathref="path.all">
org.objectweb.asm.Opcodes @ demo interface
</forbiddenapis>
</au:expectfailure>
Expand Down
8 changes: 4 additions & 4 deletions src/test/antunit/TestFileSignatures.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

<target name="testAttribute">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis signaturesfile="signatures1.txt" classpathref="path.main-run">
<forbiddenapis signaturesfile="signatures1.txt" classpathref="path.all">
<fileset refid="main.classes"/>
</forbiddenapis>
</au:expectfailure>
Expand All @@ -29,7 +29,7 @@

<target name="testFileSet">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
<signaturesFileset file="signatures1.txt"/>
</forbiddenapis>
Expand All @@ -39,7 +39,7 @@

<target name="testFileList">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
<signaturesFilelist dir="." files="signatures1.txt"/>
</forbiddenapis>
Expand All @@ -49,7 +49,7 @@

<target name="testFileResource">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
<signaturesFile file="signatures1.txt"/>
</forbiddenapis>
Expand Down
6 changes: 3 additions & 3 deletions src/test/antunit/TestFinalJAR.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<taskdef name="forbiddenapis-jar" classname="de.thetaphi.forbiddenapis.AntTask" classpath="${jar-file}"/>

<target name="testMySelfWithFinalJAR1">
<forbiddenapis-jar internalRuntimeForbidden="true" classpathref="path.main-run">
<forbiddenapis-jar internalRuntimeForbidden="true" classpathref="path.all">
<fileset dir="${antunit.main.classes}"/>
<bundledsignatures name="jdk-unsafe-${jdk.version}"/>
<bundledsignatures name="jdk-deprecated-${jdk.version}"/>
Expand All @@ -28,7 +28,7 @@
</target>

<target name="testMySelfWithFinalJAR2">
<forbiddenapis-jar dir="${antunit.main.classes}" internalRuntimeForbidden="true" classpathref="path.main-run">
<forbiddenapis-jar dir="${antunit.main.classes}" internalRuntimeForbidden="true" classpathref="path.all">
<bundledsignatures name="jdk-unsafe-${jdk.version}"/>
<bundledsignatures name="jdk-deprecated-${jdk.version}"/>
</forbiddenapis-jar>
Expand All @@ -37,7 +37,7 @@

<target name="testMySelfWithAntLib">
<taskdef uri="antlib:de.thetaphi.forbiddenapis" classpath="${jar-file}"/>
<fa:forbiddenapis xmlns:fa="antlib:de.thetaphi.forbiddenapis" dir="${antunit.main.classes}" internalRuntimeForbidden="true" classpathref="path.main-run">
<fa:forbiddenapis xmlns:fa="antlib:de.thetaphi.forbiddenapis" dir="${antunit.main.classes}" internalRuntimeForbidden="true" classpathref="path.all">
<bundledsignatures name="jdk-unsafe-${jdk.version}"/>
<bundledsignatures name="jdk-deprecated-${jdk.version}"/>
</fa:forbiddenapis>
Expand Down
16 changes: 8 additions & 8 deletions src/test/antunit/TestInlineSignatures.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

<target name="testForbiddenClassWithMessage">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
java.awt.Color @ Color is disallowed, thats not bad, because ANT has no colors...
java.lang.String @ You are crazy that you disallow strings
Expand All @@ -31,7 +31,7 @@

<target name="testForbiddenClassPatternWithMessage">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
java.util.Array* @ You are crazy that you disallow all Array*
java.lang.** @ You are crazy that you disallow all java.lang
Expand All @@ -43,7 +43,7 @@

<target name="testForbiddenClassWithDefaultMessage">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
@defaultMessage Let's disable some of AWT
java.awt.BorderLayout
Expand All @@ -57,7 +57,7 @@

<target name="testForbiddenMethodWithMessage">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
java.lang.String#substring(int,int) @ You are crazy that you disallow substrings
</forbiddenapis>
Expand All @@ -67,7 +67,7 @@

<target name="testForbiddenFieldWithMessage">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
java.util.Locale#ENGLISH @ We are speaking chinese here!
</forbiddenapis>
Expand All @@ -77,7 +77,7 @@

<target name="testFailOnMissing">
<au:expectfailure expectedMessage="Parsing signatures failed: Class 'foo.bar.ForbiddenApis' not found on classpath while parsing signature: foo.bar.ForbiddenApis#testMethod()">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
foo.bar.ForbiddenApis#testMethod() @ should fail here
java.lang.String#forbiddenFoobarMethod() @ should also fail
Expand All @@ -87,7 +87,7 @@
</target>

<target name="testDontFailOnMissing">
<forbiddenapis classpathref="path.main-run">
<forbiddenapis classpathref="path.all">
<fileset refid="main.classes"/>
@ignoreUnresolvable
foo.bar.ForbiddenApis#testMethod() @ should be ignored
Expand All @@ -101,7 +101,7 @@
</target>

<target name="testDontFailOnMissingWithAttribute">
<forbiddenapis classpathref="path.main-run" failOnUnresolvableSignatures="false">
<forbiddenapis classpathref="path.all" failOnUnresolvableSignatures="false">
<fileset refid="main.classes"/>
foo.bar.ForbiddenApis#testMethod() @ should be ignored
java.lang.String#forbiddenFoobarMethod() @ should be ignored
Expand Down
Loading

0 comments on commit 1020ac4

Please sign in to comment.