KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hansel > AntCoverageTask


1 package org.hansel;
2
3 import java.io.File JavaDoc;
4 import java.io.FileFilter JavaDoc;
5 import java.io.FilenameFilter JavaDoc;
6 import java.lang.reflect.Method JavaDoc;
7 import java.lang.reflect.Modifier JavaDoc;
8 import java.text.NumberFormat JavaDoc;
9 import java.util.Comparator JavaDoc;
10 import java.util.Enumeration JavaDoc;
11 import java.util.HashSet JavaDoc;
12 import java.util.Iterator JavaDoc;
13 import java.util.Set JavaDoc;
14 import java.util.Stack JavaDoc;
15 import java.util.StringTokenizer JavaDoc;
16 import java.util.TreeSet JavaDoc;
17
18 import junit.framework.Test;
19 import junit.framework.TestSuite;
20
21 import org.apache.tools.ant.AntClassLoader;
22 import org.apache.tools.ant.BuildException;
23 import org.apache.tools.ant.Task;
24 import org.apache.tools.ant.types.Path;
25 import org.apache.tools.ant.types.Reference;
26
27 public class AntCoverageTask extends Task {
28     private static final String JavaDoc SUITE_METHOD = "suite";
29     private static final Class JavaDoc[] SUITE_TYPES = new Class JavaDoc[0];
30     private static final Object JavaDoc[] SUITE_PARAMS = new Object JavaDoc[0];
31
32     private static final FileFilter JavaDoc DIR_FILTER =
33         new FileFilter JavaDoc() {
34             public boolean accept(File JavaDoc path) {
35                 return path.isDirectory();
36             }
37         };
38
39     private static final FilenameFilter JavaDoc CLASS_FILTER =
40         new FilenameFilter JavaDoc() {
41             public boolean accept(File JavaDoc dir, String JavaDoc name) {
42                 return (name.endsWith(".class")
43                         && (name.indexOf("$") < 0));
44             }
45         };
46
47     private String JavaDoc packages;
48     
49     private Path classpath;
50     private String JavaDoc classFilePath;
51
52     private String JavaDoc excludePackages;
53
54     private boolean printStats;
55
56     private ClassLoader JavaDoc cl;
57     private ClassLoader JavaDoc oldCl;
58
59     private int numTests;
60     private int numCoverageTests;
61
62     public AntCoverageTask() {
63         numTests = 0;
64         numCoverageTests = 0;
65         printStats = true;
66     }
67
68     /**
69      * Set the classpath to be used when running the Java class
70      *
71      * @param s an Ant Path object containing the classpath.
72      */

73     public void setClasspath(Path s) {
74         createClasspath().append(s);
75     }
76     
77     /**
78      * Adds a path to the classpath.
79      */

80     public Path createClasspath() {
81         classpath = new Path(getProject());
82         return classpath;
83     }
84
85     /**
86      * Classpath to use, by reference.
87      */

88     public void setClasspathRef(Reference r) {
89         createClasspath().setRefid(r);
90     }
91
92     public void setStats(boolean printStats) {
93         this.printStats = printStats;
94     }
95
96     public void setClassFilePath(String JavaDoc classFilePath) {
97         this.classFilePath = classFilePath;
98     }
99
100     public void setPackages(String JavaDoc packages) {
101         this.packages = packages;
102     }
103
104     public void setExcludePackages(String JavaDoc excludePackages) {
105         this.excludePackages = excludePackages;
106     }
107
108     private void createClassloader() throws BuildException {
109         Path path = new Path(this.getProject());
110         path.setLocation(new File JavaDoc(classFilePath));
111
112         if (classpath != null) {
113             classpath.append(path);
114         } else {
115             classpath = path;
116         }
117
118         cl = new AntClassLoader(getClass().getClassLoader(),
119                                 getProject(), classpath, true);
120
121         oldCl = Thread.currentThread().getContextClassLoader();
122         Thread.currentThread().setContextClassLoader(cl);
123     }
124
125     private void resetClassLoader() {
126         Thread.currentThread().setContextClassLoader(oldCl);
127     }
128
129     private Set JavaDoc createSortedSet() {
130         return new TreeSet JavaDoc(new Comparator JavaDoc() {
131                 public int compare(Object JavaDoc o1, Object JavaDoc o2) {
132                     return o1.toString().compareTo(o2.toString());
133                 }
134
135                 public boolean equals(Object JavaDoc obj) {
136                     return false;
137                 }
138             });
139     }
140
141     private String JavaDoc normalize(String JavaDoc packageName) {
142         while (packageName.endsWith("*")) {
143             packageName = packageName.substring(0, packageName.length() - 1);
144          }
145
146         if (packageName.endsWith(File.separator)) {
147             packageName = packageName.substring(0, packageName.length() - 1);
148         }
149
150         return packageName;
151     }
152
153     private File JavaDoc getPackageFile(String JavaDoc packageName) throws BuildException {
154         packageName = classFilePath + File.separator + packageName;
155         return testDirectory("Package", packageName);
156     }
157
158     private void findClasses(String JavaDoc packageName, Set JavaDoc<Class JavaDoc> addTo) {
159         File JavaDoc packageFile = getPackageFile(packageName);
160         File JavaDoc[] classes = packageFile.listFiles(CLASS_FILTER);
161
162         for (int i=0; i<classes.length; i++) {
163             String JavaDoc name = classes[i].getName();
164             String JavaDoc classname =
165                     packageName.replace(File.separatorChar, '.')
166                     + "."
167                     + name.substring(0, name.length() - 6);
168             try {
169                 addTo.add(cl.loadClass(classname));
170             } catch (ClassNotFoundException JavaDoc cnfe) {
171                 throw new BuildException(cnfe);
172             }
173         }
174
175     }
176
177     private Set JavaDoc<String JavaDoc> createPackageSet(String JavaDoc path,
178                                  String JavaDoc packageNames) {
179         HashSet JavaDoc<String JavaDoc> result = new HashSet JavaDoc<String JavaDoc>();
180
181         if (packageNames == null) {
182             return result;
183         }
184  
185         packageNames = packageNames.replace('.',
186                                             File.separatorChar);
187         Stack JavaDoc<String JavaDoc> stack = new Stack JavaDoc<String JavaDoc>();
188         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(packageNames, ",");
189         while (st.hasMoreTokens()) {
190             stack.push(st.nextToken().trim());
191         }
192
193         while (!stack.isEmpty()) {
194             String JavaDoc packageName = (String JavaDoc) stack.pop();
195             boolean recurse = packageName.endsWith("*");
196
197             packageName = normalize(packageName);
198             File JavaDoc packageFile = getPackageFile(packageName);
199             
200             result.add(packageName);
201
202             if (recurse) {
203                 File JavaDoc[] subdirs = packageFile.listFiles(DIR_FILTER);
204                 for (int i=0; i<subdirs.length; i++) {
205                     stack.push(packageName
206                                + File.separator
207                                + subdirs[i].getName()
208                                + "*");
209                 }
210             }
211         }
212
213         return result;
214     }
215
216   
217     private Set JavaDoc getClasses(Set JavaDoc packages) {
218         Set JavaDoc result = createSortedSet();
219
220         Iterator JavaDoc it = packages.iterator();
221
222         while (it.hasNext()) {
223             String JavaDoc packageName = (String JavaDoc) it.next();
224             findClasses(packageName, result);
225         }
226
227         return result;
228     }
229
230     private void addTest(Set JavaDoc<String JavaDoc> testClasses,
231                          Set JavaDoc<Class JavaDoc> resultSet,
232                          Test test) throws ClassNotFoundException JavaDoc {
233         String JavaDoc className = test.getClass().getName();
234         if (testClasses.contains(className)) {
235             return;
236         }
237  
238         // Don't include TestSuites/CoverageDecorator + private classes
239
// in statistics.
240
if (!(className.startsWith(TestSuite.class.getName())
241               || className.startsWith(CoverageDecorator.class.getName()))) {
242             numTests++;
243             testClasses.add(className);
244         }
245
246         if (test instanceof TestSuite) {
247             Enumeration JavaDoc e = ((TestSuite) test).tests();
248             while (e.hasMoreElements()) {
249                 addTest(testClasses, resultSet,
250                         (Test) e.nextElement());
251             }
252         }
253
254         if (test instanceof CoverageDecorator) {
255             numCoverageTests++;
256             Class JavaDoc[] classes = ((CoverageDecorator) test).getClassesCovered();
257             for (int i=0; i<classes.length; i++) {
258                 resultSet.add(classes[i]);
259             }
260         }
261     }
262
263     private Set JavaDoc getClassesCovered(Set JavaDoc<String JavaDoc> classSet) throws ClassNotFoundException JavaDoc {
264         Set JavaDoc result = createSortedSet();
265         Iterator JavaDoc it = classSet.iterator();
266
267         while (it.hasNext()) {
268             Set JavaDoc testClasses = new HashSet JavaDoc();
269
270             Class JavaDoc next = (Class JavaDoc) it.next();
271             if (!next.isInterface()
272                 && ((next.getModifiers() & Modifier.ABSTRACT) == 0)
273                 && Test.class.isAssignableFrom(next)) {
274
275                 try {
276                     Method JavaDoc suitMethod = next.getMethod(SUITE_METHOD,
277                                                        SUITE_TYPES);
278                     try {
279                         addTest(testClasses,
280                                 result,
281                                 (Test) suitMethod.invoke(null, SUITE_PARAMS));
282                     } catch (Exception JavaDoc e) {
283                         throw new BuildException(e);
284                     }
285
286                 } catch (NoSuchMethodException JavaDoc nsme) {
287                     // mmh, no suite() method, probably not a coverage
288
// test. But add anyway, so we get the statistics right.
289
Enumeration JavaDoc e = new TestSuite(next).tests();
290                     while (e.hasMoreElements()) {
291                         addTest(testClasses, result,
292                                 (Test) e.nextElement());
293                     }
294                 }
295                  
296             }
297         }
298
299         return result;
300     }
301
302     private Set JavaDoc getClassesToCover(Set JavaDoc<Class JavaDoc> classes) {
303         Set JavaDoc<Class JavaDoc> result = createSortedSet();
304         
305         Iterator JavaDoc<Class JavaDoc> it = classes.iterator();
306
307         while (it.hasNext()) {
308             Class JavaDoc next = (Class JavaDoc) it.next();
309
310             if (!next.isInterface()
311                 && !Test.class.isAssignableFrom(next)) {
312                 result.add(next);
313             }
314         }
315
316         return result;
317     }
318
319     private File JavaDoc testDirectory(String JavaDoc name,
320                                String JavaDoc path) throws BuildException {
321         if (path == null) {
322             throw new BuildException("'" +
323                                      name
324                                      + "' property has to be set.");
325         }
326
327         File JavaDoc dir = new File JavaDoc(path);
328         if (!(dir.exists() && dir.isDirectory())) {
329             throw new BuildException(name
330                                      + " directory: '"
331                                      + path
332                                      + "' does not exist.");
333         }
334
335         return dir;
336     }
337
338     public void execute() throws BuildException {
339         try {
340             testDirectory("ClassFilePath", classFilePath);
341             createClassloader();
342             
343             Set JavaDoc packageSet = createPackageSet(classFilePath,
344                                               packages);
345             Set JavaDoc excludePackageSet = createPackageSet(classFilePath,
346                                                      excludePackages);
347             
348             Set JavaDoc allClasses = getClasses(packageSet);
349             int numClasses = allClasses.size();
350             
351             Set JavaDoc classesCovered = getClassesCovered(allClasses);
352             
353             packageSet.removeAll(excludePackageSet);
354             
355             Set JavaDoc classes = getClasses(packageSet);
356             Set JavaDoc classesToCover = getClassesToCover(classes);
357             
358             int numClassesToCover = classesToCover.size();
359             
360             classesToCover.removeAll(classesCovered);
361             
362             Iterator JavaDoc it = classesToCover.iterator();
363             while (it.hasNext()) {
364                 handleErrorOutput("Class not covered by a coverage test: '"
365                                   + ((Class JavaDoc) it.next()).getName() + "'");
366             }
367             
368             int numUncoveredClasses = classesToCover.size();
369             int numCoveredClasses = (numClassesToCover - numUncoveredClasses);
370             
371             if (printStats) {
372                 handleOutput("");
373                 handleOutput("Coverage Statistics");
374                 handleOutput("--------------------");
375                 handleOutput("Classes: "
376                              + Util.leftFill(5, "" + numClasses));
377                 handleOutput("Classes requiring coverage: "
378                              + Util.leftFill(5, "" + numClassesToCover));
379                 handleOutput("Testcases: "
380                              + Util.leftFill(5, "" + numTests));
381                 handleOutput("Coverage Testcases: "
382                          + Util.leftFill(5, "" + numCoverageTests));
383                 handleOutput("Classes covered: "
384                              + Util.leftFill(5, "" + numCoveredClasses));
385                 NumberFormat JavaDoc nf = NumberFormat.getPercentInstance();
386                 String JavaDoc p = nf.format((double) numCoveredClasses
387                                      / (double) numClassesToCover);
388                 handleOutput("Percentage covered: "
389                              + Util.leftFill(5, p));
390             }
391
392             resetClassLoader();
393         } catch (Throwable JavaDoc t) {
394             t.printStackTrace();
395             throw new BuildException(t);
396         }
397
398     }
399
400 }
401
Popular Tags