(original) (raw)
diff -r 699dff9a1eeb src/classes/com/sun/tdk/jcov/instrument/XmlContext.java --- a/src/classes/com/sun/tdk/jcov/instrument/XmlContext.java Wed Jan 24 18:28:09 2018 +0300 +++ b/src/classes/com/sun/tdk/jcov/instrument/XmlContext.java Thu Mar 01 08:40:44 2018 -0500 @@ -98,49 +98,49 @@ this.showAbstract = showAbstract; } - void incIndent() { + public void incIndent() { indentHistory.push(indent); indent += indentDelta; } - void decIndent() { + public void decIndent() { indent = indentHistory.pop(); } - void indent() { + public void indent() { print(indent); } - void indentPrintln(String str) { + public void indentPrintln(String str) { indent(); println(str); } - void attr(String name, String value) { + public void attr(String name, String value) { print(" " + name + "=\""); writeEscaped(value); print("\""); } - void attr(String name, Object value) { + public void attr(String name, Object value) { print(" " + name + "=\""); writeEscaped(value.toString()); print("\""); } - void attr(String name, int value) { + public void attr(String name, int value) { print(" " + name + "=\"" + value + "\""); } - void attr(String name, long value) { + public void attr(String name, long value) { print(" " + name + "=\"" + value + "\""); } - void attr(String name, boolean value) { + public void attr(String name, boolean value) { print(" " + name + "=\"" + value + "\""); } - void attrNormalized(String name, String value) { + public void attrNormalized(String name, String value) { print(" " + name + "=\""); writeEscaped(value); print("\""); @@ -161,7 +161,7 @@ this.skipNotCoveredClasses = skipNotCoveredClasses; } - private void writeEscaped(String str) { + public void writeEscaped(String str) { if (str == null){ return; } diff -r 699dff9a1eeb src/classes/com/sun/tdk/jcov/report/AbstractCoverage.java --- a/src/classes/com/sun/tdk/jcov/report/AbstractCoverage.java Wed Jan 24 18:28:09 2018 +0300 +++ b/src/classes/com/sun/tdk/jcov/report/AbstractCoverage.java Thu Mar 01 08:40:44 2018 -0500 @@ -175,6 +175,24 @@ } /** + * Simple formatter that outputs a floating point number. This is + * used for Cobertura XML reports. + */ + public static class FloatFormatter implements CoverageFormatter { + @Override + public String format(CoverageData data) { + if (data.total != 0) { + final double total = data.total; + final double covered = data.covered; + + return Double.toString(covered / total); + } else { + return "0.0"; + } + } + } + + /** * Default CoverageFormatter that formats coverage in form of "percent% * (covered/total)" or " -" if total is null */ diff -r 699dff9a1eeb src/classes/com/sun/tdk/jcov/report/CoberturaReportGeneratorSPI.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/classes/com/sun/tdk/jcov/report/CoberturaReportGeneratorSPI.java Thu Mar 01 08:40:44 2018 -0500 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018, Eric L. McCorkle. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tdk.jcov.report; + +import com.sun.tdk.jcov.report.cobertura.CoberturaReportGenerator; +import com.sun.tdk.jcov.tools.EnvHandler; +import com.sun.tdk.jcov.tools.EnvServiceProvider; +import com.sun.tdk.jcov.tools.JCovTool.EnvHandlingException; + +public class CoberturaReportGeneratorSPI + implements ReportGeneratorSPI, EnvServiceProvider { + + /** + * {@inheritDoc} + */ + @Override + public ReportGenerator getReportGenerator(final String formatName) { + System.err.println("Checking format " + formatName); + if (formatName.equalsIgnoreCase("cobertura")) { + final ReportGenerator out = new CoberturaReportGenerator(); + + return out; + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int handleEnv(final EnvHandler opts) throws EnvHandlingException { + return 0; + } + + @Override + public void extendEnvHandler(final EnvHandler handler) {} + + +} diff -r 699dff9a1eeb src/classes/com/sun/tdk/jcov/report/DefaultReportGeneratorSPI.java --- a/src/classes/com/sun/tdk/jcov/report/DefaultReportGeneratorSPI.java Wed Jan 24 18:28:09 2018 +0300 +++ b/src/classes/com/sun/tdk/jcov/report/DefaultReportGeneratorSPI.java Thu Mar 01 08:40:44 2018 -0500 @@ -27,6 +27,7 @@ import com.sun.tdk.jcov.ant.AntableSPI; import com.sun.tdk.jcov.report.text.TextReportGenerator; import com.sun.tdk.jcov.report.html.CoverageReport; +import com.sun.tdk.jcov.report.cobertura.CoberturaReportGenerator; import com.sun.tdk.jcov.tools.EnvHandler; import com.sun.tdk.jcov.tools.EnvServiceProvider; import com.sun.tdk.jcov.tools.JCovTool.EnvHandlingException; @@ -40,6 +41,7 @@ protected CoverageReport html = null; protected TextReportGenerator txt = null; + protected CoberturaReportGenerator cobertura = null; protected boolean showMethods = true; protected boolean showBlocks = true; protected boolean showBranches = true; @@ -70,6 +72,11 @@ html.setShowLines(showLines); html.setShowOverviewColorBars(showOverviewColorBars); return html; + } else if ("cobertura".equalsIgnoreCase(name)) { + if (cobertura == null) { + cobertura = new CoberturaReportGenerator(); + } + return cobertura; } return null; @@ -147,4 +154,4 @@ new OptionDescr("noline", "Additional filtering", "Hide line coverage from report"); protected final static OptionDescr DSC_OVERVIEW_COLORBARS = new OptionDescr("addoverviewbars", "Additional reporting", "Adds colorful bars to the overview frames."); -} \ No newline at end of file +} diff -r 699dff9a1eeb src/classes/com/sun/tdk/jcov/report/cobertura/CoberturaReportGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/classes/com/sun/tdk/jcov/report/cobertura/CoberturaReportGenerator.java Thu Mar 01 08:40:44 2018 -0500 @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2018, Eric L. McCorkle. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.tdk.jcov.report.cobertura; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.Runnable; + +import com.sun.tdk.jcov.instrument.XmlContext; +import com.sun.tdk.jcov.report.AbstractCoverage; +import com.sun.tdk.jcov.report.ClassCoverage; +import com.sun.tdk.jcov.report.DataType; +import com.sun.tdk.jcov.report.FieldCoverage; +import com.sun.tdk.jcov.report.ItemCoverage; +import com.sun.tdk.jcov.report.MethodCoverage; +import com.sun.tdk.jcov.report.PackageCoverage; +import com.sun.tdk.jcov.report.ProductCoverage; +import com.sun.tdk.jcov.report.ReportGenerator; + +public class CoberturaReportGenerator implements ReportGenerator { + private static final String XML_HEADER = + ""; + private static final String XML_DTD = + ""; + private static final String COVERAGE_NODE = "coverage"; + private static final String LINE_RATE_ATTR = "line-rate"; + private static final String BRANCH_RATE_ATTR = "branch-rate"; + private static final String BRANCHES_COVERED_ATTR = "branches-covered"; + private static final String BRANCHES_RATE_ATTR = "branches-rate"; + private static final String TIMESTAMP_ATTR = "timestamp"; + private static final String COMPLEXITY_ATTR = "complexity"; + private static final String VERSION_ATTR = "version"; + + private static final String SOURCES_NODE = "sources"; + private static final String SOURCE_NODE = "source"; + + private static final String PACKAGES_NODE = "packages"; + + private static final String PACKAGE_NODE = "packages"; + + private static final String CLASSES_NODE = "classes"; + + private static final String CLASS_NODE = "class"; + private static final String NAME_ATTR = "name"; + private static final String FILENAME_ATTR = "filename"; + + + private static final String METHODS_NODE = "methods"; + + private static final String METHOD_NODE = "method"; + private static final String SIGNATURE_ATTR = "signature"; + private static final String HITS_ATTR = "hits"; + + private static final String LINES_NODE = "lines"; + + private static final String LINE_NODE = "line"; + private static final String NUMBER_ATTR = "number"; + private static final String BRANCH_ATTR = "branch"; + private static final String CONDITION_COVERAGE_ATTR = "condition-coverage"; + + private static final String CONDITIONS_NODE = "conditions"; + + private static final String CONDITION_NODE = "condition"; + private static final String COVERAGE_ATTR = "coverage"; + + private static final AbstractCoverage.CoverageFormatter formatter = + new AbstractCoverage.FloatFormatter(); + + private XmlContext ctx; + + /** + * {@inheritDoc} + */ + @Override + public void init(final String outputPath) throws IOException { + this.ctx = new XmlContext(new FileOutputStream(outputPath)); + } + + private void startNode(final String name) { + startNode(name, + new Runnable() { + @Override public void run() {} + }); + } + + private void startNode(final String name, + final Runnable attrs) { + ctx.indent(); + ctx.print("<"); + ctx.print(name); + attrs.run(); + ctx.println(">"); + ctx.incIndent(); + } + + private void singletonNode(final String name, + final Runnable attrs) { + ctx.indent(); + ctx.print("<"); + ctx.print(name); + attrs.run(); + ctx.println("/>"); + } + + private void endNode(final String name) { + ctx.decIndent(); + ctx.indent(); + ctx.print(""); + } + + private void writeXMLHeader() { + ctx.println(XML_HEADER); + ctx.println(XML_DTD); + ctx.println(); + } + + private void writeSource(final String srcRootPath) { + ctx.indent(); + ctx.print("<"); + ctx.print(SOURCE_NODE); + ctx.print(">"); + ctx.writeEscaped(srcRootPath); + ctx.print(""); + } + + private void writeSources(final Options options) { + startNode(SOURCES_NODE); + + for(final String srcRootPath : options.getSrcRootPaths()) { + writeSource(srcRootPath); + } + + endNode(SOURCES_NODE); + } + + private void itemNodeAttrs(final ItemCoverage item) { + ctx.attr(NUMBER_ATTR, item.getSourceLine()); + ctx.attr(HITS_ATTR, item.getCount()); + ctx.attr(BRANCH_ATTR, !item.isBlock()); + + if (!item.isBlock()) { + ctx.attr(CONDITION_COVERAGE_ATTR, + item.getCoverageString(DataType.BRANCH)); + } + } + + private void writeItem(final ItemCoverage item) { + singletonNode(LINE_NODE, + new Runnable() { + @Override + public void run() { + itemNodeAttrs(item); + } + }); + } + + private void writeItems(final Iterable items) { + startNode(LINES_NODE); + + for(final ItemCoverage item : items) { + writeItem(item); + } + + endNode(LINES_NODE); + } + + private void methodNodeAttrs(final MethodCoverage method) { + ctx.attr(NAME_ATTR, method.getName()); + ctx.attr(SIGNATURE_ATTR, method.getSignature()); + ctx.attr(LINE_RATE_ATTR, method.getCoverageString(DataType.LINE, + formatter)); + ctx.attr(BRANCH_RATE_ATTR, method.getCoverageString(DataType.BRANCH, + formatter)); + } + + private void writeMethod(final MethodCoverage method) { + startNode(METHOD_NODE, + new Runnable() { + @Override + public void run() { + methodNodeAttrs(method); + } + }); + + writeItems(method); + + endNode(METHOD_NODE); + } + + private void writeMethods(final Iterable methods) { + startNode(METHODS_NODE); + + for(final MethodCoverage method : methods) { + writeMethod(method); + } + + endNode(METHODS_NODE); + } + + private void fieldNodeAttrs(final FieldCoverage field) { + ctx.attr(NUMBER_ATTR, field.getStartLine()); + ctx.attr(HITS_ATTR, field.getHitCount()); + ctx.attr(BRANCH_ATTR, false); + } + + private void writeField(final FieldCoverage field) { + startNode(LINE_NODE, + new Runnable() { + @Override + public void run() { + fieldNodeAttrs(field); + } + }); + + endNode(LINE_NODE); + } + + /* Cobertura doesn't have fields, so we output these as line coverage. */ + private void writeClassLines(final ClassCoverage cls) { + startNode(LINES_NODE); + + for(final MethodCoverage method : cls.getMethods()) { + for(final ItemCoverage item : method) { + writeItem(item); + } + } + + for(final FieldCoverage field : cls.getFields()) { + writeField(field); + } + + endNode(LINES_NODE); + } + + private String trimPath(final String path, + final Options options) { + for(final String srcRootPath : options.getSrcRootPaths()) { + if (path.startsWith(srcRootPath)) { + int idx; + + for(idx = srcRootPath.length(); + path.charAt(idx) == File.separatorChar; + idx++); + + return path.substring(idx); + } + } + + return path; + } + + private void classNodeAttrs(final ClassCoverage cls, + final Options options) { + ctx.attr(NAME_ATTR, cls.getName()); + ctx.attr(FILENAME_ATTR, trimPath(cls.getSource(), options)); + ctx.attr(LINE_RATE_ATTR, cls.getCoverageString(DataType.LINE, + formatter)); + ctx.attr(BRANCH_RATE_ATTR, cls.getCoverageString(DataType.BRANCH, + formatter)); + // See comments below + ctx.attr(COMPLEXITY_ATTR, "1.0"); + } + + private void writeClass(final ClassCoverage cls, + final Options options) { + startNode(CLASS_NODE, + new Runnable() { + @Override + public void run() { + classNodeAttrs(cls, options); + } + }); + + writeMethods(cls.getMethods()); + writeClassLines(cls); + + endNode(CLASS_NODE); + } + + private void packageNodeAttrs(final PackageCoverage pack) { + ctx.attr(NAME_ATTR, pack.getName()); + ctx.attr(LINE_RATE_ATTR, pack.getCoverageString(DataType.LINE, + formatter)); + ctx.attr(BRANCH_RATE_ATTR, pack.getCoverageString(DataType.BRANCH, + formatter)); + // It's not clear what this actually is supposed to mean, but + // other tools just set it to 1.0 + ctx.attr(COMPLEXITY_ATTR, "1.0"); + } + + private void writeClasses(final Iterable classes, + final Options options) { + startNode(CLASSES_NODE); + + for(final ClassCoverage cls : classes) { + writeClass(cls, options); + } + + endNode(CLASSES_NODE); + } + + private void writePackage(final PackageCoverage pack, + final Options options) { + startNode(PACKAGE_NODE, + new Runnable() { + @Override + public void run() { + packageNodeAttrs(pack); + } + }); + writeClasses(pack, options); + endNode(PACKAGE_NODE); + } + + private void writePackages(final Iterable packs, + final Options options) { + startNode(PACKAGES_NODE); + + for(final PackageCoverage pack : packs) { + writePackage(pack, options); + } + + endNode(PACKAGES_NODE); + } + + private void coverageNodeAttrs(final ProductCoverage coverage) { + ctx.attr(LINE_RATE_ATTR, coverage.getCoverageString(DataType.LINE, + formatter)); + ctx.attr(BRANCH_RATE_ATTR, coverage.getCoverageString(DataType.BRANCH, + formatter)); + ctx.attr(TIMESTAMP_ATTR, Long.toString(System.currentTimeMillis() / + 1000L)); + } + + /** + * {@inheritDoc} + */ + @Override + public void generateReport(final ProductCoverage coverage, + final Options options) + throws IOException { + writeXMLHeader(); + + startNode(COVERAGE_NODE, + new Runnable() { + @Override + public void run() { + coverageNodeAttrs(coverage); + } + }); + + writeSources(options); + writePackages(coverage, options); + + endNode(COVERAGE_NODE); + ctx.flush(); + } +}