Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding stream writer to ScoverageXmlWriter.scala to work with large … #272

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import java.io.File

import scoverage._

import scala.xml.{Node, PrettyPrinter}
import javax.xml.stream.XMLOutputFactory
import javax.xml.stream.XMLStreamWriter
import java.io.FileWriter
import com.sun.xml.internal.txw2.output.IndentingXMLStreamWriter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an internal class. Can it be returned by some public factory to avoid referencing it directly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


/** @author Stephen Samuel */
class ScoverageXmlWriter(sourceDirectories: Seq[File], outputDir: File, debug: Boolean) extends BaseReportWriter(sourceDirectories, outputDir) {
Expand All @@ -15,105 +18,126 @@ class ScoverageXmlWriter(sourceDirectories: Seq[File], outputDir: File, debug: B

def write(coverage: Coverage): Unit = {
val file = IOUtils.reportFile(outputDir, debug)
IOUtils.writeToFile(file, new PrettyPrinter(120, 4).format(xml(coverage)))

val factory = XMLOutputFactory.newInstance()
val w: XMLStreamWriter = factory.createXMLStreamWriter(new FileWriter(file))
val writer = new IndentingXMLStreamWriter(w)
xml(coverage, writer)
}

private def xml(coverage: Coverage): Node = {
<scoverage statement-count={coverage.statementCount.toString}
statements-invoked={coverage.invokedStatementCount.toString}
statement-rate={coverage.statementCoverageFormatted}
branch-rate={coverage.branchCoverageFormatted}
version="1.0"
timestamp={System.currentTimeMillis.toString}>
<packages>
{coverage.packages.map(pack)}
</packages>
</scoverage>
private def xml(coverage: Coverage, writer: XMLStreamWriter): Unit = {
writer.writeStartDocument()
writer.writeStartElement("scoverage")
writer.writeAttribute("statement-count", coverage.statementCount.toString)
writer.writeAttribute("statements-invoked", coverage.invokedStatementCount.toString)
writer.writeAttribute("statement-rate", coverage.statementCoverageFormatted)
writer.writeAttribute("branch-rate", coverage.branchCoverageFormatted)
writer.writeAttribute("version", "1.0")
writer.writeAttribute("timestamp", System.currentTimeMillis.toString)

writer.writeStartElement("packages")
coverage.packages.foreach{m: MeasuredPackage => pack(m,writer)}
writer.writeEndElement()
writer.writeEndElement()
writer.writeEndDocument()

writer.flush()
writer.close()
}

private def statement(stmt: Statement): Node = {
private def statement(stmt: Statement, writer: XMLStreamWriter): Unit = {
debug match {
case true =>
<statement package={stmt.location.packageName}
class={stmt.location.className}
class-type={stmt.location.classType.toString}
full-class-name={stmt.location.fullClassName}
source={stmt.source}
method={stmt.location.method}
start={stmt.start.toString}
end={stmt.end.toString}
line={stmt.line.toString}
symbol={escape(stmt.symbolName)}
tree={escape(stmt.treeName)}
branch={stmt.branch.toString}
invocation-count={stmt.count.toString}
ignored={stmt.ignored.toString}>
{escape(stmt.desc)}
</statement>
writer.writeStartElement("statement")
writer.writeAttribute("package", stmt.location.packageName)
writer.writeAttribute("class", stmt.location.className)
writer.writeAttribute("class-type", stmt.location.classType.toString)
writer.writeAttribute("full-class-name", stmt.location.fullClassName)
writer.writeAttribute("source", stmt.source)
writer.writeAttribute("method", stmt.location.method)
writer.writeAttribute("start", stmt.start.toString)
writer.writeAttribute("end", stmt.end.toString)
writer.writeAttribute("line", stmt.line.toString)
writer.writeAttribute("symbol", escape(stmt.symbolName))
writer.writeAttribute("tree", escape(stmt.treeName))
writer.writeAttribute("branch", stmt.branch.toString)
writer.writeAttribute("invocation-count", stmt.count.toString)
writer.writeAttribute("ignored", stmt.ignored.toString)
writer.writeCharacters(escape(stmt.desc))
writer.writeEndElement()
case false =>
<statement package={stmt.location.packageName}
class={stmt.location.className}
class-type={stmt.location.classType.toString}
full-class-name={stmt.location.fullClassName}
source={stmt.source}
method={stmt.location.method}
start={stmt.start.toString}
end={stmt.end.toString}
line={stmt.line.toString}
branch={stmt.branch.toString}
invocation-count={stmt.count.toString}
ignored={stmt.ignored.toString}/>
writer.writeStartElement("statement")
writer.writeAttribute("package", stmt.location.packageName)
writer.writeAttribute("class", stmt.location.className)
writer.writeAttribute("class-type", stmt.location.classType.toString)
writer.writeAttribute("full-class-name", stmt.location.fullClassName)
writer.writeAttribute("source", stmt.source)
writer.writeAttribute("method", stmt.location.method)
writer.writeAttribute("start", stmt.start.toString)
writer.writeAttribute("end", stmt.end.toString)
writer.writeAttribute("line", stmt.line.toString)
writer.writeAttribute("branch", stmt.branch.toString)
writer.writeAttribute("invocation-count", stmt.count.toString)
writer.writeAttribute("ignored", stmt.ignored.toString)
writer.writeEndElement()
}
}

private def method(method: MeasuredMethod): Node = {
<method name={method.name}
statement-count={method.statementCount.toString}
statements-invoked={method.invokedStatementCount.toString}
statement-rate={method.statementCoverageFormatted}
branch-rate={method.branchCoverageFormatted}>
<statements>
{method.statements.map(statement)}
</statements>
</method>
private def method(method: MeasuredMethod, writer: XMLStreamWriter): Unit = {
writer.writeStartElement("method")
writer.writeAttribute("name", method.name)
writer.writeAttribute("statement-count", method.statementCount.toString)
writer.writeAttribute("statements-invoked", method.invokedStatementCount.toString)
writer.writeAttribute("statement-rate", method.statementCoverageFormatted)
writer.writeAttribute("branch-rate",method.branchCoverageFormatted)

writer.writeStartElement("statements")
method.statements.foreach{s: Statement => statement(s, writer)}
writer.writeEndElement()
writer.writeEndElement()

}

private def klass(klass: MeasuredClass): Node = {
<class name={klass.fullClassName}
filename={relativeSource(klass.source)}
statement-count={klass.statementCount.toString}
statements-invoked={klass.invokedStatementCount.toString}
statement-rate={klass.statementCoverageFormatted}
branch-rate={klass.branchCoverageFormatted}>
<methods>
{klass.methods.map(method)}
</methods>
</class>
private def klass(klass: MeasuredClass, writer: XMLStreamWriter): Unit = {
writer.writeStartElement("class")
writer.writeAttribute("name", klass.fullClassName)
writer.writeAttribute("filename", relativeSource(klass.source))
writer.writeAttribute("statement-count", klass.statementCount.toString)
writer.writeAttribute("statements-invoked", klass.invokedStatementCount.toString)
writer.writeAttribute("statement-rate", klass.statementCoverageFormatted)
writer.writeAttribute("branch-rate",klass.branchCoverageFormatted)

writer.writeStartElement("methods")
klass.methods.foreach{m: MeasuredMethod => method(m, writer)}
writer.writeEndElement()
writer.writeEndElement()
}

private def pack(pack: MeasuredPackage): Node = {
<package name={pack.name}
statement-count={pack.statementCount.toString}
statements-invoked={pack.invokedStatementCount.toString}
statement-rate={pack.statementCoverageFormatted}>
<classes>
{pack.classes.map(klass)}
</classes>
</package>
private def pack(pack: MeasuredPackage, writer: XMLStreamWriter): Unit = {
writer.writeStartElement("package")
writer.writeAttribute("name", pack.name)
writer.writeAttribute("statement-count", pack.statementCount.toString)
writer.writeAttribute("statements-invoked", pack.invokedStatementCount.toString)
writer.writeAttribute("statement-rate", pack.statementCoverageFormatted)

writer.writeStartElement("classes")
pack.classes.foreach{k: MeasuredClass => klass(k, writer)}
writer.writeEndElement()
writer.writeEndElement()
}
/**
* This method ensures that the output String has only
* valid XML unicode characters as specified by the
* XML 1.0 standard. For reference, please see
* <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
* standard</a>. This method will return an empty
* String if the input is null or empty.
*
* @param in The String whose non-valid characters we want to remove.
* @return The in String, stripped of non-valid characters.
* @see http://blog.mark-mclaren.info/2007/02/invalid-xml-characters-when-valid-utf8_5873.html
*
*/
* This method ensures that the output String has only
* valid XML unicode characters as specified by the
* XML 1.0 standard. For reference, please see
* <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
* standard</a>. This method will return an empty
* String if the input is null or empty.
*
* @param in The String whose non-valid characters we want to remove.
* @return The in String, stripped of non-valid characters.
* @see http://blog.mark-mclaren.info/2007/02/invalid-xml-characters-when-valid-utf8_5873.html
*
*/
def escape(in: String): String = {
val out = new StringBuilder()
for ( current <- Option(in).getOrElse("").toCharArray ) {
Expand Down