KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > csdl > jblanket > report > JBlanketReport


1 package csdl.jblanket.report;
2
3 import csdl.jblanket.JBlanket;
4 import csdl.jblanket.JBlanketException;
5 import csdl.jblanket.methodset.MethodSet;
6 import csdl.jblanket.methodset.MethodSetManager;
7 import csdl.jblanket.util.MethodCategories;
8
9 import java.io.File JavaDoc;
10 import java.io.FileInputStream JavaDoc;
11 import java.io.FileOutputStream JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.util.Date JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import org.apache.tools.ant.DirectoryScanner;
19
20 /**
21  * Creates reports for method coverage.
22  * <p>
23  * This is the last step in JBlanket.
24  * <p>
25  * There are two main functions of this class:
26  * <ul>
27  * <li> Combines the methods invoked during testing in "COVER-*.xml" files into one XML file,
28  * where * is the fully qualified name of the test class, then derives the methods that were
29  * not tested.
30  * <li> Calls the AggregateTransformer class to combine JBlanket output and transform them
31  * into HTML files.
32  * </ul>
33  * <p>
34  * The above mentioned functions are achieved by invoking the
35  * <code>main</code> method. Arguments to pass to the main method include:
36  * <p>
37  * <b>Required</b> command line argument:
38  * <ul>
39  * <p>
40  * none.
41  * </ul>
42  * <p>
43  * <b>Optional</b> command line argument:
44  * <ul>
45  * <p>
46  * 'enable' - describes if a JBlanket report should be created. Valid values include
47  * "true", "on", "yes" to create a report or "false", "off", or "no" to not
48  * create a report.<br>
49  * <i>For example</i>: -enable true
50  * <p>
51  * 'verbose' - describes if report should be created in verbose mode<br>
52  * <i>For example</i>: -verbose true
53  * <p>
54  * 'reportFormat' - format of the HTML report, either 'frames' or 'noframes'<br>
55  * <i>For example</i>: -reportFormat frames
56  * <p>
57  * 'toDir' - directory where all HTML files should be sent<br>
58  * <i>For example</i>: -toDir jblanket/html
59  * <p>
60  * 'excludeOneLineMethods' - describes if one-line methods were excluded<br>
61  * <i>For example</i>: -excludeOneLineMethods false
62  * <p>
63  * 'excludeConstructors' - describes if constructors were excluded<br>
64  * <i>For example</i>: -excludeConstructors false
65  * <p>
66  * 'excludeIndividualMethods' - describes if individual methods were excluded<br>
67  * <i>For example</i>: -excludeIndividualMethods false
68  * <p>
69  * 'totalFile' - name of XML file containing all methods included in the coverage measurement<br>
70  * <i>For example</i>: -totalFile totalMethods.xml
71  * <p>
72  * 'testedFile' - name of XML file to contain all methods that were tested<br>
73  * <i>For example</i>: -testedFile testedMethods.xml
74  * <p>
75  * 'untestedFile' - name of XML file to contain all methods that were not tested<br>
76  * <i>For example</i>: -untestedFile untestedMethods.xml
77  * <p>
78  * 'onelineFile' - name of XML file containing all one-line methods<br>
79  * <i>For example</i>: -oneLineFile oneLineMethods.xml
80  * <p>
81  * 'constructionFile' - name of XML file containing all constructors<br>
82  * <i>For example</i>: -constructorFile constructorMethods.xml
83  * <p>
84  * 'excludedIndividualFile' - name of XML file containing all individually excluded methods<br>
85  * <i>For example</i>: -excludedIndividualFile excludedIndividualMethods.xml
86  * </ul>
87  * <p>
88  * Default values are provided for all optional command line arguments and are equivalent to
89  * those shown in the examples. Note that values for similar arguments found in
90  * csdl.jblanket.modifier.Modifier or csdl.jblanket.app.ExcludeIndividualMethodApp must be set to
91  * the same value. For example, if the 'excludeOneLineMethods' argument was set to 'true' and the
92  * 'onelinefile' argument was set to 'myOneLineMethods.xml' in the Modifier class, then arguments
93  * for 'excludeOneLineMethods' and 'onelinefile' in csdl.jblanket.report.JBlanketReport and
94  * csdl.jblanket.app.ExcludeIndividualMethodApp also need to be set to 'true' and
95  * 'myOneLineMethods.xml', respectively.
96  * <p>
97  * Note that the methods in <code>excludedIndividualFile</code> take priority over all the other
98  * methods. I.e., if a one-line method was individually excluded by the application, then it is
99  * considered to be an individually excluded methods instead of a one-line method.
100  *
101  * @author Joy M. Agustin
102  * @version $Id: JBlanketReport.java,v 1.3 2005/02/21 20:28:40 timshadel Exp $id
103  */

104 public class JBlanketReport extends JBlanket {
105   
106   /** Prefix to file name for JBlanket intermediate coverage data from JUnit tests */
107   private static final String JavaDoc PREFIX = "COVER-";
108   /** Name of file with aggregate of all methods */
109   private static final String JavaDoc AGG_FILENAME = "MethodSets.xml";
110   
111   /** Holds the name of the current class */
112   private static String JavaDoc currentClassName;
113   /** Time stamp from 'totalFile' that will be stores in JBlanket summary output files */
114   private Date JavaDoc timeStamp;
115   /** Format of HTML reports */
116   private String JavaDoc reportFormat;
117   /** Directory for HTML output */
118   private File JavaDoc toDir;
119   /** Message containing coverage results */
120   private String JavaDoc results;
121   
122   /** Contains methods invoked during testing */
123   private MethodSet testedSet;
124   /** Contains methods not invoked during testing */
125   private MethodSet untestedSet;
126   
127   /** Describes if individual methods should be excluded from the coverage measurement */
128   private boolean excludeIndividualMethods = false;
129   /** Contains individual methods excluded from coverage */
130   private MethodSet excludedIndividualSet;
131     
132   /**
133    * Constructs a new JBlanketReport object. This object will read in information stored in XML
134    * files <code>totalFile</code>, <code>oneLineFile</code>, and <code>constructorFile</code> and
135    * store information in the <Code>testedFile</code> and <code>untestedFile</code> files in XML
136    * format.
137    *
138    * @param verbose describes if JBlanket should execute in verbose mode.
139    * @param excludeOneLineMethods describes if one-line methods should be excluded.
140    * @param excludeConstructors describes if constructors should be excluded.
141    * @param excludeIndividualMethods describes if individual methods should be excluded.
142    * @param reportFormat format of HTML report.
143    * @param toDir output directory of HTML report.
144    * @throws JBlanketException if cannot read from <code>totalFile</code>,
145    * <code>oneLineFile</code>, or <code>constructorFile</code>.
146    */

147   public JBlanketReport(boolean verbose, boolean excludeOneLineMethods,
148                         boolean excludeConstructors, boolean excludeIndividualMethods,
149                         String JavaDoc reportFormat, File JavaDoc toDir)
150                         
151       throws JBlanketException {
152     super();
153
154     this.verbose = verbose;
155     this.reportFormat = reportFormat;
156     if (toDir == null) {
157         this.toDir = new File JavaDoc(jblanketDir);
158     } else {
159         this.toDir = toDir;
160     }
161
162     // get all filesets; since report is probably created in different JVM than instrumentation,
163
// need to load all MethodSet elements from files
164
MethodSetManager manager = MethodSetManager.getInstance();
165     super.totalSet = manager.getMethodSet(super.categories.getFileName("totalFile"));
166     this.timeStamp = loadMethods(super.totalSet,
167                                  new File JavaDoc(super.categories.getFileName("totalFile")));
168
169     // if one-line methods are excluded, get them
170
super.excludeOneLineMethods = excludeOneLineMethods;
171     super.oneLineSet = new MethodSet();
172     if (excludeOneLineMethods) {
173       loadMethods(super.oneLineSet, new File JavaDoc(super.categories.getFileName("oneLineFile")));
174     }
175
176     // if constructors are excluded, get them
177
super.excludeConstructors = excludeConstructors;
178     super.constructorSet = new MethodSet();
179     if (excludeConstructors) {
180       loadMethods(super.constructorSet, new File JavaDoc(super.categories.getFileName("constructorFile")));
181     }
182
183     // if individual methods are excluded, get them
184
this.excludeIndividualMethods = excludeIndividualMethods;
185     this.excludedIndividualSet = new MethodSet();
186     if (excludeIndividualMethods) {
187       File JavaDoc excludeIndividualFile =
188           new File JavaDoc(super.categories.getFileName("excludedIndividualFile"));
189       // file will not exist if this is the first time excluding individual files
190
if (excludeIndividualFile.exists()) {
191         loadMethods(this.excludedIndividualSet, excludeIndividualFile);
192       }
193       else {
194         this.excludedIndividualSet = new MethodSet();
195       }
196     }
197
198     super.untestableSet = manager.getMethodSet(super.categories.getFileName("untestableFile"));
199     loadMethods(super.untestableSet, new File JavaDoc(super.categories.getFileName("untestableFile")));
200
201     // create empty MethodSet elements in MethodSetManager
202
this.testedSet = manager.getMethodSet(super.categories.getFileName("testedFile"));
203     this.untestedSet = manager.getMethodSet(super.categories.getFileName("untestedFile"));
204   }
205
206   /**
207    * Creates a report from the XML files.
208    *
209    * @throws JBlanketException if unable to create report.
210    * @return a summary of the report.
211    */

212   public String JavaDoc createReport() throws JBlanketException {
213
214     createTestedFile();
215     createUntestedFile();
216
217     // create aggregate file "COVER-MethodSets.xml"
218
Map JavaDoc reportCategories = getReportCategories();
219     // send in the jblanketDir value to avoid added "Warnings" to the screen
220
AggregateTransformer transformer = new AggregateTransformer(reportCategories, this.reportFormat,
221                                                                 super.jblanketDir, this.toDir);
222     File JavaDoc aggregateFile = new File JavaDoc(super.jblanketDir, PREFIX + AGG_FILENAME);
223     transformer.createAggregateFile(aggregateFile);
224
225     // transform aggregate file to HTML
226
transformer.transformXmlToHtml(aggregateFile.getAbsolutePath());
227     return this.results;
228   }
229   
230   /**
231    * Creates an aggregate file containing all methods invoked during testing.
232    *
233    * @throws JBlanketException if no files found from testing, cannot read date from any
234    * 'COVER-*' files, or cannot store test file.
235    */

236   protected void createTestedFile() throws JBlanketException {
237
238     // get all intermediate coverage files from executing JUnit tests
239
DirectoryScanner scanner = new DirectoryScanner();
240     scanner.setIncludes(new String JavaDoc[]{PREFIX + "*"});
241     scanner.setExcludes(null);
242     scanner.setBasedir(new File JavaDoc(jblanketDir));
243     scanner.setCaseSensitive(true);
244     scanner.scan();
245     String JavaDoc[] files = scanner.getIncludedFiles();
246
247     // if no 'COVER-*.xml' files are found, throw exception
248
if (files.length == 0) {
249       String JavaDoc message = "No intermediate '" + PREFIX + "*.xml' files found in " + super.jblanketDir
250                        + ". Invoked class files may not have been modified by JBlanket.";
251       throw new JBlanketException(message);
252     }
253
254     // process each file to form a single aggregate file
255
MethodSetManager manager = MethodSetManager.getInstance();
256     for (int i = 0; i < files.length; i++) {
257       MethodSet nextSet = manager.getMethodSet(files[i]);
258
259       // skip previous aggregate JBlanket output if not deleted between executions
260
if ((PREFIX + AGG_FILENAME).equals(files[i])) {
261         continue;
262       }
263       loadMethods(nextSet, new File JavaDoc(super.jblanketDir, files[i]));
264       this.testedSet.union(nextSet);
265     }
266
267     // verify all methods in testedSet are valid; don't want to alter the other MethodSets just yet
268
this.testedSet.intersection(super.totalSet);
269
270     // store total tested methods before extracting optional exclusions
271
try {
272       storeMethods(this.testedSet, new File JavaDoc(categories.getFileName("total.testedFile")));
273     }
274     catch (IOException JavaDoc e) {
275       throw new JBlanketException("Unable to store total tested methods to "
276                                   + categories.getFileName("total.testedFile"), e);
277     }
278     
279     // removed the optional method exclusions
280
this.testedSet.difference(super.oneLineSet);
281     this.testedSet.difference(super.constructorSet);
282     this.testedSet.difference(this.excludedIndividualSet);
283     try {
284       storeMethods(this.testedSet, new File JavaDoc(categories.getFileName("testedFile")));
285     }
286     catch (IOException JavaDoc e) {
287       throw new JBlanketException("Unable to store tested methods to "
288                                   + categories.getFileName("testedFile"), e);
289     }
290   }
291
292   /**
293    * Creates a file containing the methods that were not invoked during testing.
294    * <p>
295    * NOTE: Results are rounded to nearest percent while coverage in reports are rounded to the
296    * nearest half percent.
297    *
298    * @throws JBlanketException if cannot read from totalFile, set in constructor.
299    */

300   protected void createUntestedFile() throws JBlanketException {
301     // get number of methods in each set
302
int untestableSize = this.untestableSet.size();
303     int totalSize = super.totalSet.size() + untestableSize;
304     int oneLineSize = super.oneLineSet.size();
305     int constructorSize = super.constructorSet.size();
306     int excludedIndividualSize = this.excludedIndividualSet.size();
307     int subtotalSize = totalSize - oneLineSize - constructorSize -
308             excludedIndividualSize - untestableSize;
309     int testedSize = testedSet.size();
310
311     // store total untested methods before extracting optional exclusions
312
this.untestedSet = super.totalSet.difference(this.testedSet);
313     try {
314       storeMethods(this.untestedSet, new File JavaDoc(categories.getFileName("total.untestedFile")));
315     }
316     catch (IOException JavaDoc e) {
317       throw new JBlanketException("Unable to store total untested methods to "
318                                   + categories.getFileName("total.untestedFile"), e);
319     }
320     
321     // remove the optional method exclusions
322
this.untestedSet.difference(super.oneLineSet);
323     this.untestedSet.difference(super.constructorSet);
324     this.untestedSet.difference(this.excludedIndividualSet);
325     try {
326       storeMethods(this.untestedSet, new File JavaDoc(super.categories.getFileName("untestedFile")));
327     }
328     catch (IOException JavaDoc e) {
329       throw new JBlanketException("Unable to store untested methods to "
330                                   + categories.getFileName("untestedFile"), e);
331     }
332     
333     // calculate coverage measurements
334
int untestedSize = this.untestedSet.size();
335     int percent = 100;
336     int oneLinePercent = Math.round(((float) oneLineSize / totalSize) * percent);
337     int constructorPercent = Math.round(((float) constructorSize / totalSize) * percent);
338     int excludedIndividualPercent = Math.round(((float) excludedIndividualSize / totalSize)
339                                                * percent);
340     int testedPercent = Math.round(((float) testedSize / subtotalSize) * percent);
341     int untestedPercent = percent - testedPercent;
342
343     // generate output message
344
StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
345     msg.append("********************************************************\n");
346     msg.append("Method-level Coverage:\n");
347     msg.append("All methods : {total=" + totalSize + "}\n");
348     msg.append("Untestable methods : {total=" + untestableSize + "}\n");
349     if (super.excludeOneLineMethods) {
350       msg.append("Excluded One-line methods : {total=" + oneLineSize + "}\n");
351     }
352     if (super.excludeConstructors) {
353       msg.append("Excluded Constructors : {total=" + constructorSize + "}\n");
354     }
355     if (this.excludeIndividualMethods) {
356       msg.append("Excluded individual methods : {total=" + excludedIndividualSize + "}\n");
357     }
358     msg.append("--------------------------------------------------------\n");
359     if (super.excludeOneLineMethods || super.excludeConstructors || this.excludeIndividualMethods) {
360       msg.append("Remaining methods : {total=" + subtotalSize + "}\n");
361     }
362     msg.append("Tested methods : {total=" + testedSize +
363             ", percent=" + testedPercent + "%}\n");
364     msg.append("Untested methods : {total=" + untestedSize + ", percent="
365                + untestedPercent + "%}\n");
366     msg.append("********************************************************");
367
368     this.results = msg.toString();
369   }
370   
371   /**
372    * Loads all the method information into <code>jblanketSet</code> from <code>file</code>
373    * in the jblanket.dir system property.
374    *
375    * @param methodSet the collection of method information to load.
376    * @param file the input file.
377    * @return the Date found in <code>file</code>.
378    * @throws JBlanketException if cannot write to <code>fileName</code>.
379    */

380   private Date JavaDoc loadMethods(MethodSet methodSet, File JavaDoc file) throws JBlanketException {
381     
382     Date JavaDoc timeStamp;
383     try {
384       // throws FileNotFoundException
385
FileInputStream JavaDoc in = new FileInputStream JavaDoc(file);
386       // throws PareseException
387
timeStamp = methodSet.load(in);
388       // throws IOException
389
in.close();
390     }
391     catch (Exception JavaDoc e) {
392       throw new JBlanketException("Unable to read file " + file.getAbsolutePath(), e);
393     }
394     
395     return timeStamp;
396   }
397   
398   /**
399    * Stores all the method information from <code>jblanketSet</code> to <code>fileName</code>
400    * in the jblanket.dir system property.
401    *
402    * @param methodSet the collection of method information to output.
403    * @param file the output file.
404    * @throws IOException if cannot write to <code>fileName</code>.
405    */

406   protected void storeMethods(MethodSet methodSet, File JavaDoc file) throws IOException JavaDoc {
407     
408     // create FileOutputStream for output of test class results -- throws FileNotFoundException
409
FileOutputStream JavaDoc fostream = new FileOutputStream JavaDoc(file);
410     // store test class results -- throws IOException
411
methodSet.store(fostream, null, this.timeStamp);
412     // throws IOException
413
fostream.close();
414   }
415
416   /**
417    * Returns all the categories of methods collected. These categories are used as categories
418    * for the methods in the aggregate XML file.
419    *
420    * @return all the collected method categories.
421    */

422   protected Map JavaDoc getReportCategories() {
423
424     Map JavaDoc reportCategories = new HashMap JavaDoc();
425
426     if (super.excludeConstructors) {
427       reportCategories.put("constructor", super.categories.getFileName("constructorFile"));
428     }
429
430     if (super.excludeOneLineMethods) {
431       reportCategories.put("oneline", super.categories.getFileName("oneLineFile"));
432     }
433
434     if (this.excludeIndividualMethods) {
435       reportCategories.put("excludedIndividual",
436                            super.categories.getFileName("excludedIndividualFile"));
437     }
438
439     reportCategories.put("tested", super.categories.getFileName("testedFile"));
440     reportCategories.put("untested", super.categories.getFileName("untestedFile"));
441     reportCategories.put("untestable", super.categories.getFileName("untestableFile"));
442     return reportCategories;
443   }
444   
445   /**
446    * Provides the command line interface.
447    *
448    * @param args the command line arguments.
449    * @throws JBlanketException if cannot read the date from files.
450    */

451   public static void main(String JavaDoc args[]) throws JBlanketException {
452     main(java.util.Arrays.asList(args));
453   }
454
455   /**
456    * Processes the command line arguments as a List.
457    * <p>
458    * Created for JBlanketReportTask Ant taskdef. This method grabs all of the output files
459    * from storeMethodTypeSignature method in csdl.jblanket.modifier.MethodCollector and combines
460    * the results into a format similar to JUnit.
461    * <p>
462    * The command line arguments are as follows:
463    * <pre>
464    * '-verbose' - describes if should execute in verbose mode
465    * '-reportFormat' - format of the HTML report, either 'frames' or 'noframes'
466    * '-toDir' - directory for HTML output
467    * '-excludeOneLineMethods' - describes if should exclude one-line methods
468    * '-excludeConstructors' - describes if should exclude constructors
469    * '-excludeIndividualMethods' - describes if should exclude individual methods
470    * '-totalFile' - name of the output XML file for total methods
471    * '-testedFile' - name of the output XML file to contain all methods that were tested
472    * '-untestedFile' - name of the output XML file to contain all methods that were not tested
473    * '-oneLineFile' - name of the output XML file for one-line methods
474    * '-constructorFile' - name of the output XML file for constructors
475    * '-excludedIndividualFile' - name of the output XML file for individually excluded methods
476    * </pre>
477    *
478    * @param args the List of command line arguments.
479    * @throws JBlanketException if cannot read the date from files.
480    */

481   public static void main(List JavaDoc args) throws JBlanketException {
482
483     // Verbose mode
484
boolean verbose = false;
485     // format of final HTML report
486
String JavaDoc reportFormat = "frames";
487     File JavaDoc toDir = null;
488
489     // Exclude one-line methods
490
boolean excludeOneLineMethods = false;
491     // Exclude constructors
492
boolean excludeConstructors = false;
493     // Exclude individual methods
494
boolean excludeIndividualMethods = false;
495
496     MethodCategories categories = MethodCategories.getInstance();
497
498     // index of current command line arguments.
499
int i;
500     // Parses args into corresponsing variables.
501
for (i = 0; i < args.size(); ++i) {
502       String JavaDoc argument = (String JavaDoc) args.get(i);
503       if (argument.equals("-verbose")) {
504         verbose = ((Boolean JavaDoc) args.get(++i)).booleanValue();
505       }
506       else if (argument.equals("-reportFormat")) {
507         reportFormat = (String JavaDoc) args.get(++i);
508       }
509       else if (argument.equals("-toDir")) {
510         toDir = new File JavaDoc((String JavaDoc) args.get(++i));
511       }
512       else if (argument.equals("-excludeOneLineMethods")) {
513         excludeOneLineMethods = ((Boolean JavaDoc) args.get(++i)).booleanValue();
514       }
515       else if (argument.equals("-excludeConstructors")) {
516         excludeConstructors = ((Boolean JavaDoc) args.get(++i)).booleanValue();
517       }
518       else if (argument.equals("-excludeIndividualMethods")) {
519         excludeIndividualMethods = ((Boolean JavaDoc) args.get(++i)).booleanValue();
520       }
521       else if (argument.equals("-oneLineFile")) {
522         categories.addCategory("oneLineFile", (String JavaDoc) args.get(++i));
523       }
524       else if (argument.equals("-constructorFile")) {
525         categories.addCategory("constructorFile", (String JavaDoc) args.get(++i));
526       }
527       else if (argument.equals("-excludedIndividualFile")) {
528         categories.addCategory("excludedIndividualFile", (String JavaDoc) args.get(++i));
529       }
530       else if (argument.equals("-totalFile")) {
531         categories.addCategory("totalFile", (String JavaDoc) args.get(++i));
532       }
533       else if (argument.equals("-testedFile")) {
534         categories.addCategory("testedFile", (String JavaDoc) args.get(++i));
535       }
536       else if (argument.equals("-untestedFile")) {
537         categories.addCategory("untestedFile", (String JavaDoc) args.get(++i));
538       }
539       else if (argument.equals("-untestableFile")) {
540           categories.addCategory("untestableFile", (String JavaDoc) args.get(++i));
541         }
542       else {
543         System.out.println("Incorrect usage: " + argument);
544         System.exit(1);
545       }
546     }
547     
548     JBlanketReport report = new JBlanketReport(verbose, excludeOneLineMethods, excludeConstructors,
549                                                excludeIndividualMethods, reportFormat, toDir);
550
551     System.out.println(report.createReport());
552     if (reportFormat.equals("frames")) {
553       System.out.println("JBlanket results in " + report.toDir.getAbsolutePath()
554         + File.separator + "index.html");
555     }
556     else {
557       System.out.println("JBlanket results in " + report.toDir.getAbsolutePath()
558         + File.separator + "jblanket-noframes.html");
559     }
560   }
561 }
562
Popular Tags