KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cobertura > reporting > html > HTMLReport


1 /*
2  * Cobertura - http://cobertura.sourceforge.net/
3  *
4  * Copyright (C) 2005 Mark Doliner
5  * Copyright (C) 2005 Grzegorz Lukasik
6  * Copyright (C) 2005 Jeremy Thomerson
7  *
8  * Cobertura is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published
10  * by the Free Software Foundation; either version 2 of the License,
11  * or (at your option) any later version.
12  *
13  * Cobertura is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Cobertura; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21  * USA
22  */

23
24 package net.sourceforge.cobertura.reporting.html;
25
26 import java.io.BufferedReader JavaDoc;
27 import java.io.File JavaDoc;
28 import java.io.FileNotFoundException JavaDoc;
29 import java.io.FileOutputStream JavaDoc;
30 import java.io.FileReader JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.PrintStream JavaDoc;
33 import java.text.DateFormat JavaDoc;
34 import java.text.DecimalFormat JavaDoc;
35 import java.text.NumberFormat JavaDoc;
36 import java.util.Collection JavaDoc;
37 import java.util.Collections JavaDoc;
38 import java.util.Date JavaDoc;
39 import java.util.Iterator JavaDoc;
40 import java.util.SortedSet JavaDoc;
41 import java.util.TreeSet JavaDoc;
42 import java.util.Vector JavaDoc;
43
44 import net.sourceforge.cobertura.coveragedata.ClassData;
45 import net.sourceforge.cobertura.coveragedata.CoverageData;
46 import net.sourceforge.cobertura.coveragedata.PackageData;
47 import net.sourceforge.cobertura.coveragedata.ProjectData;
48 import net.sourceforge.cobertura.coveragedata.SourceFileData;
49 import net.sourceforge.cobertura.reporting.ComplexityCalculator;
50 import net.sourceforge.cobertura.reporting.html.files.CopyFiles;
51 import net.sourceforge.cobertura.util.FileFinder;
52 import net.sourceforge.cobertura.util.Header;
53
54 import org.apache.log4j.Logger;
55
56 public class HTMLReport
57 {
58
59     private static final Logger LOGGER = Logger.getLogger(HTMLReport.class);
60
61     private File JavaDoc destinationDir;
62
63     private FileFinder finder;
64
65     private ComplexityCalculator complexity;
66
67     private ProjectData projectData;
68
69     /**
70      * Create a coverage report
71      */

72     public HTMLReport(ProjectData projectData, File JavaDoc outputDir,
73             FileFinder finder, ComplexityCalculator complexity)
74             throws Exception JavaDoc
75     {
76         this.destinationDir = outputDir;
77         this.finder = finder;
78         this.complexity = complexity;
79         this.projectData = projectData;
80
81         CopyFiles.copy(outputDir);
82         generatePackageList();
83         generateSourceFileLists();
84         generateOverviews();
85         generateSourceFiles();
86     }
87
88     private String JavaDoc generatePackageName(PackageData packageData)
89     {
90         if (packageData.getName().equals(""))
91             return "(default)";
92         return packageData.getName();
93     }
94
95     private void generatePackageList() throws IOException JavaDoc
96     {
97         File JavaDoc file = new File JavaDoc(destinationDir, "frame-packages.html");
98         PrintStream JavaDoc out = null;
99
100         try
101         {
102             out = new PrintStream JavaDoc(new FileOutputStream JavaDoc(file));
103
104             out
105                     .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
106             out
107                     .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
108
109             out
110                     .println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">");
111             out.println("<head>");
112             out
113                     .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
114             out.println("<title>Coverage Report</title>");
115             out
116                     .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/main.css\" />");
117             out.println("</head>");
118             out.println("<body>");
119             out.println("<h5>Packages</h5>");
120             out.println("<table width=\"100%\">");
121             out.println("<tr>");
122             out
123                     .println("<td nowrap=\"nowrap\"><a HREF=\"frame-summary.html\" onclick='parent.sourceFileList.location.href=\"frame-sourcefiles.html\"' target=\"summary\">All</a></td>");
124             out.println("</tr>");
125
126             Iterator JavaDoc iter = projectData.getPackages().iterator();
127             while (iter.hasNext())
128             {
129                 PackageData packageData = (PackageData)iter.next();
130                 String JavaDoc url1 = "frame-summary-" + packageData.getName()
131                         + ".html";
132                 String JavaDoc url2 = "frame-sourcefiles-" + packageData.getName()
133                         + ".html";
134                 out.println("<tr>");
135                 out.println("<td nowrap=\"nowrap\"><a HREF=\"" + url1
136                         + "\" onclick='parent.sourceFileList.location.href=\""
137                         + url2 + "\"' target=\"summary\">"
138                         + generatePackageName(packageData) + "</a></td>");
139                 out.println("</tr>");
140             }
141             out.println("</table>");
142             out.println("</body>");
143             out.println("</html>");
144         }
145         finally
146         {
147             if (out != null)
148             {
149                 out.close();
150             }
151         }
152     }
153
154     private void generateSourceFileLists() throws IOException JavaDoc
155     {
156         generateSourceFileList(null);
157         Iterator JavaDoc iter = projectData.getPackages().iterator();
158         while (iter.hasNext())
159         {
160             PackageData packageData = (PackageData)iter.next();
161             generateSourceFileList(packageData);
162         }
163     }
164
165     private void generateSourceFileList(PackageData packageData)
166             throws IOException JavaDoc
167     {
168         String JavaDoc filename;
169         Collection JavaDoc sourceFiles;
170         if (packageData == null)
171         {
172             filename = "frame-sourcefiles.html";
173             sourceFiles = projectData.getSourceFiles();
174         }
175         else
176         {
177             filename = "frame-sourcefiles-" + packageData.getName() + ".html";
178             sourceFiles = packageData.getSourceFiles();
179         }
180
181         // sourceFiles may be sorted, but if so it's sorted by
182
// the full path to the file, and we only want to sort
183
// based on the file's basename.
184
Vector JavaDoc sortedSourceFiles = new Vector JavaDoc();
185         sortedSourceFiles.addAll(sourceFiles);
186         Collections.sort(sortedSourceFiles,
187                 new SourceFileDataBaseNameComparator());
188
189         File JavaDoc file = new File JavaDoc(destinationDir, filename);
190         PrintStream JavaDoc out = null;
191         try
192         {
193             out = new PrintStream JavaDoc(new FileOutputStream JavaDoc(file));
194
195             out
196                     .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
197             out
198                     .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
199
200             out.println("<html>");
201             out.println("<head>");
202             out
203                     .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>");
204             out.println("<title>Coverage Report Classes</title>");
205             out
206                     .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/main.css\"/>");
207             out.println("</head>");
208             out.println("<body>");
209             out.println("<h5>");
210             out.println(packageData == null ? "All Packages"
211                     : generatePackageName(packageData));
212             out.println("</h5>");
213             out.println("<div class=\"separator\">&nbsp;</div>");
214             out.println("<h5>Classes</h5>");
215             if (!sortedSourceFiles.isEmpty())
216             {
217                 out.println("<table width=\"100%\">");
218                 out.println("<tbody>");
219
220                 for (Iterator JavaDoc iter = sortedSourceFiles.iterator(); iter
221                         .hasNext();)
222                 {
223                     SourceFileData sourceFileData = (SourceFileData)iter.next();
224                     out.println("<tr>");
225                     String JavaDoc percentCovered;
226                     if (sourceFileData.getNumberOfValidLines() > 0)
227                         percentCovered = getPercentValue(sourceFileData
228                                 .getLineCoverageRate());
229                     else
230                         percentCovered = "N/A";
231                     out
232                             .println("<td nowrap=\"nowrap\"><a target=\"summary\" HREF=\""
233                                     + sourceFileData.getNormalizedName()
234                                     + ".html\">"
235                                     + sourceFileData.getBaseName()
236                                     + "</a> <i>("
237                                     + percentCovered
238                                     + ")</i></td>");
239                     out.println("</tr>");
240                 }
241                 out.println("</tbody>");
242                 out.println("</table>");
243             }
244
245             out.println("</body>");
246             out.println("</html>");
247         }
248         finally
249         {
250             if (out != null)
251             {
252                 out.close();
253             }
254         }
255     }
256
257     private void generateOverviews() throws IOException JavaDoc
258     {
259         generateOverview(null);
260         Iterator JavaDoc iter = projectData.getPackages().iterator();
261         while (iter.hasNext())
262         {
263             PackageData packageData = (PackageData)iter.next();
264             generateOverview(packageData);
265         }
266     }
267
268     private void generateOverview(PackageData packageData) throws IOException JavaDoc
269     {
270         Iterator JavaDoc iter;
271
272         String JavaDoc filename;
273         if (packageData == null)
274         {
275             filename = "frame-summary.html";
276         }
277         else
278         {
279             filename = "frame-summary-" + packageData.getName() + ".html";
280         }
281         File JavaDoc file = new File JavaDoc(destinationDir, filename);
282         PrintStream JavaDoc out = null;
283
284         try
285         {
286             out = new PrintStream JavaDoc(new FileOutputStream JavaDoc(file));
287
288             out
289                     .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
290             out
291                     .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
292
293             out.println("<html>");
294             out.println("<head>");
295             out
296                     .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>");
297             out.println("<title>Coverage Report</title>");
298             out
299                     .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/main.css\"/>");
300             out
301                     .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/sortabletable.css\"/>");
302             out
303                     .println("<script type=\"text/javascript\" SRC=\"js/popup.js\"></script>");
304             out
305                     .println("<script type=\"text/javascript\" SRC=\"js/sortabletable.js\"></script>");
306             out
307                     .println("<script type=\"text/javascript\" SRC=\"js/customsorttypes.js\"></script>");
308             out.println("</head>");
309             out.println("<body>");
310
311             out.print("<h5>Coverage Report - ");
312             out.print(packageData == null ? "All Packages"
313                     : generatePackageName(packageData));
314             out.println("</h5>");
315             out.println("<div class=\"separator\">&nbsp;</div>");
316             out.println("<table class=\"report\" id=\"packageResults\">");
317             out.println(generateTableHeader("Package", true));
318             out.println("<tbody>");
319
320             SortedSet JavaDoc packages;
321             if (packageData == null)
322             {
323                 // Output a summary line for all packages
324
out.println(generateTableRowForTotal());
325
326                 // Get packages
327
packages = projectData.getPackages();
328             }
329             else
330             {
331                 // Get subpackages
332
packages = projectData.getSubPackages(packageData.getName());
333             }
334
335             // Output a line for each package or subpackage
336
iter = packages.iterator();
337             while (iter.hasNext())
338             {
339                 PackageData subPackageData = (PackageData)iter.next();
340                 out.println(generateTableRowForPackage(subPackageData));
341             }
342
343             out.println("</tbody>");
344             out.println("</table>");
345             out.println("<script type=\"text/javascript\">");
346             out
347                     .println("var packageTable = new SortableTable(document.getElementById(\"packageResults\"),");
348             out
349                     .println(" [\"String\", \"Number\", \"Percentage\", \"Percentage\", \"FormattedNumber\"]);");
350             out.println("packageTable.sort(0);");
351             out.println("</script>");
352
353             // Get the list of source files in this package
354
Collection JavaDoc sourceFiles;
355             if (packageData == null)
356             {
357                 PackageData defaultPackage = (PackageData)projectData
358                         .getChild("");
359                 if (defaultPackage != null)
360                 {
361                     sourceFiles = defaultPackage.getSourceFiles();
362                 }
363                 else
364                 {
365                     sourceFiles = new TreeSet JavaDoc();
366                 }
367             }
368             else
369             {
370                 sourceFiles = packageData.getSourceFiles();
371             }
372
373             // Output a line for each source file
374
if (sourceFiles.size() > 0)
375             {
376                 out.println("<div class=\"separator\">&nbsp;</div>");
377                 out.println("<table class=\"report\" id=\"classResults\">");
378                 out.println(generateTableHeader("Classes in this Package",
379                         false));
380                 out.println("<tbody>");
381
382                 iter = sourceFiles.iterator();
383                 while (iter.hasNext())
384                 {
385                     SourceFileData sourceFileData = (SourceFileData)iter.next();
386                     out.println(generateTableRowsForSourceFile(sourceFileData));
387                 }
388
389                 out.println("</tbody>");
390                 out.println("</table>");
391                 out.println("<script type=\"text/javascript\">");
392                 out
393                         .println("var classTable = new SortableTable(document.getElementById(\"classResults\"),");
394                 out
395                         .println(" [\"String\", \"Percentage\", \"Percentage\", \"FormattedNumber\"]);");
396                 out.println("classTable.sort(0);");
397                 out.println("</script>");
398             }
399
400             out.println(generateFooter());
401
402             out.println("</body>");
403             out.println("</html>");
404         }
405         finally
406         {
407             if (out != null)
408             {
409                 out.close();
410             }
411         }
412     }
413
414     private void generateSourceFiles()
415     {
416         Iterator JavaDoc iter = projectData.getSourceFiles().iterator();
417         while (iter.hasNext())
418         {
419             SourceFileData sourceFileData = (SourceFileData)iter.next();
420             try
421             {
422                 generateSourceFile(sourceFileData);
423             }
424             catch (IOException JavaDoc e)
425             {
426                 LOGGER.info("Could not generate HTML file for source file "
427                         + sourceFileData.getName() + ": "
428                         + e.getLocalizedMessage());
429             }
430         }
431     }
432
433     private void generateSourceFile(SourceFileData sourceFileData)
434             throws IOException JavaDoc
435     {
436         if (!sourceFileData.containsInstrumentationInfo())
437         {
438             LOGGER.info("Data file does not contain instrumentation "
439                     + "information for the file " + sourceFileData.getName()
440                     + ". Ensure this class was instrumented, and this "
441                     + "data file contains the instrumentation information.");
442         }
443
444         String JavaDoc filename = sourceFileData.getNormalizedName() + ".html";
445         File JavaDoc file = new File JavaDoc(destinationDir, filename);
446         PrintStream JavaDoc out = null;
447
448         try
449         {
450             out = new PrintStream JavaDoc(new FileOutputStream JavaDoc(file));
451
452             out
453                     .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
454             out
455                     .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
456
457             out.println("<html>");
458             out.println("<head>");
459             out
460                     .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>");
461             out.println("<title>Coverage Report</title>");
462             out
463                     .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/main.css\"/>");
464             out
465                     .println("<script type=\"text/javascript\" SRC=\"js/popup.js\"></script>");
466             out.println("</head>");
467             out.println("<body>");
468             out.print("<h5>Coverage Report - ");
469             String JavaDoc classPackageName = sourceFileData.getPackageName();
470             if ((classPackageName != null) && classPackageName.length() > 0)
471             {
472                 out.print(classPackageName + ".");
473             }
474             out.print(sourceFileData.getBaseName());
475             out.println("</h5>");
476
477             // Output the coverage summary for this class
478
out.println("<div class=\"separator\">&nbsp;</div>");
479             out.println("<table class=\"report\">");
480             out.println(generateTableHeader("Classes in this File", false));
481             out.println(generateTableRowsForSourceFile(sourceFileData));
482             out.println("</table>");
483
484             // Output the coverage summary for methods in this class
485
// TODO
486

487             // Output this class's source code with syntax and coverage highlighting
488
out.println("<div class=\"separator\">&nbsp;</div>");
489             out.println(generateHtmlizedJavaSource(sourceFileData));
490
491             out.println(generateFooter());
492
493             out.println("</body>");
494             out.println("</html>");
495         }
496         finally
497         {
498             if (out != null)
499             {
500                 out.close();
501             }
502         }
503     }
504
505     private String JavaDoc generateHtmlizedJavaSource(SourceFileData sourceFileData)
506     {
507         File JavaDoc sourceFile = null;
508         try
509         {
510             sourceFile = finder.getFileForSource(sourceFileData.getName());
511         }
512         catch (IOException JavaDoc e)
513         {
514             return "<p>Unable to locate " + sourceFileData.getName()
515                     + ". Have you specified the source directory?</p>";
516         }
517
518         BufferedReader JavaDoc br = null;
519         try
520         {
521             br = new BufferedReader JavaDoc(new FileReader JavaDoc(sourceFile));
522         }
523         catch (FileNotFoundException JavaDoc e)
524         {
525             return "<p>Unable to open " + sourceFile.getAbsolutePath() + "</p>";
526         }
527
528         StringBuffer JavaDoc ret = new StringBuffer JavaDoc();
529         ret
530                 .append("<table cellspacing=\"0\" cellpadding=\"0\" class=\"src\">\n");
531         try
532         {
533             String JavaDoc lineStr;
534             JavaToHtml javaToHtml = new JavaToHtml();
535             int lineNumber = 1;
536             while ((lineStr = br.readLine()) != null)
537             {
538                 ret.append("<tr>");
539                 if (sourceFileData.isValidSourceLineNumber(lineNumber))
540                 {
541                     long numberOfHits = sourceFileData.getHitCount(lineNumber);
542                     ret.append(" <td class=\"numLineCover\">&nbsp;"
543                             + lineNumber + "</td>");
544                     if (numberOfHits > 0)
545                     {
546                         ret.append(" <td class=\"nbHitsCovered\">&nbsp;"
547                                 + numberOfHits + "</td>");
548                         ret
549                                 .append(" <td class=\"src\"><pre class=\"src\">&nbsp;"
550                                         + javaToHtml.process(lineStr)
551                                         + "</pre></td>");
552                     }
553                     else
554                     {
555                         ret.append(" <td class=\"nbHitsUncovered\">&nbsp;"
556                                 + numberOfHits + "</td>");
557                         ret
558                                 .append(" <td class=\"src\"><pre class=\"src\"><span class=\"srcUncovered\">&nbsp;"
559                                         + javaToHtml.process(lineStr)
560                                         + "</span></pre></td>");
561                     }
562                 }
563                 else
564                 {
565                     ret.append(" <td class=\"numLine\">&nbsp;" + lineNumber
566                             + "</td>");
567                     ret.append(" <td class=\"nbHits\">&nbsp;</td>\n");
568                     ret.append(" <td class=\"src\"><pre class=\"src\">&nbsp;"
569                             + javaToHtml.process(lineStr) + "</pre></td>");
570                 }
571                 ret.append("</tr>\n");
572                 lineNumber++;
573             }
574         }
575         catch (IOException JavaDoc e)
576         {
577             ret.append("<tr><td>Error reading from file "
578                     + sourceFile.getAbsolutePath() + ": "
579                     + e.getLocalizedMessage() + "</td></tr>\n");
580         }
581         finally
582         {
583             try
584             {
585                 br.close();
586             }
587             catch (IOException JavaDoc e)
588             {
589             }
590         }
591
592         ret.append("</table>\n");
593
594         return ret.toString();
595     }
596
597     private static String JavaDoc generateFooter()
598     {
599         return "<div class=\"footer\">Report generated by "
600                 + "<a HREF=\"http://cobertura.sourceforge.net/\" target=\"_top\">Cobertura</a> "
601                 + Header.version() + " on "
602                 + DateFormat.getInstance().format(new Date JavaDoc()) + ".</div>";
603     }
604
605     private static String JavaDoc generateTableHeader(String JavaDoc title,
606             boolean showColumnForNumberOfClasses)
607     {
608         StringBuffer JavaDoc ret = new StringBuffer JavaDoc();
609         ret.append("<thead>");
610         ret.append("<tr>");
611         ret.append(" <td class=\"heading\">" + title + "</td>");
612         if (showColumnForNumberOfClasses)
613         {
614             ret.append(" <td class=\"heading\"># Classes</td>");
615         }
616         ret.append(" <td class=\"heading\">"
617                 + generateHelpURL("Line Coverage",
618                         "The percent of lines executed by this test run.")
619                 + "</td>");
620         ret.append(" <td class=\"heading\">"
621                 + generateHelpURL("Branch Coverage",
622                         "The percent of branches executed by this test run.")
623                 + "</td>");
624         ret
625                 .append(" <td class=\"heading\">"
626                         + generateHelpURL(
627                                 "Complexity",
628                                 "Average McCabe's cyclomatic code complexity for all methods. This is basically a count of the number of different code paths in a method (incremented by 1 for each if statement, while loop, etc.)")
629                         + "</td>");
630         ret.append("</tr>");
631         ret.append("</thead>");
632         return ret.toString();
633     }
634
635     private static String JavaDoc generateHelpURL(String JavaDoc text, String JavaDoc description)
636     {
637         StringBuffer JavaDoc ret = new StringBuffer JavaDoc();
638         boolean popupTooltips = false;
639         if (popupTooltips)
640         {
641             ret
642                     .append("<a class=\"hastooltip\" HREF=\"help.html\" onclick=\"popupwindow('help.html'); return false;\">");
643             ret.append(text);
644             ret.append("<span>" + description + "</span>");
645             ret.append("</a>");
646         }
647         else
648         {
649             ret
650                     .append("<a class=\"dfn\" HREF=\"help.html\" onclick=\"popupwindow('help.html'); return false;\">");
651             ret.append(text);
652             ret.append("</a>");
653         }
654         return ret.toString();
655     }
656
657     private String JavaDoc generateTableRowForTotal()
658     {
659         StringBuffer JavaDoc ret = new StringBuffer JavaDoc();
660         double ccn = complexity.getCCNForProject(projectData);
661
662         ret.append(" <tr>");
663         ret.append("<td><b>All Packages</b></td>");
664         ret.append("<td class=\"value\">"
665                 + projectData.getNumberOfSourceFiles() + "</td>");
666         ret.append(generateTableColumnsFromData(projectData, ccn));
667         ret.append("</tr>");
668         return ret.toString();
669     }
670
671     private String JavaDoc generateTableRowForPackage(PackageData packageData)
672     {
673         StringBuffer JavaDoc ret = new StringBuffer JavaDoc();
674         String JavaDoc url1 = "frame-summary-" + packageData.getName() + ".html";
675         String JavaDoc url2 = "frame-sourcefiles-" + packageData.getName() + ".html";
676         double ccn = complexity.getCCNForPackage(packageData);
677
678         ret.append(" <tr>");
679         ret.append("<td><a HREF=\"" + url1
680                 + "\" onclick='parent.sourceFileList.location.href=\"" + url2
681                 + "\"'>" + generatePackageName(packageData) + "</a></td>");
682         ret.append("<td class=\"value\">" + packageData.getNumberOfChildren()
683                 + "</td>");
684         ret.append(generateTableColumnsFromData(packageData, ccn));
685         ret.append("</tr>");
686         return ret.toString();
687     }
688
689     private String JavaDoc generateTableRowsForSourceFile(SourceFileData sourceFileData)
690     {
691         StringBuffer JavaDoc ret = new StringBuffer JavaDoc();
692         String JavaDoc sourceFileName = sourceFileData.getNormalizedName();
693         // TODO: ccn should be calculated per-class, not per-file
694
double ccn = complexity.getCCNForSourceFile(sourceFileData);
695
696         Iterator JavaDoc iter = sourceFileData.getClasses().iterator();
697         while (iter.hasNext())
698         {
699             ClassData classData = (ClassData)iter.next();
700             ret
701                     .append(generateTableRowForClass(classData, sourceFileName,
702                             ccn));
703         }
704
705         return ret.toString();
706     }
707
708     private String JavaDoc generateTableRowForClass(ClassData classData,
709             String JavaDoc sourceFileName, double ccn)
710     {
711         StringBuffer JavaDoc ret = new StringBuffer JavaDoc();
712
713         ret.append(" <tr>");
714         // TODO: URL should jump straight to the class (only for inner classes?)
715
ret.append("<td><a HREF=\"" + sourceFileName
716                 + ".html\">" + classData.getBaseName() + "</a></td>");
717         ret.append(generateTableColumnsFromData(classData, ccn));
718         ret.append("</tr>\n");
719         return ret.toString();
720     }
721
722     /**
723      * Return a string containing three HTML table cells. The first
724      * cell contains a graph showing the line coverage, the second
725      * cell contains a graph showing the branch coverage, and the
726      * third cell contains the code complexity.
727      *
728      * @param ccn The code complexity to display. This should be greater
729      * than 1.
730      * @return A string containing the HTML for three table cells.
731      */

732     private static String JavaDoc generateTableColumnsFromData(CoverageData coverageData,
733             double ccn)
734     {
735         int numLinesCovered = coverageData.getNumberOfCoveredLines();
736         int numLinesValid = coverageData.getNumberOfValidLines();
737         int numBranchesCovered = coverageData.getNumberOfCoveredBranches();
738         int numBranchesValid = coverageData.getNumberOfValidBranches();
739
740         // The "hidden" CSS class is used below to write the ccn without
741
// any formatting so that the table column can be sorted correctly
742
return "<td>" + generatePercentResult(numLinesCovered, numLinesValid)
743                 +"</td><td>"
744                 + generatePercentResult(numBranchesCovered, numBranchesValid)
745                 + "</td><td class=\"value\"><span class=\"hidden\">"
746                 + ccn + ";</span>" + getDoubleValue(ccn) + "</td>";
747     }
748
749     /**
750      * This is crazy complicated, and took me a while to figure out,
751      * but it works. It creates a dandy little percentage meter, from
752      * 0 to 100.
753      * @param dividend The number of covered lines or branches.
754      * @param divisor The number of valid lines or branches.
755      * @return A percentage meter.
756      */

757     private static String JavaDoc generatePercentResult(int dividend, int divisor)
758     {
759         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
760
761         sb.append("<table cellpadding=\"0px\" cellspacing=\"0px\" class=\"percentgraph\"><tr class=\"percentgraph\"><td align=\"right\" class=\"percentgraph\" width=\"40\">");
762         if (divisor > 0)
763             sb.append(getPercentValue((double)dividend / divisor));
764         else
765             sb.append(generateHelpURL(
766                     "N/A",
767                     "Line coverage and branch coverage will appear as \"Not Applicable\" when Cobertura can not find line number information in the .class file. This happens for stub and skeleton classes, interfaces, or when the class was not compiled with \"debug=true.\""));
768         sb.append("</td><td class=\"percentgraph\"><div class=\"percentgraph\">");
769         if (divisor > 0)
770         {
771             sb.append("<div class=\"greenbar\" style=\"width:"
772                     + (dividend * 100 / divisor) + "px\">");
773             sb.append("<span class=\"text\">");
774             sb.append(dividend);
775             sb.append("/");
776             sb.append(divisor);
777         }
778         else
779         {
780             sb.append("<div class=\"na\" style=\"width:100px\">");
781             sb.append("<span class=\"text\">");
782             sb.append(generateHelpURL(
783                     "N/A",
784                     "Line coverage and branch coverage will appear as \"Not Applicable\" when Cobertura can not find line number information in the .class file. This happens for stub and skeleton classes, interfaces, or when the class was not compiled with \"debug=true.\""));
785         }
786         sb.append("</span></div></div></td></tr></table>");
787
788         return sb.toString();
789     }
790
791     private static String JavaDoc getDoubleValue(double value)
792     {
793         NumberFormat JavaDoc formatter;
794         formatter = new DecimalFormat JavaDoc();
795         return formatter.format(value);
796     }
797
798     private static String JavaDoc getPercentValue(double value)
799     {
800         NumberFormat JavaDoc formatter;
801         formatter = NumberFormat.getPercentInstance();
802         return formatter.format(value);
803     }
804
805 }
806
Popular Tags