package org.apache.maven.plugin.jcoverage.report; /* ==================================================================== * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== */ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.oro.text.perl.Perl5Util; /** * @author Emmanuel Venisse * @version $Id$ */ public class CoverageReport { /** coverage data */ private Coverage coverage; /** * Create a coverage report * @param coverage coverage data */ public CoverageReport(Coverage coverage) { this.coverage = coverage; } public void generate(String dir) throws IOException { File directory = new File(dir); directory.mkdirs(); generateSourceFiles(directory); generateFrameset(directory); generatePackageList(directory); generateClassList(directory); generateOverview(directory); } private void generateFrameset(File dir) throws IOException { File fsFile = new File(dir, "index.html"); PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fsFile))); pw.println("<html>"); pw.println("<head>"); pw.println("<title>unit tests coverage report</title>"); pw.println("</head>"); pw.println("<FRAMESET cols=\"20%,80%\">"); pw.println("<FRAMESET rows=\"30%,70%\">"); pw.println("<FRAME src=\"overview-frame.html\" name=\"packageListFrame\" title=\"All Packages\">"); pw.println("<FRAME src=\"allclasses-frame.html\" name=\"packageFrame\" title=\"All classes and interfaces (except non-static nested types)\">"); pw.println("</FRAMESET>"); pw.println("<FRAME src=\"overview-summary.html\" name=\"classFrame\" title=\"Package, class and interface descriptions\" scrolling=\"yes\">"); pw.println("<NOFRAMES>"); 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."); pw.println("<BR>"); pw.println("Link to<A HREF=\"overview-summary.html\">Non-frame version.</A>"); pw.println("</NOFRAMES>"); pw.println("</FRAMESET>"); pw.println("</html>"); pw.close(); } private void generatePackageList(File dir) throws IOException { File fsFile = new File(dir, "overview-frame.html"); PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fsFile))); pw.println("<html>"); pw.println("<head>"); pw.println("<title>unit tests coverage report</title>"); pw.println("<link rel =\"stylesheet\" type=\"text/css\" href=\"style.css\" title=\"Style\">"); pw.println("</head>"); pw.println("<body>"); pw.println("<span class=\"title\">Coverage report</span>"); pw.println("<table>"); pw.println("<tr>"); pw.println("<td nowrap=\"nowrap\">"); pw.println("<a href=\"overview-summary.html\" target=\"classFrame\">Overview</a><br>"); pw.println("<a href=\"allclasses-frame.html\" target=\"packageFrame\">All classes</a>"); pw.println("</td>"); pw.println("</tr>"); pw.println("</table>"); pw.println("<p>"); pw.println("<table>"); pw.println("<tr>"); pw.println("<td nowrap=\"nowrap\"><span class=\"title2\">All packages</span></td>"); pw.println("</tr>"); pw.println("<tr>"); pw.println("<td nowrap=\"nowrap\">"); for (Iterator iter = coverage.getPackagesSortedByName().iterator(); iter.hasNext(); ) { Package pkg = (Package) iter.next(); String url = pkg.getDirectory() + "/package-frame.html"; pw.println("<a href=\"" + url + "\" target=\"packageFrame\">" + pkg.getName() + "</a><br>"); } pw.println("</td>"); pw.println("</tr>"); pw.println("</table>"); pw.println("</body>"); pw.println("</html>"); pw.close(); for (Iterator iter = coverage.getPackagesSortedByName().iterator(); iter.hasNext(); ) { Package pkg = (Package) iter.next(); generateClassList(dir, pkg); generateOverview(dir, pkg); } } private void generateClassList(File dir) throws IOException { generateClassList(dir, null); } private void generateClassList(File dir, Package pkg) throws IOException { String filename; String rootRef; List classes; String urlDirectory = ""; if (pkg == null) { rootRef = ""; filename = "allclasses-frame.html"; classes = coverage.getClassesSortedByName(); } else { rootRef = getRelativePath(pkg.getName() + "/"); filename = pkg.getDirectory() + "/package-frame.html"; classes = pkg.getClassesSortedByName(); urlDirectory = "."; } File fsFile = new File(dir, filename); fsFile.getParentFile().mkdirs(); PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fsFile))); pw.println("<html>"); pw.println("<head>"); pw.println("<title>unit tests coverage report</title>"); pw.println("<link rel =\"stylesheet\" type=\"text/css\" href=\"" + rootRef + "style.css\" title=\"Style\">"); pw.println("</head>"); pw.println("<body>"); if (pkg != null) { pw.println("<a href=\"package-summary.html\" target=\"classFrame\">" + pkg.getName() + "</a><br>"); pw.println("<p>"); } pw.println("<span class=\"title\">All classes</span>"); pw.println("<table>"); pw.println("<tr>"); pw.println("<td nowrap=\"nowrap\">"); for (Iterator iter = classes.iterator(); iter.hasNext(); ) { Clazz theClass = (Clazz) iter.next(); if (pkg == null) { urlDirectory = theClass.getFile().substring(0, theClass.getFile().lastIndexOf("/")); } String classFilename = theClass.getName() + ".html"; if (theClass.getFile().endsWith("/" + theClass.getName() + ".java")) { pw.println("<a href=\"" + urlDirectory + "/" + classFilename + "\" target=\"classFrame\">" + theClass.getName() + "</a><span class=\"text_italic\"> (" + getPercentValue(theClass.getLineRate()) + ")</span><br>"); } } pw.println("</td>"); pw.println("</tr>"); pw.println("</table>"); pw.println("</body>"); pw.println("</html>"); pw.close(); } private void generateOverview(File dir) throws IOException { generateOverview(dir, null); } private void generateOverview(File dir, Package thePackage) throws IOException { String filename = "overview-summary.html"; String rootRef; if (thePackage != null) { filename = thePackage.getDirectory() + "/package-summary.html"; rootRef = getRelativePath(thePackage.getName() + "/"); } else { rootRef = ""; } File fsFile = new File(dir, filename); PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fsFile))); pw.println("<html>"); pw.println("<head>"); pw.println("<title>unit tests coverage report</title>"); pw.println("<link rel =\"stylesheet\" type=\"text/css\" href=\"" + rootRef + "style.css\" title=\"Style\">"); pw.println("</head>"); pw.println("<body>"); pw.println("<span class=\"title\">Coverage report</span>"); pw.println("<p>"); pw.println("<table class=\"report\" cellpadding=\"0\" cellspacing=\"0\">"); pw.println("<tr class=\"report\">"); pw.println("<th class=\"report\"> </th>"); pw.println("<th class=\"report\">Files</th>"); pw.println("<th class=\"report\">%line</th>"); pw.println("<th class=\"report\">%branch</th>"); pw.println("</tr>"); pw.println("<tr class=\"report\">"); if (thePackage != null) { pw.println("<td class=\"reportText\">" + thePackage.getName() + "</td>"); pw.println("<td class=\"reportValue\">" + thePackage.getClasses().size() + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(thePackage.getCoveredPercentLine())) + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(thePackage.getCoveredPercentBranch())) + "</td>"); } else { pw.println("<td class=\"reportText\">Project</td>"); pw.println("<td class=\"reportValue\">" + coverage.getClasses().size() + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(coverage.getCoveredPercentLine())) + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(coverage.getCoveredPercentBranch())) + "</td>"); } pw.println("</tr>"); List pkgList = null; if (thePackage != null) { pkgList = coverage.getSubPackage(thePackage); if (pkgList.size() > 0) { pw.println("<tr>"); pw.println("<td class=\"spacer\" colspan=\"4\"><span class=\"title2\">Packages</span></td>"); pw.println("</tr>"); for (Iterator iter = pkgList.iterator(); iter.hasNext(); ) { Package pkg = (Package) iter.next(); pw.println("<tr class=\"report\">"); String subPkgDir = pkg.getDirectory().substring(thePackage.getDirectory().length() + 1); pw.println("<td class=\"reportText\"><a href=\"" + subPkgDir + "/package-summary.html\">" + pkg.getName() + "</a></td>"); pw.println("<td class=\"reportValue\">" + pkg.getClasses().size() + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(pkg.getCoveredPercentLine())) + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(pkg.getCoveredPercentBranch())) + "</td>"); pw.println("</tr>"); } } if (thePackage.getClasses().size() > 0) { pw.println("<tr>"); pw.println("<td class=\"spacer\" colspan=\"4\"><span class=\"title2\">Classes</span></td>"); pw.println("</tr>"); for (Iterator it = thePackage.getClassesSortedByName().iterator(); it.hasNext(); ) { Clazz cl = (Clazz) it.next(); if (cl.getFile().indexOf("[Unknown]")<0) { String classFilename = cl.getFile().substring(cl.getFile().lastIndexOf("/")+1, cl.getFile().lastIndexOf(".")) + ".html"; pw.println("<tr class=\"report\">"); pw.println("<td class=\"reportText\" colspan=\"2\"><a href=\"" + classFilename + "\">" + cl.getName() + "</a></td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(cl.getLineRate())) + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(cl.getBranchRate())) + "</td>"); pw.println("</tr>"); } } } } else { pkgList = coverage.getPackages(); if (pkgList.size() > 0) { pw.println("<tr>"); pw.println("<td class=\"spacer\" colspan=\"4\"><span class=\"title2\">Packages</span></td>"); pw.println("</tr>"); for (Iterator iter = coverage.getPackagesSortedByName().iterator(); iter.hasNext(); ) { Package pkg = (Package) iter.next(); pw.println("<tr class=\"report\">"); pw.println("<td class=\"reportText\"><a href=\"" + pkg.getDirectory() + "/package-summary.html\">" + pkg.getName() + "</a></td>"); pw.println("<td class=\"reportValue\">" + pkg.getClasses().size() + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(pkg.getCoveredPercentLine())) + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(pkg.getCoveredPercentBranch())) + "</td>"); pw.println("</tr>"); } } if (coverage.getClasses().size() > 0) { List classesList = new ArrayList(); for (Iterator iter = coverage.getClassesSortedByName().iterator(); iter.hasNext(); ) { Clazz cl = (Clazz) iter.next(); if (cl.getPackageName() == null || cl.getPackageName().equals("")) { classesList.add(cl); } } if (classesList.size() > 0) { pw.println("<tr>"); pw.println("<td class=\"spacer\" colspan=\"4\"><span class=\"title2\">Classes</span></td>"); pw.println("</tr>"); for (Iterator iter = classesList.iterator(); iter.hasNext(); ) { Clazz cl = (Clazz) iter.next(); if (cl.getFile().indexOf("[Unknown]")<0) { String classFilename = cl.getFile().substring(cl.getFile().lastIndexOf("/")+1, cl.getFile().lastIndexOf(".")) + ".html"; pw.println("<tr class=\"report\">"); pw.println("<td class=\"reportText\" colspan=\"2\"><a href=\"" + classFilename + "\">" + cl.getName() + "</a></td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(cl.getLineRate())) + "</td>"); pw.println("<td class=\"reportValue\">" + generatePercentResult(getPercentValue(cl.getBranchRate())) + "</td>"); pw.println("</tr>"); } } } } } pw.println("</table>"); pw.println(generateFooter()); pw.println("</body>"); pw.println("</html>"); pw.close(); } private void generateSourceFiles(File dir) throws IOException { for (Iterator iter = coverage.getClasses().iterator(); iter.hasNext(); ) { Clazz theClass = (Clazz) iter.next(); File file = new File(coverage.getSrcDirectory(), theClass.getFile()); if (file.exists()) { generateSourceFile(dir, theClass); } } } private void generateSourceFile(File directory, Clazz theClass) throws IOException { String srcOutputFilename = theClass.getFile().substring(0, theClass.getFile().lastIndexOf(".")) + ".html"; File srcOutputFile = new File(directory, srcOutputFilename); File dirOutputFile = srcOutputFile.getParentFile(); if (dirOutputFile != null) { dirOutputFile.mkdirs(); } PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(srcOutputFile))); pw.println("<html>"); pw.println("<head>"); pw.println("<title>unit tests coverage</title>"); String rootRef = getRelativePath(theClass.getPackageName()); pw.println("<link rel =\"stylesheet\" type=\"text/css\" href=\"" + rootRef + "style.css\" title=\"Style\">"); pw.println("</head>"); pw.println("<body>"); pw.println("<span class=\"title\">Coverage report</span>"); pw.println("<p>"); pw.println(" <table cellspacing=\"0\" cellpadding=\"0\" class=\"report\">"); pw.println(" <tr class=\"report\">"); pw.println(" <th class=\"report\"> </th>"); pw.println(" <th class=\"report\">%line</th>"); pw.println(" <th class=\"report\">%branch</th>"); pw.println(" </tr>"); pw.println(" <tr class=\"report\">"); pw.println(" <td class=\"reportText\"><span class=\"text\">" + theClass.getPackageName() + "." + theClass.getName() + "</span></td>"); pw.println(" <td class=\"reportValue\">" + generatePercentResult(getPercentValue(theClass.getLineRate())) + "</td>"); pw.println(" <td class=\"reportValue\">" + generatePercentResult(getPercentValue(theClass.getBranchRate())) + "</td>"); pw.println(" </tr>"); pw.println(" </table>"); pw.println(" <p>"); pw.println(" <table cellspacing=\"0\" cellpadding=\"0\" class=\"src\">"); BufferedReader br = new BufferedReader(new FileReader(new File(coverage.getSrcDirectory(), theClass.getFile()))); String lineStr; int numLigne = 1; while ((lineStr = br.readLine()) != null) { Line theLine = (Line) theClass.getLinesMap().get(new Integer(numLigne)); int nbHits = 0; if (theLine != null) { nbHits = theLine.getNbHits(); } pw.println(" <tr>"); if (theLine != null) { pw.println(" <td class=\"numLineCover\"> " + numLigne + "</td>"); if (nbHits > 0) { pw.println(" <td class=\"nbHitsCovered\"> " + theLine.getNbHits() + "</td>"); pw.println(" <td class=\"src\"><pre class=\"src\"> " + JavaToHtml.syntaxHighlight(lineStr) + "</pre></td>"); } else { pw.println(" <td class=\"nbHitsUncovered\"> " + theLine.getNbHits() + "</td>"); pw.println(" <td class=\"src\"><pre class=\"src\"><span class=\"srcUncovered\"> "+ JavaToHtml.syntaxHighlight(lineStr) + "</span></pre></td>"); } } else { pw.println(" <td class=\"numLine\"> " + numLigne + "</td>"); pw.println(" <td class=\"nbHits\"> </td>"); pw.println(" <td class=\"src\"><pre class=\"src\"> " + JavaToHtml.syntaxHighlight(lineStr) + "</pre></td>"); } pw.println(" </tr>"); numLigne++; } pw.println(" </table>"); pw.println(generateFooter()); pw.println("</body>"); pw.println("</html>"); pw.close(); } private String generateFooter() { StringBuffer sb = new StringBuffer(); sb.append("<p>"); sb.append("<table cellpadding=\"0\" cellspacing=\"0\" class=\"report\">"); sb.append(" <tr class=\"report\">"); sb.append(" <td class=\"reportText\"><span class=\"text\">"); 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/reference/plugins/jcoverage/\">Maven JCoverage Plugin</a>."); sb.append(" </span></td>"); sb.append(" </tr>"); sb.append("</table>"); return sb.toString(); } private String generatePercentResult(String percentValue) { if (percentValue.endsWith("%")) { percentValue = percentValue.substring(0, percentValue.length() - 1); } double rest = 0; try { rest = 100d - new Double(percentValue).doubleValue(); } catch(NumberFormatException e) { rest = 0; } StringBuffer sb = new StringBuffer(); sb.append("<table class=\"percentGraph\" cellpadding=\"0\" cellspacing=\"0\" align=\"right\">"); sb.append("<tr>"); sb.append("<td><span class=\"text\">" + percentValue + "% </span></td>"); sb.append("<td>"); sb.append("<table class=\"percentGraph\" cellpadding=\"0\" cellspacing=\"0\">"); sb.append("<tr>"); sb.append("<td class=\"percentCovered\" width=\"" + percentValue + "\"></td>"); sb.append("<td class=\"percentUnCovered\" width=\"" + String.valueOf(rest) + "\"></td>"); sb.append("</tr>"); sb.append("</table>"); sb.append("</td>"); sb.append("</tr>"); sb.append("</table>"); return sb.toString(); } private String getRelativePath(String path) { if (path != null && !path.equals("")) { return new Perl5Util().substitute("s/[^\\.]*(\\.|$)/..\\//g", path); } else { return ""; } } private String getPercentValue(String value) { if (value.endsWith("%")) { value = value.substring(0, value.length() - 1); } double percent = 0; try { percent = new Double(value).doubleValue(); } catch(NumberFormatException e) { percent = 0; } NumberFormat percentFormatter; percentFormatter = NumberFormat.getPercentInstance(); return percentFormatter.format(percent); } }