• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2  *
3  * This program and the accompanying materials are made available under
4  * the terms of the Common Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
6  *
7  * $Id: ReportGenerator.java,v 1.1.1.1.2.1 2004/07/16 23:32:30 vlad_r Exp $
8  */
9 package com.vladium.emma.report.txt;
10 
11 import java.io.BufferedWriter;
12 import java.io.File;
13 import java.io.FileOutputStream;
14 import java.io.IOException;
15 import java.io.OutputStreamWriter;
16 import java.io.UnsupportedEncodingException;
17 import java.util.Date;
18 import java.util.Iterator;
19 import java.util.LinkedList;
20 
21 import com.vladium.util.Files;
22 import com.vladium.util.IProperties;
23 import com.vladium.util.asserts.$assert;
24 import com.vladium.emma.IAppConstants;
25 import com.vladium.emma.IAppErrorCodes;
26 import com.vladium.emma.EMMAProperties;
27 import com.vladium.emma.EMMARuntimeException;
28 import com.vladium.emma.data.ICoverageData;
29 import com.vladium.emma.data.IMetaData;
30 import com.vladium.emma.report.AbstractReportGenerator;
31 import com.vladium.emma.report.AllItem;
32 import com.vladium.emma.report.ClassItem;
33 import com.vladium.emma.report.IItem;
34 import com.vladium.emma.report.IItemAttribute;
35 import com.vladium.emma.report.ItemComparator;
36 import com.vladium.emma.report.MethodItem;
37 import com.vladium.emma.report.PackageItem;
38 import com.vladium.emma.report.SourcePathCache;
39 import com.vladium.emma.report.SrcFileItem;
40 
41 // ----------------------------------------------------------------------------
42 /**
43  * @author Vlad Roubtsov, (C) 2003
44  */
45 public
46 final class ReportGenerator extends AbstractReportGenerator
47                             implements IAppErrorCodes
48 {
49     // public: ................................................................
50 
51     // TODO: this is prototype quality, needs major cleanup
52 
53     // IReportGenerator:
54 
getType()55     public String getType ()
56     {
57         return TYPE;
58     }
59 
process(final IMetaData mdata, final ICoverageData cdata, final SourcePathCache cache, final IProperties properties)60     public void process (final IMetaData mdata, final ICoverageData cdata,
61                          final SourcePathCache cache, final IProperties properties)
62         throws EMMARuntimeException
63     {
64         initialize (mdata, cdata, cache, properties);
65 
66         long start = 0, end;
67         final boolean trace1 = m_log.atTRACE1 ();
68 
69         if (trace1) start = System.currentTimeMillis ();
70 
71         {
72             m_queue = new LinkedList ();
73             for (m_queue.add (m_view.getRoot ()); ! m_queue.isEmpty (); )
74             {
75                 final IItem head = (IItem) m_queue.removeFirst ();
76 
77                 head.accept (this, null);
78             }
79             line ();
80 
81             close ();
82         }
83 
84         if (trace1)
85         {
86             end = System.currentTimeMillis ();
87 
88             m_log.trace1 ("process", "[" + getType () + "] report generated in " + (end - start) + " ms");
89         }
90     }
91 
cleanup()92     public void cleanup ()
93     {
94         m_queue = null;
95         close ();
96 
97         super.cleanup ();
98     }
99 
100 
101     // IItemVisitor:
102 
visit(final AllItem item, final Object ctx)103     public Object visit (final AllItem item, final Object ctx)
104     {
105         File outFile = m_settings.getOutFile ();
106         if (outFile == null)
107         {
108             outFile = new File ("coverage.txt");
109             m_settings.setOutFile (outFile);
110         }
111 
112         final File fullOutFile = Files.newFile (m_settings.getOutDir (), outFile);
113 
114         m_log.info ("writing [" + getType () + "] report to [" + fullOutFile.getAbsolutePath () + "] ...");
115 
116         openOutFile (fullOutFile, m_settings.getOutEncoding (), true);
117 
118         // build ID stamp:
119         try
120         {
121             final StringBuffer label = new StringBuffer (101);
122 
123             label.append ("[");
124             label.append (IAppConstants.APP_NAME);
125             label.append (" v"); label.append (IAppConstants.APP_VERSION_WITH_BUILD_ID_AND_TAG);
126             label.append (" report, generated ");
127             label.append (new Date (EMMAProperties.getTimeStamp ()));
128             label.append ("]");
129 
130             m_out.write (label.toString ());
131             m_out.newLine ();
132 
133             m_out.flush ();
134         }
135         catch (IOException ioe)
136         {
137             throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
138         }
139 
140         final int [] columns = m_settings.getColumnOrder ();
141 
142         line ();
143 
144         // [all] coverage summary row:
145         addTitleRow ("OVERALL COVERAGE SUMMARY", 0, 1);
146         {
147             // header row:
148             addHeaderRow (item, columns);
149 
150             // coverage row:
151             addItemRow (item, columns);
152         }
153 
154         // [all] stats summary table ([all] only):
155         addTitleRow ("OVERALL STATS SUMMARY", 1, 1);
156         {
157             row ("total packages:" + m_separator + item.getChildCount ());
158             row ("total classes:" + m_separator + item.getAggregate (IItem.TOTAL_CLASS_COUNT));
159             row ("total methods:" + m_separator + item.getAggregate (IItem.TOTAL_METHOD_COUNT));
160 
161             if (m_srcView && m_hasSrcFileInfo)
162             {
163                 row ("total executable files:" + m_separator + item.getAggregate (IItem.TOTAL_SRCFILE_COUNT));
164 
165                 if (m_hasLineNumberInfo)
166                     row ("total executable lines:" + m_separator + item.getAggregate (IItem.TOTAL_LINE_COUNT));
167             }
168         }
169 
170         final boolean deeper = (m_settings.getDepth () > item.getMetadata ().getTypeID ());
171 
172         // render package summary rows:
173         addTitleRow ("COVERAGE BREAKDOWN BY PACKAGE", 1, 1);
174         {
175             boolean headerDone = false;
176             final ItemComparator order = m_typeSortComparators [PackageItem.getTypeMetadata ().getTypeID ()];
177             for (Iterator packages = item.getChildren (order); packages.hasNext (); )
178             {
179                 final IItem pkg = (IItem) packages.next ();
180 
181                 if (! headerDone)
182                 {
183                     // header row:
184                     addHeaderRow (pkg, columns);
185                     headerDone = true;
186                 }
187 
188                 // coverage row:
189                 addItemRow (pkg, columns);
190 
191                 if (deeper) m_queue.addLast (pkg);
192             }
193         }
194 
195         return ctx;
196     }
197 
visit(final PackageItem item, final Object ctx)198     public Object visit (final PackageItem item, final Object ctx)
199     {
200         if (m_verbose) m_log.verbose ("  report: processing package [" + item.getName () + "] ...");
201 
202         final int [] columns = m_settings.getColumnOrder ();
203 
204         line ();
205 
206         // coverage summary row:
207         addTitleRow ("COVERAGE SUMMARY FOR PACKAGE [".concat (item.getName ()).concat ("]"), 0, 1);
208         {
209             // header row:
210             addHeaderRow (item, columns);
211 
212             // coverage row:
213             addItemRow (item, columns);
214         }
215 
216 
217         final boolean deeper = (m_settings.getDepth () > item.getMetadata ().getTypeID ());
218 
219         // render child summary rows:
220 
221         final String summaryTitle = m_srcView ? "COVERAGE BREAKDOWN BY SOURCE FILE" : "COVERAGE BREAKDOWN BY CLASS";
222         addTitleRow (summaryTitle, 1, 1);
223         {
224             boolean headerDone = false;
225             final ItemComparator order = m_typeSortComparators [m_srcView ? SrcFileItem.getTypeMetadata ().getTypeID () : ClassItem.getTypeMetadata ().getTypeID ()];
226             for (Iterator srcORclsFiles = item.getChildren (order); srcORclsFiles.hasNext (); )
227             {
228                 final IItem srcORcls = (IItem) srcORclsFiles.next ();
229 
230                 if (! headerDone)
231                 {
232                     // header row:
233                     addHeaderRow (srcORcls, columns);
234                     headerDone = true;
235                 }
236 
237                 // coverage row:
238                 addItemRow (srcORcls, columns);
239 
240                 if (deeper) m_queue.addLast (srcORcls);
241             }
242         }
243 
244         return ctx;
245     }
246 
visit(final SrcFileItem item, final Object ctx)247     public Object visit (final SrcFileItem item, final Object ctx)
248     {
249         final int [] columns = m_settings.getColumnOrder ();
250 
251         line ();
252 
253         // coverage summary row:
254         addTitleRow ("COVERAGE SUMMARY FOR SOURCE FILE [".concat (item.getName ()).concat ("]"), 0, 1);
255         {
256             // header row:
257             addHeaderRow (item, columns);
258 
259             // coverage row:
260             addItemRow (item, columns);
261         }
262 
263         // render child summary rows:
264         addTitleRow ("COVERAGE BREAKDOWN BY CLASS AND METHOD", 1, 1);
265         {
266             boolean headerDone = false;
267             final ItemComparator order = m_typeSortComparators [ClassItem.getTypeMetadata ().getTypeID ()];
268             for (Iterator classes = item.getChildren (order); classes.hasNext (); )
269             {
270                 final IItem cls = (IItem) classes.next ();
271 
272                 if (! headerDone)
273                 {
274                     // header row:
275                     addHeaderRow (cls, columns);
276                     headerDone = true;
277                 }
278 
279                 // coverage row:
280                 //addItemRow (child, columns);
281 
282                 addTitleRow ("class [" + cls.getName () + "] methods", 0, 0);
283 
284                 // TODO: select the right comparator here
285                 final ItemComparator order2 = m_typeSortComparators [MethodItem.getTypeMetadata ().getTypeID ()];
286                 for (Iterator methods = cls.getChildren (order2); methods.hasNext (); )
287                 {
288                     final MethodItem method = (MethodItem) methods.next ();
289 
290                     addItemRow (method, columns);
291                 }
292             }
293         }
294 
295         return ctx;
296     }
297 
visit(final ClassItem item, final Object ctx)298     public Object visit (final ClassItem item, final Object ctx)
299     {
300         final int [] columns = m_settings.getColumnOrder ();
301 
302         line ();
303 
304         // coverage summary row:
305         addTitleRow ("COVERAGE SUMMARY FOR CLASS [".concat (item.getName ()).concat ("]"), 0, 1);
306         {
307             // header row:
308             addHeaderRow (item, columns);
309 
310             // coverage row:
311             addItemRow (item, columns);
312         }
313 
314         // render child summary rows:
315         addTitleRow ("COVERAGE BREAKDOWN BY METHOD", 1, 1);
316         {
317             final ItemComparator order = m_typeSortComparators [MethodItem.getTypeMetadata ().getTypeID ()];
318             for (Iterator methods = item.getChildren (order); methods.hasNext (); )
319             {
320                 final IItem method = (IItem) methods.next ();
321 
322                 // coverage row:
323                 addItemRow (method, columns);
324             }
325         }
326 
327         return ctx;
328     }
329 
330     // protected: .............................................................
331 
332     // package: ...............................................................
333 
334     // private: ...............................................................
335 
336 
addTitleRow(final String text, final int hlines, final int flines)337     private void addTitleRow (final String text, final int hlines, final int flines)
338     {
339         for (int i = 0; i < hlines; ++ i) eol ();
340         row (new StringBuffer (text).append (":"));
341         for (int i = 0; i < flines; ++ i) eol ();
342     }
343 
addHeaderRow(final IItem item, final int [] columns)344     private void addHeaderRow (final IItem item, final int [] columns)
345     {
346         if ($assert.ENABLED)
347         {
348             $assert.ASSERT (item != null, "null input: item");
349             $assert.ASSERT (columns != null, "null input: columns");
350         }
351 
352         // header row:
353         final StringBuffer buf = new StringBuffer ();
354 
355         for (int c = 0, cLimit = columns.length; c < cLimit; ++ c)
356         {
357             final int attrID = columns [c];
358             final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
359 
360             if (attr != null)
361             {
362                 buf.append ('[');
363                 buf.append (attr.getName ());
364                 buf.append (']');
365             }
366             if (c != cLimit - 1) buf.append (m_separator);
367         }
368 
369         row (buf);
370     }
371 
372 
373     /*
374      * No header row, just data rows.
375      */
addItemRow(final IItem item, final int [] columns)376     private void addItemRow (final IItem item, final int [] columns)
377     {
378         if ($assert.ENABLED)
379         {
380             $assert.ASSERT (item != null, "null input: item");
381             $assert.ASSERT (columns != null, "null input: columns");
382         }
383 
384         final StringBuffer buf = new StringBuffer (11); // TODO: reuse a buffer
385 
386         for (int c = 0, cLimit = columns.length; c < cLimit; ++ c)
387         {
388             final int attrID = columns [c];
389             final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
390 
391             if (attr != null)
392             {
393                 boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
394 
395                 if (fail)
396                 {
397                     //buf.append ('(');
398                     //buf.append ("! ");
399                     attr.format (item, buf);
400                     buf.append ('!');
401                     //buf.append (')');
402                 }
403                 else
404                 {
405                     attr.format (item, buf);
406                 }
407             }
408             if (c != cLimit - 1) buf.append (m_separator);
409         }
410 
411         row (buf);
412     }
413 
414 
row(final StringBuffer str)415     private void row (final StringBuffer str)
416     {
417         if ($assert.ENABLED) $assert.ASSERT (str != null, "str = null");
418 
419         try
420         {
421             m_out.write (str.toString ());
422             m_out.newLine ();
423         }
424         catch (IOException ioe)
425         {
426             throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
427         }
428     }
429 
row(final String str)430     private void row (final String str)
431     {
432         if ($assert.ENABLED) $assert.ASSERT (str != null, "str = null");
433 
434         try
435         {
436             m_out.write (str);
437             m_out.newLine ();
438         }
439         catch (IOException ioe)
440         {
441             throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
442         }
443     }
444 
line()445     private void line ()
446     {
447         try
448         {
449             m_out.write (LINE);
450             m_out.newLine ();
451         }
452         catch (IOException ioe)
453         {
454             throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
455         }
456     }
457 
eol()458     private void eol ()
459     {
460         try
461         {
462             m_out.newLine ();
463         }
464         catch (IOException ioe)
465         {
466             throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
467         }
468     }
469 
close()470     private void close ()
471     {
472         if (m_out != null)
473         {
474             try
475             {
476                 m_out.flush ();
477                 m_out.close ();
478             }
479             catch (IOException ioe)
480             {
481                 throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
482             }
483             finally
484             {
485                 m_out = null;
486             }
487         }
488     }
489 
openOutFile(final File file, final String encoding, final boolean mkdirs)490     private void openOutFile (final File file, final String encoding, final boolean mkdirs)
491     {
492         try
493         {
494             if (mkdirs)
495             {
496                 final File parent = file.getParentFile ();
497                 if (parent != null) parent.mkdirs ();
498             }
499 
500             m_out = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (file), encoding), IO_BUF_SIZE);
501         }
502         catch (UnsupportedEncodingException uee)
503         {
504             // TODO: error code
505             throw new EMMARuntimeException (uee);
506         }
507         // note: in J2SDK 1.3 FileOutputStream constructor's throws clause
508         // was narrowed to FileNotFoundException:
509         catch (IOException fnfe) // FileNotFoundException
510         {
511             // TODO: error code
512             throw new EMMARuntimeException (fnfe);
513         }
514     }
515 
516 
517     private char m_separator = '\t'; // TODO: set this
518 
519     private LinkedList /* IITem */ m_queue;
520     private BufferedWriter m_out;
521 
522     private static final String TYPE = "txt";
523     private static final String LINE = "-------------------------------------------------------------------------------";
524 
525     private static final int IO_BUF_SIZE = 32 * 1024;
526 
527 } // end of class
528 // ----------------------------------------------------------------------------