|
" + generateBranchInfo(lineData, javaToHtml.process(lineStr)) + "</pre>"); } else { ret.append(" <td class=\"nbHitsUncovered\">" + generateBranchInfo(lineData, " " + ((lineData != null) ? lineData.getHits() : 0)) + "</td>"); ret .append(" <td class=\"src\">\n"); } finally { try { br.close(); source.close(); } catch (IOException e) { } } ret.append("</table>\n"); return ret.toString(); } private static String generateFooter() { return "<div class=\"footer\">Report generated by " + "<a href=\"http://cobertura.sourceforge.net/\" target=\"_top\">Cobertura " + Header.version() + " on " + DateFormat.getInstance().format(new Date()) + ".</div>"; } private static String generateTableHeader(String title, boolean showColumnForNumberOfClasses) { StringBuffer ret = new StringBuffer(); ret.append("<thead>"); ret.append("<tr>"); ret.append(" <td class=\"heading\">" + title + ""); if (showColumnForNumberOfClasses) { ret.append(" <td class=\"heading\"># Classes"); } ret.append(" <td class=\"heading\">" + generateHelpURL("Line Coverage", "The percent of lines executed by this test run.") + "</td>"); ret.append(" <td class=\"heading\">" + generateHelpURL("Branch Coverage", "The percent of branches executed by this test run.") + "</td>"); ret .append(" <td class=\"heading\">" + generateHelpURL( "Complexity", "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.)") + "</td>"); ret.append("</tr>"); ret.append("</thead>"); return ret.toString(); } private static String generateHelpURL(String text, String description) { StringBuffer ret = new StringBuffer(); boolean popupTooltips = false; if (popupTooltips) { ret .append("<a class=\"hastooltip\" href=\"help.html\" onclick=\"popupwindow('help.html'); return false;\">"); ret.append(text); ret.append("<span>" + description + ""); ret.append("</a>"); } else { ret .append("<a class=\"dfn\" href=\"help.html\" onclick=\"popupwindow('help.html'); return false;\">"); ret.append(text); ret.append("</a>"); } return ret.toString(); } private String generateTableRowForTotal() { StringBuffer ret = new StringBuffer(); double ccn = complexity.getCCNForProject(projectData); ret.append(" <tr>"); ret.append("<td>All Packages"); ret.append("<td class=\"value\">" + projectData.getNumberOfClasses() + "</td>"); ret.append(generateTableColumnsFromData(projectData, ccn)); ret.append("</tr>"); return ret.toString(); } private String generateTableRowForPackage(PackageData packageData) { StringBuffer ret = new StringBuffer(); String url1 = "frame-summary-" + packageData.getName() + ".html"; String url2 = "frame-sourcefiles-" + packageData.getName() + ".html"; double ccn = complexity.getCCNForPackage(packageData); ret.append(" <tr>"); ret.append("<td>"); ret.append("<td class=\"value\">" + packageData.getNumberOfChildren() + "</td>"); ret.append(generateTableColumnsFromData(packageData, ccn)); ret.append("</tr>"); return ret.toString(); } private String generateTableRowsForSourceFile(SourceFileData sourceFileData) { StringBuffer ret = new StringBuffer(); String sourceFileName = sourceFileData.getNormalizedName(); // TODO: ccn should be calculated per-class, not per-file double ccn = complexity.getCCNForSourceFile(sourceFileData); Iterator iter = sourceFileData.getClasses().iterator(); while (iter.hasNext()) { ClassData classData = (ClassData)iter.next(); ret .append(generateTableRowForClass(classData, sourceFileName, ccn)); } return ret.toString(); } private String generateTableRowForClass(ClassData classData, String sourceFileName, double ccn) { StringBuffer ret = new StringBuffer(); ret.append(" <tr>"); // TODO: URL should jump straight to the class (only for inner classes?) ret.append("<td>"); ret.append(generateTableColumnsFromData(classData, ccn)); ret.append("</tr>\n"); return ret.toString(); } /** * Return a string containing three HTML table cells. The first * cell contains a graph showing the line coverage, the second * cell contains a graph showing the branch coverage, and the * third cell contains the code complexity. * * @param ccn The code complexity to display. This should be greater * than 1. * @return A string containing the HTML for three table cells. */ private static String generateTableColumnsFromData(CoverageData coverageData, double ccn) { int numLinesCovered = coverageData.getNumberOfCoveredLines(); int numLinesValid = coverageData.getNumberOfValidLines(); int numBranchesCovered = coverageData.getNumberOfCoveredBranches(); int numBranchesValid = coverageData.getNumberOfValidBranches(); // The "hidden" CSS class is used below to write the ccn without // any formatting so that the table column can be sorted correctly return "<td>" + generatePercentResult(numLinesCovered, numLinesValid) +"</td>"; } /** * This is crazy complicated, and took me a while to figure out, * but it works. It creates a dandy little percentage meter, from * 0 to 100. * @param dividend The number of covered lines or branches. * @param divisor The number of valid lines or branches. * @return A percentage meter. */ private static String generatePercentResult(int dividend, int divisor) { StringBuffer sb = new StringBuffer(); sb.append("<table cellpadding=\"0px\" cellspacing=\"0px\" class=\"percentgraph\">" + generateBranchInfo(lineData, javaToHtml.process(lineStr)) + "</span>
"); } } else { ret.append(" <td class=\"numLine\"> " + lineNumber + "</td>"); ret.append(" <td class=\"nbHits\"> \n"); ret.append(" <td class=\"src\">" + javaToHtml.process(lineStr) + "</pre>"); } ret.append("</tr>\n"); lineNumber++; } } catch (IOException e) { ret.append("<tr>
Cobertura example source code file (HTMLReport.java)
The Cobertura HTMLReport.java source code/* * Cobertura - http://cobertura.sourceforge.net/ * * Copyright (C) 2005 Mark Doliner * Copyright (C) 2005 Grzegorz Lukasik * Copyright (C) 2005 Jeremy Thomerson * Copyright (C) 2006 Naoki Iwami * Copyright (C) 2009 Charlie Squires * Copyright (C) 2009 John Lewis * * Cobertura is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * Cobertura is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Cobertura; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ package net.sourceforge.cobertura.reporting.html; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; import net.sourceforge.cobertura.coveragedata.ClassData; import net.sourceforge.cobertura.coveragedata.CoverageData; import net.sourceforge.cobertura.coveragedata.LineData; import net.sourceforge.cobertura.coveragedata.PackageData; import net.sourceforge.cobertura.coveragedata.ProjectData; import net.sourceforge.cobertura.coveragedata.SourceFileData; import net.sourceforge.cobertura.reporting.ComplexityCalculator; import net.sourceforge.cobertura.reporting.html.files.CopyFiles; import net.sourceforge.cobertura.util.FileFinder; import net.sourceforge.cobertura.util.Header; import net.sourceforge.cobertura.util.IOUtil; import net.sourceforge.cobertura.util.Source; import net.sourceforge.cobertura.util.StringUtil; import org.apache.log4j.Logger; public class HTMLReport { private static final Logger LOGGER = Logger.getLogger(HTMLReport.class); private File destinationDir; private FileFinder finder; private ComplexityCalculator complexity; private ProjectData projectData; private String encoding; /** * Create a coverage report * @param encoding */ public HTMLReport(ProjectData projectData, File outputDir, FileFinder finder, ComplexityCalculator complexity, String encoding) throws Exception { this.destinationDir = outputDir; this.finder = finder; this.complexity = complexity; this.projectData = projectData; this.encoding = encoding; CopyFiles.copy(outputDir); generatePackageList(); generateSourceFileLists(); generateOverviews(); generateSourceFiles(); } private String generatePackageName(PackageData packageData) { if (packageData.getName().equals("")) return "(default)"; return packageData.getName(); } private void generatePackageList() throws IOException { File file = new File(destinationDir, "frame-packages.html"); PrintWriter out = null; try { out = IOUtil.getPrintWriter(file); out .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""); out .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); out .println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"); out.println("<head>"); out .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"); out.println("<title>Coverage Report"); out .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" href=\"css/main.css\" />"); out.println("</head>"); out.println("<body>"); out.println("<h5>Packages"); out.println("<table width=\"100%\">"); out.println("<tr>"); out .println("<td nowrap=\"nowrap\">All | Error reading " + source.getOriginDesc() + ": " + e.getLocalizedMessage() + "</td> | |
" + generatePercentResult(numBranchesCovered, numBranchesValid) + "</td> | " + ccn + ";</span>" + getDoubleValue(ccn) + " | |
"); if (divisor > 0) sb.append(getPercentValue((double)dividend / divisor)); else sb.append(generateHelpURL( "N/A", "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.\"")); sb.append("</td> | ");
if (divisor > 0)
{
sb.append("<div class=\"greenbar\" style=\"width:"
+ (dividend * 100 / divisor) + "px\">");
sb.append("<span class=\"text\">");
sb.append(dividend);
sb.append("/");
sb.append(divisor);
}
else
{
sb.append("<div class=\"na\" style=\"width:100px\">");
sb.append("<span class=\"text\">");
sb.append(generateHelpURL(
"N/A",
"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.\""));
}
sb.append("</span> |
... this post is sponsored by my books ... | |
![]() #1 New Release! |
![]() FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.