blob: aeeec72cea58bbfe6b8e3a2e2de5d481916524bf [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package org.apache.flex.tools.codecoverage.reporter.reports;
import java.io.BufferedWriter;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.flex.tools.codecoverage.reporter.CoverageSummary;
import org.apache.flex.tools.codecoverage.reporter.PackageSummaryInfo;
import org.apache.flex.tools.codecoverage.reporter.SummaryInfo;
import org.apache.flex.tools.codecoverage.reporter.SummaryType;
/**
* XML formatted code coverage report.
*
*/
public class XMLReportWriter implements IReportWriter
{
private static final String REPORT_VERSION = "1.0";
private Collection<String> includeFilters;
private Collection<String> excludeFilters;
private boolean showPackages;
private boolean showFiles;
private boolean showMethods;
private boolean showUnexecutedDetails;
/**
* Constructor.
*
* @param reportOptions Options to control the contents of the report.
*/
public XMLReportWriter(final ReportOptions reportOptions)
{
this.includeFilters = reportOptions.getIncludeFilters();
this.excludeFilters = reportOptions.getExcludeFilters();
this.showPackages = reportOptions.isShowPackages();
this.showFiles = reportOptions.isShowFiles();
this.showMethods = reportOptions.isShowMethods();
this.showUnexecutedDetails = reportOptions.isShowUnexecutedDetails();
}
@Override
public void writeTo(final BufferedWriter writer, final CoverageSummary coverageSummary)
{
final XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
assert xmlOutputFactory != null : "Expect XMLOutputFactory implementation.";
try
{
final XMLStreamWriter xmlWriter = xmlOutputFactory.
createXMLStreamWriter(writer);
xmlWriter.writeStartDocument("utf-8", "1.0");
// write top-level report
outputTopLevelStart(xmlWriter, coverageSummary.getOverallSummaryInfo());
if (showPackages)
{
// start package element
xmlWriter.writeStartElement("packages");
for (Map.Entry<String, PackageSummaryInfo> packageEntry :
coverageSummary.getPackageSummaryEntrySet())
{
PackageSummaryInfo packageSummary = packageEntry.getValue();
outputPackageCoverageStart(xmlWriter, packageSummary.getSummaryInfo());
if (showFiles)
{
outputFiles(xmlWriter, packageSummary, coverageSummary);
}
xmlWriter.writeEndElement(); // package
}
xmlWriter.writeEndElement(); // packages
}
xmlWriter.writeEndElement(); // code-coverage (top-level)
xmlWriter.writeEndDocument();
xmlWriter.close();
}
catch (XMLStreamException e)
{
e.printStackTrace();
}
}
/**
* Output the files xml and its children.
*
* @param xmlWriter
* @param packageSummary
* @param coverageSummary
* @throws XMLStreamException
*/
private void outputFiles(final XMLStreamWriter xmlWriter,
final PackageSummaryInfo packageSummary,
final CoverageSummary coverageSummary) throws XMLStreamException
{
// start file element
xmlWriter.writeStartElement("files");
for (final String packageFileKey : packageSummary.getFilesInPackage())
{
final SummaryInfo fileSummary = coverageSummary.getFileSummaryInfo(packageFileKey);
outputFileCoverageStart(xmlWriter, fileSummary);
final Set<String> methodNames = coverageSummary.getMethodsInFile(packageFileKey);
if (showMethods && !methodNames.isEmpty())
{
// start method element
xmlWriter.writeStartElement("methods");
for (final String methodName : methodNames)
{
SummaryInfo methodSummary = coverageSummary.
getMethodSummaryInfo(methodName);
outputMethodNameCoverage(xmlWriter, methodSummary);
}
xmlWriter.writeEndElement(); // methods
}
xmlWriter.writeEndElement(); // file
}
xmlWriter.writeEndElement(); // files
}
/**
* Output the coverage information for a method.
*
* @param xmlWriter
* @param summaryInfo
* @throws XMLStreamException
*/
private void outputMethodNameCoverage(final XMLStreamWriter xmlWriter,
final SummaryInfo summaryInfo) throws XMLStreamException
{
xmlWriter.writeStartElement("method");
xmlWriter.writeAttribute("name", summaryInfo.getName());
outputLineCoverage(xmlWriter, summaryInfo, false);
outputMethodCoverage(xmlWriter, summaryInfo, false);
xmlWriter.writeEndElement();
}
/**
* Output the start element for file coverage information.
*
* @param xmlWriter
* @param summaryInfo
* @throws XMLStreamException
*/
private void outputFileCoverageStart(final XMLStreamWriter xmlWriter,
final SummaryInfo summaryInfo) throws XMLStreamException
{
xmlWriter.writeStartElement("file");
xmlWriter.writeAttribute("name", summaryInfo.getName());
outputLineCoverage(xmlWriter, summaryInfo, showUnexecutedDetails);
outputMethodCoverage(xmlWriter, summaryInfo, showUnexecutedDetails);
}
/**
* Output code coverage for a package.
* @param xmlWriter
* @param summaryInfo
* @throws XMLStreamException
*/
private void outputPackageCoverageStart(final XMLStreamWriter xmlWriter,
final SummaryInfo summaryInfo) throws XMLStreamException
{
xmlWriter.writeStartElement("package");
xmlWriter.writeAttribute("name", summaryInfo.getName());
outputLineCoverage(xmlWriter, summaryInfo, false);
outputMethodCoverage(xmlWriter, summaryInfo, false);
}
/**
* Output top level summary information
*
* @param summaryInfo overall coverage info.
* @throws XMLStreamException
*/
private void outputTopLevelStart(final XMLStreamWriter xmlWriter,
final SummaryInfo summaryInfo) throws XMLStreamException
{
xmlWriter.writeStartElement("code-coverage");
xmlWriter.writeAttribute("version", REPORT_VERSION);
outputLineCoverage(xmlWriter, summaryInfo, false);
outputMethodCoverage(xmlWriter, summaryInfo, false);
outputFilter(xmlWriter, "include-filter");
outputFilter(xmlWriter, "exclude-filter");
}
/**
* Output filters as part of the report.
*
* @param xmlWriter
* @param filterName The name of the filter to output.
* @throws XMLStreamException
*/
private void outputFilter(final XMLStreamWriter xmlWriter,
final String filterName) throws XMLStreamException
{
Collection<String> filters = null;
String startElementName = null;
if ("include-filter".equals(filterName))
{
startElementName = "include-filters";
filters = includeFilters;
}
else if ("exclude-filter".equals(filterName))
{
startElementName = "exclude-filters";
filters = excludeFilters;
}
else
{
throw new IllegalArgumentException("unexpected filter name:" + filterName);
}
if (filters.isEmpty())
return;
xmlWriter.writeStartElement(startElementName);
for (final String filter : filters)
{
xmlWriter.writeStartElement(filterName);
xmlWriter.writeCharacters(filter);
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
}
/**
* Common method to output line coverage information.
*
* @param xmlWriter
* @param overall
* @throws XMLStreamException
*/
private void outputLineCoverage(final XMLStreamWriter xmlWriter,
final SummaryInfo overall, boolean showDetails) throws XMLStreamException
{
outputSummaryInfo(xmlWriter, "line-coverage", overall, SummaryType.LINE, showDetails);
}
/**
* Common method to output method coverage information.
*
* @param xmlWriter
* @param overall
* @throws XMLStreamException
*/
private void outputMethodCoverage(final XMLStreamWriter xmlWriter,
final SummaryInfo overall, final boolean showDetails)
throws XMLStreamException
{
outputSummaryInfo(xmlWriter, "method-coverage", overall,
SummaryType.METHOD, showDetails);
}
/**
* Common method to output summary information.
*
* @param xmlWriter The writer.
* @param elementName The name of the element.
* @param summaryInfo The summary info to output.
* @param summaryType Choose either LINE or METHOD.
* @param showDetails Show the lines/methods that were not executed.
* @throws XMLStreamException
*/
private void outputSummaryInfo(final XMLStreamWriter xmlWriter,
final String elementName,
final SummaryInfo summaryInfo,
final SummaryType summaryType,
final boolean showDetails) throws XMLStreamException
{
xmlWriter.writeStartElement(elementName);
final int executed;
final int total;
final int percent;
Set<?> items = null;
if (summaryType == SummaryType.LINE)
{
executed = summaryInfo.getExecutedLineCount();
total = summaryInfo.getTotalLineCount();
percent = total == 0 ? 0 : executed * 100 / total;
if (showDetails)
items = summaryInfo.getUnexecutedLines();
}
else
{
executed = summaryInfo.getExecutedMethodCount();
total = summaryInfo.getTotalMethodCount();
percent = total == 0 ? 0 : executed * 100 / total;
if (showDetails)
items = summaryInfo.getUnexecutedMethods();
}
xmlWriter.writeAttribute("executed", Integer.toString(executed));
xmlWriter.writeAttribute("total", Integer.toString(total));
xmlWriter.writeAttribute("percent", Integer.toString(percent));
if (showDetails)
outputUnexecutedSet(xmlWriter, items);
xmlWriter.writeEndElement();
}
/**
* Output unexecuted lines or methods.
*
* @param xmlWriter
* @param items
* @throws XMLStreamException
*/
private void outputUnexecutedSet(final XMLStreamWriter xmlWriter,
final Set<?> items) throws XMLStreamException
{
if (items == null || items.isEmpty())
return;
xmlWriter.writeStartElement("unexecuted-set");
for (Object item : items)
{
xmlWriter.writeStartElement("unexecuted");
xmlWriter.writeCharacters(item.toString());
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
}
}