/* * Copyright (c) 2006-2011 RogĂ©rio Liesenfeld * This file is subject to the terms of the MIT license (see LICENSE.txt). */ package mockit.coverage.reporting.packages; import java.io.*; import java.util.*; import mockit.coverage.*; import mockit.coverage.data.*; import mockit.coverage.reporting.OutputFile; public final class IndexPage extends ListWithFilesAndPercentages { private final List<File> sourceDirs; private final Map<String, List<String>> packageToFiles; private final Map<String, int[]> packageToPackagePercentages; private final PackageCoverageReport packageReport; private String packageName; public IndexPage( File outputFile, List<File> sourceDirs, Map<String, List<String>> packageToFiles, Map<String, FileCoverageData> fileToFileData) throws IOException { super(new OutputFile(outputFile), " "); this.sourceDirs = sourceDirs; this.packageToFiles = packageToFiles; packageToPackagePercentages = new HashMap<String, int[]>(); packageReport = new PackageCoverageReport(output, fileToFileData, sourceDirs != null); } public void generate() { try { writeHeader(); List<String> packages = new ArrayList<String>(packageToFiles.keySet()); writeMetricsForEachFile(null, packages); writeLineWithCoverageTotals(); writeFooter(); } finally { output.close(); } } private void writeHeader() { ((OutputFile) output).writeCommonHeader(); output.println(" <h1>JMockit Coverage Report</h1>"); output.println(" <table>"); writeTableCaption(); writeTableFirstRowWithColumnTitles(); } private void writeTableCaption() { if (sourceDirs == null) { output.println(" <caption>All Packages and Files</caption>"); } else { output.write(" <caption>All Packages and Files<div style='font-size: smaller'>"); String commaSepDirs = sourceDirs.toString(); output.write(commaSepDirs.substring(1, commaSepDirs.length() - 1)); output.println("</div></caption>"); } } private void writeTableFirstRowWithColumnTitles() { int totalFileCount = computeTotalNumberOfSourceFilesAndMaximumFileNameLength(); output.println(" <tr>"); output.write(" <th style='cursor: pointer' onclick='showHideAllFiles(this)'>Packages: "); output.print(packageToFiles.keySet().size()); output.println("</th>"); output.write( " <th onclick='location.reload()' style='cursor: pointer' " + "title='Click on the title for each metric to sort by size (total number of line " + "segments, paths, or fields).'>Files: "); output.print(totalFileCount); output.println("</th>"); if (Metrics.LINE_COVERAGE) { output.println( " <th onclick='sortTables(1)' style='cursor: pointer' title='" + "Measures how much of the executable production code was exercised by tests.\r\n" + "An executable line of code contains one or more executable segments.\r\n" + "The percentages are calculated as 100*NE/NS, where NS is the number of segments " + "and NE the number of executed segments.'>Line</th>"); } if (Metrics.PATH_COVERAGE) { output.println( " <th onclick='sortTables(2)' style='cursor: pointer' title='" + "Measures how many of the possible execution paths through method/constructor bodies " + "were actually executed by tests.\r\n" + "The percentages are calculated as 100*NPE/NP, where NP is the number of possible " + "paths and NPE the number of fully executed paths.'>Path</th>"); } if (Metrics.DATA_COVERAGE) { output.println( " <th onclick='sortTables(3)' style='cursor: pointer' title='" + "Measures how many of the instance and static non-final fields were fully exercised " + "by the test run.\r\n" + "To be fully exercised, a field must have the last value assigned to it read by at " + "least one test.\r\n" + "The percentages are calculated as 100*NFE/NF, where NF is the number of non-final " + "fields and NFE the number of fully exercised fields.'>Data</th>"); } output.println(" </tr>"); } private int computeTotalNumberOfSourceFilesAndMaximumFileNameLength() { int totalFileCount = 0; int maxFileNameLength = 0; for (List<String> files : packageToFiles.values()) { totalFileCount += files.size(); for (String fileName : files) { int n = fileName.length(); if (n > maxFileNameLength) { maxFileNameLength = n; } } } packageReport.setMaxFileNameLength(maxFileNameLength); return totalFileCount; } private void writeLineWithCoverageTotals() { output.println(" <tr class='total'>"); output.println(" <td>Total</td><td> </td>"); writeLineWithCoverageTotals(0); writeLineWithCoverageTotals(1); writeLineWithCoverageTotals(2); output.println(" </tr>"); } private void writeLineWithCoverageTotals(int metric) { if (Metrics.withMetric(metric)) { int covered = coveredItems[metric]; int total = totalItems[metric]; int percentage = CoveragePercentage.calculate(covered, total); printCoveragePercentage(metric, covered, total, percentage); } } private void writeFooter() { output.println(" </table>"); output.write(" <p>Generated on "); output.print(new Date()); output.println("</p>"); ((OutputFile) output).writeCommonFooter(); } @Override protected void writeMetricsForFile(String unused, String packageName) { this.packageName = packageName; writeTableCellWithPackageName(); writeInternalTableForSourceFiles(); writeCoveragePercentageForFile(0); writeCoveragePercentageForFile(1); writeCoveragePercentageForFile(2); } private void writeTableCellWithPackageName() { printIndent(); output.write( packageToFiles.get(packageName).size() > 1 ? " <td class='package click' onclick='showHideFiles(this)'>" : " <td class='package'>"); output.write(packageName.replace('/', '.')); output.println("</td>"); } private void writeInternalTableForSourceFiles() { printIndent(); output.println(" <td>"); printIndent(); output.println(" <table width='100%'>"); packageReport.writeMetricsForEachFile(packageName, packageToFiles.get(packageName)); recordCoverageInformationForPackage(0); recordCoverageInformationForPackage(1); recordCoverageInformationForPackage(2); printIndent(); output.println(" </table>"); printIndent(); output.println(" </td>"); } private void recordCoverageInformationForPackage(int metric) { if (Metrics.withMetric(metric)) { int coveredInPackage = packageReport.coveredItems[metric]; int totalInPackage = packageReport.totalItems[metric]; int packagePercentage = CoveragePercentage.calculate(coveredInPackage, totalInPackage); setPackageCoveragePercentage(metric, packagePercentage); totalItems[metric] += totalInPackage; coveredItems[metric] += coveredInPackage; } } private void setPackageCoveragePercentage(int metric, int percentage) { int[] percentages = packageToPackagePercentages.get(packageName); if (percentages == null) { percentages = new int[3]; packageToPackagePercentages.put(packageName, percentages); } percentages[metric] = percentage; } private void writeCoveragePercentageForFile(int metric) { if (Metrics.withMetric(metric)) { int coveredInPackage = packageReport.coveredItems[metric]; int totalInPackage = packageReport.totalItems[metric]; int filePercentage = packageToPackagePercentages.get(packageName)[metric]; printCoveragePercentage(metric, coveredInPackage, totalInPackage, filePercentage); } } }