View Javadoc

1   package org.apache.maven.jcoveragereport;
2   
3   /* ====================================================================
4    *   Copyright 2001-2004 The Apache Software Foundation.
5    *
6    *   Licensed under the Apache License, Version 2.0 (the "License");
7    *   you may not use this file except in compliance with the License.
8    *   You may obtain a copy of the License at
9    *
10   *       http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing, software
13   *   distributed under the License is distributed on an "AS IS" BASIS,
14   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *   See the License for the specific language governing permissions and
16   *   limitations under the License.
17   * ====================================================================
18   */
19  
20  import java.io.BufferedReader;
21  import java.io.BufferedWriter;
22  import java.io.File;
23  import java.io.FileReader;
24  import java.io.FileWriter;
25  import java.io.IOException;
26  import java.io.PrintWriter;
27  import java.text.NumberFormat;
28  import java.util.ArrayList;
29  import java.util.Iterator;
30  import java.util.List;
31  
32  import org.apache.oro.text.perl.Perl5Util;
33  
34  /**
35   * @author Emmanuel Venisse
36   * @version $Id: CoverageReport.java 328198 2005-10-25 00:28:22Z aheritier $
37   */
38  public class CoverageReport
39  {
40      /** coverage data */
41      private Coverage coverage;
42  
43      /**
44       * Create a coverage report
45       * @param coverage coverage data
46       */
47      public CoverageReport(Coverage coverage)
48      {
49          this.coverage = coverage;
50      }
51  
52      public void generate(String dir) throws IOException
53      {
54          File directory = new File(dir);
55          directory.mkdirs();
56  
57          generateSourceFiles(directory);
58          generateFrameset(directory);
59          generatePackageList(directory);
60          generateClassList(directory);
61          generateOverview(directory);
62      }
63  
64      private void generateFrameset(File dir) throws IOException
65      {
66          File fsFile = new File(dir, "index.html");
67          PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fsFile)));
68          pw.println("<html>");
69          pw.println("<head>");
70          pw.println("<title>unit tests coverage report</title>");
71          pw.println("</head>");
72          pw.println("<FRAMESET cols=\"20%,80%\">");
73          pw.println("<FRAMESET rows=\"30%,70%\">");
74          pw.println("<FRAME src=\"overview-frame.html\" name=\"packageListFrame\" title=\"All Packages\">");
75          pw.println("<FRAME src=\"allclasses-frame.html\" name=\"packageFrame\" title=\"All classes and interfaces (except non-static nested types)\">");
76          pw.println("</FRAMESET>");
77          pw.println("<FRAME src=\"overview-summary.html\" name=\"classFrame\" title=\"Package, class and interface descriptions\" scrolling=\"yes\">");
78          pw.println("<NOFRAMES>");
79          pw.println("This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.");
80          pw.println("<BR>");
81          pw.println("Link to<A HREF=\"overview-summary.html\">Non-frame version.</A>");
82          pw.println("</NOFRAMES>");
83          pw.println("</FRAMESET>");
84          pw.println("</html>");
85          pw.close();
86      }
87  
88      private void generatePackageList(File dir) throws IOException
89      {
90          File fsFile = new File(dir, "overview-frame.html");
91          PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fsFile)));
92          pw.println("<html>");
93          pw.println("<head>");
94          pw.println("<title>unit tests coverage report</title>");
95          pw.println("<link rel =\"stylesheet\" type=\"text/css\" href=\"style.css\" title=\"Style\">");
96          pw.println("</head>");
97          pw.println("<body>");
98          pw.println("<span class=\"title\">Coverage report</span>");
99          pw.println("<table>");
100         pw.println("<tr>");
101         pw.println("<td nowrap=\"nowrap\">");
102         pw.println("<a href=\"overview-summary.html\" target=\"classFrame\">Overview</a><br>");
103         pw.println("<a href=\"allclasses-frame.html\" target=\"packageFrame\">All classes</a>");
104         pw.println("</td>");
105         pw.println("</tr>");
106         pw.println("</table>");
107         pw.println("<p>");
108         pw.println("<table>");
109         pw.println("<tr>");
110         pw.println("<td nowrap=\"nowrap\"><span class=\"title2\">All packages</span></td>");
111         pw.println("</tr>");
112         pw.println("<tr>");
113         pw.println("<td nowrap=\"nowrap\">");
114 
115         for (Iterator iter = coverage.getPackagesSortedByName().iterator(); iter.hasNext(); )
116         {
117             Package pkg = (Package) iter.next();
118             String url = pkg.getDirectory() + "/package-frame.html";
119             pw.println("<a href=\"" + url + "\" target=\"packageFrame\">" + pkg.getName() + "</a><br>");
120         }
121 
122         pw.println("</td>");
123         pw.println("</tr>");
124         pw.println("</table>");
125         pw.println("</body>");
126         pw.println("</html>");
127         pw.close();
128 
129         for (Iterator iter = coverage.getPackagesSortedByName().iterator(); iter.hasNext(); )
130         {
131             Package pkg = (Package) iter.next();
132             generateClassList(dir, pkg);
133             generateOverview(dir, pkg);
134         }
135     }
136 
137     private void generateClassList(File dir) throws IOException
138     {
139         generateClassList(dir, null);
140     }
141 
142     private void generateClassList(File dir, Package pkg) throws IOException
143     {
144         String filename;
145         String rootRef;
146         List classes;
147         String urlDirectory = "";
148         if (pkg == null)
149         {
150             rootRef = "";
151             filename = "allclasses-frame.html";
152             classes = coverage.getClassesSortedByName();
153         }
154         else
155         {
156             rootRef = getRelativePath(pkg.getName() + "/");
157             filename = pkg.getDirectory() + "/package-frame.html";
158             classes = pkg.getClassesSortedByName();
159             urlDirectory = ".";
160         }
161         File fsFile = new File(dir, filename);
162         PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fsFile)));
163         pw.println("<html>");
164         pw.println("<head>");
165         pw.println("<title>unit tests coverage report</title>");
166         pw.println("<link rel =\"stylesheet\" type=\"text/css\" href=\"" + rootRef + "style.css\" title=\"Style\">");
167         pw.println("</head>");
168         pw.println("<body>");
169         if (pkg != null)
170         {
171             pw.println("<a href=\"package-summary.html\" target=\"classFrame\">" + pkg.getName() + "</a><br>");
172             pw.println("<p>");
173         }
174         pw.println("<span class=\"title\">All classes</span>");
175         pw.println("<table>");
176         pw.println("<tr>");
177         pw.println("<td nowrap=\"nowrap\">");
178 
179         for (Iterator iter = classes.iterator(); iter.hasNext(); )
180         {
181             Clazz theClass = (Clazz) iter.next();
182             if (pkg == null)
183             {
184                 urlDirectory = theClass.getFile().substring(0, theClass.getFile().lastIndexOf("/"));
185             }
186             String classFilename = theClass.getName() + ".html";
187             if (theClass.getFile().endsWith("/" + theClass.getName() + ".java"))
188             {
189                 pw.println("<a href=\"" + urlDirectory + "/" + classFilename + "\" target=\"classFrame\">" + theClass.getName() + "</a><span class=\"text_italic\">&nbsp;(" + getPercentValue(theClass.getLineRate()) + ")</span><br>");
190             }
191         }
192 
193         pw.println("</td>");
194         pw.println("</tr>");
195         pw.println("</table>");
196         pw.println("</body>");
197         pw.println("</html>");
198         pw.close();
199     }
200 
201     private void generateOverview(File dir) throws IOException
202     {
203         generateOverview(dir, null);
204     }
205 
206     private void generateOverview(File dir, Package thePackage) throws IOException
207     {
208         String filename = "overview-summary.html";
209         String rootRef;
210         if (thePackage != null)
211         {
212             filename = thePackage.getDirectory() + "/package-summary.html";
213             rootRef = getRelativePath(thePackage.getName() + "/");
214         }
215         else
216         {
217             rootRef = "";
218         }
219         File fsFile = new File(dir, filename);
220         PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fsFile)));
221         pw.println("<html>");
222         pw.println("<head>");
223         pw.println("<title>unit tests coverage report</title>");
224         pw.println("<link rel =\"stylesheet\" type=\"text/css\" href=\"" + rootRef + "style.css\" title=\"Style\">");
225         pw.println("</head>");
226         pw.println("<body>");
227         pw.println("<span class=\"title\">Coverage report</span>");
228         pw.println("<p>");
229         pw.println("<table class=\"report\" cellpadding=\"0\" cellspacing=\"0\">");
230         pw.println("<tr class=\"report\">");
231         pw.println("<th class=\"report\">&nbsp;</th>");
232         pw.println("<th class=\"report\">Files</th>");
233         pw.println("<th class=\"report\">%line</th>");
234         pw.println("<th class=\"report\">%branch</th>");
235         pw.println("</tr>");
236         pw.println("<tr class=\"report\">");
237         if (thePackage != null)
238         {
239             pw.println("<td class=\"reportText\">" + thePackage.getName() + "</td>");
240             pw.println("<td class=\"reportValue\">" + thePackage.getClasses().size() + "</td>");
241             pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(thePackage.getCoveredPercentLine())) + "</td>");
242             pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(thePackage.getCoveredPercentBranch())) + "</td>");
243         }
244         else
245         {
246             pw.println("<td class=\"reportText\">Project</td>");
247             pw.println("<td class=\"reportValue\">" + coverage.getClasses().size() + "</td>");
248             pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(coverage.getCoveredPercentLine())) + "</td>");
249             pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(coverage.getCoveredPercentBranch())) + "</td>");
250         }
251         pw.println("</tr>");
252         List pkgList = null;
253         if (thePackage != null)
254         {
255             pkgList = coverage.getSubPackage(thePackage);
256             if (pkgList.size() > 0)
257             {
258                 pw.println("<tr>");
259                 pw.println("<td class=\"spacer\" colspan=\"4\"><span class=\"title2\">Packages</span></td>");
260                 pw.println("</tr>");
261                 for (Iterator iter = pkgList.iterator(); iter.hasNext(); )
262                 {
263                     Package pkg = (Package) iter.next();
264                     pw.println("<tr class=\"report\">");
265                     String subPkgDir = pkg.getDirectory().substring(thePackage.getDirectory().length() + 1);
266                     pw.println("<td class=\"reportText\"><a href=\"" + subPkgDir + "/package-summary.html\">" + pkg.getName() + "</a></td>");
267                     pw.println("<td class=\"reportValue\">" + pkg.getClasses().size() + "</td>");
268                     pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(pkg.getCoveredPercentLine())) + "</td>");
269                     pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(pkg.getCoveredPercentBranch())) + "</td>");
270                     pw.println("</tr>");
271                 }
272             }
273             if (thePackage.getClasses().size() > 0)
274             {
275                 pw.println("<tr>");
276                 pw.println("<td class=\"spacer\" colspan=\"4\"><span class=\"title2\">Classes</span></td>");
277                 pw.println("</tr>");
278                 for (Iterator it = thePackage.getClassesSortedByName().iterator(); it.hasNext(); )
279                 {
280                     Clazz cl = (Clazz) it.next();
281                     if (cl.getFile().indexOf("[Unknown]")<0)
282                     {
283                         String classFilename = getShortFilename(cl);
284                         pw.println("<tr class=\"report\">");
285                         pw.println("<td class=\"reportText\" colspan=\"2\"><a href=\"" + classFilename + "\">" + cl.getName() + "</a></td>");
286                         pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(cl.getLineRate())) + "</td>");
287                         pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(cl.getBranchRate())) + "</td>");
288                         pw.println("</tr>");
289                     }
290                 }
291             }
292         }
293         else
294         {
295             pkgList = coverage.getPackages();
296             if (pkgList.size() > 0)
297             {
298                 pw.println("<tr>");
299                 pw.println("<td class=\"spacer\" colspan=\"4\"><span class=\"title2\">Packages</span></td>");
300                 pw.println("</tr>");
301                 for (Iterator iter = coverage.getPackagesSortedByName().iterator(); iter.hasNext(); )
302                 {
303                     Package pkg = (Package) iter.next();
304                     pw.println("<tr class=\"report\">");
305                     pw.println("<td class=\"reportText\"><a href=\"" + pkg.getDirectory() + "/package-summary.html\">" + pkg.getName() + "</a></td>");
306                     pw.println("<td class=\"reportValue\">" + pkg.getClasses().size() + "</td>");
307                     pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(pkg.getCoveredPercentLine())) + "</td>");
308                     pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(pkg.getCoveredPercentBranch())) + "</td>");
309                     pw.println("</tr>");
310                 }
311             }
312             if (coverage.getClasses().size() > 0)
313             {
314                 List classesList = new ArrayList();
315                 for (Iterator iter = coverage.getClassesSortedByName().iterator(); iter.hasNext(); )
316                 {
317                     Clazz cl = (Clazz) iter.next();
318                     if (cl.getPackageName() == null
319                         || cl.getPackageName().equals(""))
320                     {
321                         classesList.add(cl);
322                     }
323                 }
324                 if (classesList.size() > 0)
325                 {
326                     pw.println("<tr>");
327                     pw.println("<td class=\"spacer\" colspan=\"4\"><span class=\"title2\">Classes</span></td>");
328                     pw.println("</tr>");
329                     for (Iterator iter = classesList.iterator(); iter.hasNext(); )
330                     {
331                         Clazz cl = (Clazz) iter.next();
332                         if (cl.getFile().indexOf("[Unknown]")<0)
333                         {
334                             String classFilename = getShortFilename(cl);
335                             pw.println("<tr class=\"report\">");
336                             pw.println("<td class=\"reportText\" colspan=\"2\"><a href=\"" + classFilename + "\">" + cl.getName() + "</a></td>");
337                             pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(cl.getLineRate())) + "</td>");
338                             pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(cl.getBranchRate())) + "</td>");
339                             pw.println("</tr>");
340                         }
341                     }
342                 }
343             }
344         }
345         pw.println("</table>");
346         pw.println(generateFooter());
347         pw.println("</body>");
348         pw.println("</html>");
349         pw.close();
350     }
351 
352     /**
353      * Gets the name to output the file to.
354      * 
355      * @param cl  the class to get the filename for
356      * @return the filename
357      */
358     private String getShortFilename(Clazz cl) {
359         String name = cl.getFile().substring(cl.getFile().lastIndexOf("/")+1, cl.getFile().lastIndexOf("."));
360         if (cl.getName().indexOf('$') >= 0) {
361             name = name + "_" + cl.getName().substring(cl.getName().indexOf('$') + 1);
362         }
363         return name + ".html";
364     }
365 
366     /**
367      * Gets the name to output the file to.
368      * 
369      * @param cl  the class to get the filename for
370      * @return the filename
371      */
372     private String getFullFilename(Clazz cl) {
373         String name = cl.getFile().substring(0, cl.getFile().lastIndexOf("."));
374         if (cl.getName().indexOf('$') >= 0) {
375             name = name + "_" + cl.getName().substring(cl.getName().indexOf('$') + 1);
376         }
377         return name + ".html";
378     }
379 
380     private void generateSourceFiles(File dir) throws IOException
381     {
382         for (Iterator iter = coverage.getClasses().iterator(); iter.hasNext(); )
383         {
384             Clazz theClass = (Clazz) iter.next();
385             File file = new File(coverage.getSrcDirectory(), theClass.getFile());
386             if (file.exists())
387             {
388                 generateSourceFile(dir, theClass);
389             }
390         }
391     }
392 
393     private void generateSourceFile(File directory, Clazz theClass) throws IOException
394     {
395         String srcOutputFilename = getFullFilename(theClass);
396         File srcOutputFile = new File(directory, srcOutputFilename);
397         File dirOutputFile = srcOutputFile.getParentFile();
398         if (dirOutputFile != null)
399         {
400             dirOutputFile.mkdirs();
401         }
402 
403         PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(srcOutputFile)));
404         pw.println("<html>");
405         pw.println("<head>");
406         pw.println("<title>unit tests coverage</title>");
407         String rootRef = getRelativePath(theClass.getPackageName());
408         pw.println("<link rel =\"stylesheet\" type=\"text/css\" href=\"" + rootRef + "style.css\" title=\"Style\">");
409         pw.println("</head>");
410         pw.println("<body>");
411         pw.println("<span class=\"title\">Coverage report</span>");
412         pw.println("<p>");
413         pw.println("  <table cellspacing=\"0\" cellpadding=\"0\" class=\"report\">");
414         pw.println("  <tr class=\"report\">");
415         pw.println("    <th class=\"report\">&nbsp;</th>");
416         pw.println("    <th class=\"report\">%line</th>");
417         pw.println("    <th class=\"report\">%branch</th>");
418         pw.println("  </tr>");
419         pw.println("  <tr class=\"report\">");
420         pw.println("    <td class=\"reportText\"><span class=\"text\">" + theClass.getPackageName() + "." + theClass.getName() + "</span></td>");
421         pw.println("    <td class=\"reportValue\">" + generatePercentResult(getPercentValue(theClass.getLineRate())) + "</td>");
422         pw.println("    <td class=\"reportValue\">" + generatePercentResult(getPercentValue(theClass.getBranchRate())) + "</td>");
423         pw.println("  </tr>");
424         pw.println("  </table>");
425         pw.println("  <p>");
426         pw.println("  <table cellspacing=\"0\" cellpadding=\"0\" class=\"src\">");
427 
428         BufferedReader br = new BufferedReader(new FileReader(new File(coverage.getSrcDirectory(), theClass.getFile())));
429         String lineStr;
430         int numLigne = 1;
431         while ((lineStr = br.readLine()) != null)
432         {
433             Line theLine = (Line) theClass.getLinesMap().get(new Integer(numLigne));
434             int nbHits = 0;
435             if (theLine != null)
436             {
437                 nbHits = theLine.getNbHits();
438             }
439             pw.println("    <tr>");
440             if (theLine != null)
441             {
442                 pw.println("      <td class=\"numLineCover\">&nbsp;" + numLigne + "</td>");
443                 if (nbHits > 0)
444                 {
445                     pw.println("      <td class=\"nbHitsCovered\">&nbsp;" + theLine.getNbHits() + "</td>");
446                     pw.println("      <td class=\"src\"><pre class=\"src\">&nbsp;" + JavaToHtml.syntaxHighlight(lineStr) + "</pre></td>");
447                 }
448                 else
449                 {
450                     pw.println("      <td class=\"nbHitsUncovered\">&nbsp;" + theLine.getNbHits() + "</td>");
451                     pw.println("      <td class=\"src\"><pre class=\"src\"><span class=\"srcUncovered\">&nbsp;"+ JavaToHtml.syntaxHighlight(lineStr) + "</span></pre></td>");
452                 }
453             }
454             else
455             {
456                 pw.println("      <td class=\"numLine\">&nbsp;" + numLigne + "</td>");
457                 pw.println("      <td class=\"nbHits\">&nbsp;</td>");
458                 pw.println("      <td class=\"src\"><pre class=\"src\">&nbsp;" +  JavaToHtml.syntaxHighlight(lineStr) + "</pre></td>");
459             }
460             pw.println("    </tr>");
461             numLigne++;
462         }
463         pw.println("  </table>");
464         pw.println(generateFooter());
465         pw.println("</body>");
466         pw.println("</html>");
467         br.close();
468         pw.close();
469     }
470 
471     private String generateFooter()
472     {
473         StringBuffer sb = new StringBuffer();
474         sb.append("<p>");
475         sb.append("<table cellpadding=\"0\" cellspacing=\"0\" class=\"report\">");
476         sb.append("  <tr class=\"report\">");
477         sb.append("    <td class=\"reportText\"><span class=\"text\">");
478         sb.append("    This report is generated by <a href=\"http://www.jcoverage.com\">jcoverage</a>, <a href=\"http://maven.apache.org\">Maven</a> and <a href=\"http://maven.apache.org/maven-1.x/reference/plugins/jcoverage/\">Maven JCoverage Plugin</a>.");
479         sb.append("    </span></td>");
480         sb.append("  </tr>");
481         sb.append("</table>");
482         return sb.toString();
483     }
484 
485     private String generatePercentResult(String percentValue)
486     {
487         if (percentValue.endsWith("%"))
488         {
489             percentValue = percentValue.substring(0, percentValue.length() - 1);
490         }
491         double rest = 0;
492         try
493         {
494             rest = 100d - new Double(percentValue).doubleValue();
495         }
496         catch(NumberFormatException e)
497         {
498             rest = 0;
499         }
500         StringBuffer sb = new StringBuffer();
501         sb.append("<table class=\"percentGraph\" cellpadding=\"0\" cellspacing=\"0\" align=\"right\">");
502         sb.append("<tr>");
503         sb.append("<td><span class=\"text\">" + percentValue + "%&nbsp;</span></td>");
504         sb.append("<td>");
505         sb.append("<table class=\"percentGraph\" cellpadding=\"0\" cellspacing=\"0\">");
506         sb.append("<tr>");
507         sb.append("<td class=\"percentCovered\" width=\"" + percentValue + "\"></td>");
508         sb.append("<td class=\"percentUnCovered\" width=\"" + String.valueOf(rest) + "\"></td>");
509         sb.append("</tr>");
510         sb.append("</table>");
511         sb.append("</td>");
512         sb.append("</tr>");
513         sb.append("</table>");
514         return sb.toString();
515     }
516 
517     private String getRelativePath(String path)
518     {
519         if (path != null && !path.equals(""))
520         {
521             return new Perl5Util().substitute("s/[^\\.]*(\\.|$)/..\\//g", path);
522         }
523         else
524         {
525             return "";
526         }
527     }
528 
529     private String getPercentValue(String value)
530     {
531         if (value.endsWith("%"))
532         {
533             value = value.substring(0, value.length() - 1);
534         }
535         double percent = 0;
536         try
537         {
538             percent = new Double(value).doubleValue();
539         }
540         catch(NumberFormatException e)
541         {
542             percent = 0;
543         }
544         NumberFormat percentFormatter;
545 
546         percentFormatter = NumberFormat.getPercentInstance();
547         return percentFormatter.format(percent);
548     }
549 }