001: // This file is part of KeY - Integrated Deductive Software Design
002: // Copyright (C) 2001-2007 Universitaet Karlsruhe, Germany
003: // Universitaet Koblenz-Landau, Germany
004: // Chalmers University of Technology, Sweden
005: //
006: // The KeY system is protected by the GNU General Public License.
007: // See LICENSE.TXT for details.
008: //
009: // This file is part of KeY - Integrated Deductive Software Design
010: // Copyright (C) 2001-2004 Universitaet Karlsruhe, Germany
011: // Universitaet Koblenz-Landau, Germany
012: // Chalmers University of Technology, Sweden
013: //
014: // The KeY system is protected by the GNU General Public License.
015: // See LICENSE.TXT for details.
016: package de.uka.ilkd.key.util;
017:
018: import java.io.File;
019: import java.io.FileFilter;
020: import java.lang.reflect.Constructor;
021: import java.lang.reflect.Method;
022: import java.lang.reflect.Modifier;
023: import java.util.Iterator;
024: import java.util.LinkedList;
025:
026: /**
027: * This class tests, if design principles have been hurt. Therefore it
028: * makes use of reflection.
029: */
030:
031: public class DesignTests {
032:
033: private static final File binaryPath = new File(System
034: .getProperty("key.home")
035: + File.separator + "system" + File.separator + "binary");
036:
037: private Class[] allClasses;
038:
039: private String message = "";
040:
041: /**
042: * Creates an instance used to test if design principles have been
043: * hurt.
044: * @param binaryPath String with path to all
045: * <code>classname.class</code> files to test
046: */
047: public DesignTests() {
048: }
049:
050: /**
051: * collects all found in the given directory
052: * @param directory a File denoting the directory where to look for
053: * the classes
054: * @return array of found class files
055: */
056: private static Class[] getClasses(File directory) {
057: System.out.print(".");
058: File[] classFiles = directory.listFiles(new FileFilter() {
059: public boolean accept(File fileName) {
060: return fileName.getAbsolutePath().indexOf("de/") != -1
061: && fileName.getAbsolutePath()
062: .endsWith(".class");
063: }
064: });
065:
066: Class[] classes = new Class[(classFiles == null) ? 0
067: : classFiles.length];
068: for (int i = 0; i < classes.length; i++) {
069: String absoluteName = classFiles[i].getAbsolutePath();
070: String className = absoluteName.substring(
071: absoluteName.indexOf("de/")).replace(
072: File.separatorChar, '.');
073: className = className.substring(0, className
074: .indexOf(".class"));
075:
076: try {
077: classes[i] = ClassLoader.getSystemClassLoader()
078: .loadClass(className);
079: } catch (ClassNotFoundException cnfe) {
080: System.err.println("That's weiry. Cannot find class "
081: + className + "\n" + cnfe);
082: } catch (NoClassDefFoundError ncdfe) {
083: System.err.println(className + " skipped. "
084: + "Please check your classpath.");
085: }
086: }
087:
088: return classes;
089: }
090:
091: /**
092: * adds all elements of <code>source</code> to <code>target</code>
093: * @param source the array whose elements have to inserted
094: * @param target the LinkedList where to insert the elements of the
095: * source
096: */
097: private static void copyToList(Object[] source, LinkedList target) {
098: for (int i = 0; i < source.length; i++) {
099: target.add(source[i]);
100: }
101: }
102:
103: /**
104: * iterates through the directory structure starting at
105: * <code>topDir</code> and collects all found
106: * classes.
107: * @param topDir File giving the directory where to start the
108: * iteration
109: * @return all found classes including the ones in
110: * <code>topDir</code>
111: */
112: public static Class[] getAllClasses(File topDir) {
113: LinkedList result = new LinkedList();
114: copyToList(getClasses(topDir), result);
115:
116: File[] subDirectories = topDir.listFiles(new FileFilter() {
117: public boolean accept(File fileName) {
118: return fileName.isDirectory();
119: }
120: });
121: if (subDirectories == null) {
122: return new Class[0];
123: } else {
124: for (int i = 0; i < subDirectories.length; i++) {
125: copyToList(getAllClasses(subDirectories[i]), result);
126: }
127: return (Class[]) result.toArray(new Class[result.size()]);
128: }
129: }
130:
131: /** prints an enumeration of of those classes that hurt a design principle */
132: private void printBadClasses(LinkedList badClasses) {
133: Iterator it = badClasses.iterator();
134: if (it.hasNext()) {
135: System.out.println("Bad classes:");
136: while (it.hasNext()) {
137: System.out.println("\t" + it.next());
138: }
139: }
140: }
141:
142: /**
143: * some operator classes are allowed to have greater visibility
144: */
145: private boolean exception(Class cl) {
146: return (cl == de.uka.ilkd.key.logic.op.Junctor.class); // ASMKEY extends Junctor
147: }
148:
149: /**
150: * subclass of Op should have at most package private constructors
151: * (exception: metaop)
152: */
153: public LinkedList testConstructorInOpSubclasses() {
154: LinkedList badClasses = new LinkedList();
155: for (int i = 0; i < allClasses.length; i++) {
156: if (allClasses[i] != de.uka.ilkd.key.logic.op.Op.class
157: && (de.uka.ilkd.key.logic.op.Op.class)
158: .isAssignableFrom(allClasses[i])
159: && !(de.uka.ilkd.key.logic.op.AbstractMetaOperator.class)
160: .isAssignableFrom(allClasses[i])) {
161: Constructor[] cons = allClasses[i].getConstructors();
162: for (int j = 0; j < cons.length; j++) {
163: int mods = cons[j].getModifiers();
164: if ((Modifier.isProtected(mods) && !exception(allClasses[i]))
165: || Modifier.isPublic(mods)) {
166: badClasses.add(allClasses[i]);
167: }
168: }
169: }
170: }
171: if (badClasses.size() > 0) {
172: message = "Constructors of subclasses of 'Op' ";
173: message += "must have package private or private";
174: message += "(except MetaOperators).\n";
175: }
176: return badClasses;
177: }
178:
179: /**
180: * subclass of Term must be private or package private
181: */
182: public LinkedList testTermSubclassVisibility() {
183: LinkedList badClasses = new LinkedList();
184: for (int i = 0; i < allClasses.length; i++) {
185: if (allClasses[i] != de.uka.ilkd.key.logic.Term.class
186: && (de.uka.ilkd.key.logic.Term.class)
187: .isAssignableFrom(allClasses[i])) {
188: int mods = allClasses[i].getModifiers();
189: if (Modifier.isProtected(mods)
190: || Modifier.isPublic(mods)) {
191: badClasses.add(allClasses[i]);
192: }
193: }
194: }
195: if (badClasses.size() > 0) {
196: message = "Visibility of subclasses of Term ";
197: message += "must be package private or private.\n";
198: }
199: return badClasses;
200: }
201:
202: public void runTests() {
203: LinkedList badClasses;
204: Method[] meth = getClass().getMethods();
205: System.out.println("[Design Conformance Tests]");
206: System.out.println("[Collecting classes. Please wait...]");
207: allClasses = getAllClasses(binaryPath);
208: System.out.println("\n[Testing " + allClasses.length
209: + " classes.]");
210: int failures = 0;
211: int testcases = 0;
212: for (int i = 0; i < meth.length; i++) {
213: if (meth[i].getName().startsWith("test")) {
214: try {
215: message = ".";
216: badClasses = (LinkedList) meth[i]
217: .invoke(this , null);
218: System.out.print(message);
219: testcases++;
220: failures += badClasses.size() > 0 ? 1 : 0;
221: printBadClasses(badClasses);
222: } catch (Exception e) {
223: System.err.println("Could not invoke method "
224: + meth);
225: }
226: }
227: }
228: System.out.println("\n[Tests finished. ("
229: + (testcases - failures) + "/" + testcases
230: + ") tests passed.]");
231: }
232:
233: public static void main(String[] args) {
234: DesignTests tests = new DesignTests();
235: tests.runTests();
236: }
237:
238: }
|