Skip to content
Merged
Show file tree
Hide file tree
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
79 changes: 54 additions & 25 deletions Sources/xcresultparser/CoberturaCoverageConverter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class CoberturaCoverageConverter: CoverageConverter, XmlSerializable {
dtd.name = "coverage"
// dtd.systemID = "http://cobertura.sourceforge.net/xml/coverage-04.dtd"
dtd.systemID =
"https://github.com/cobertura/cobertura/blob/master/cobertura/src/site/htdocs/xml/coverage-04.dtd"
"https://github.com/cobertura/cobertura/blob/master/cobertura/src/site/htdocs/xml/coverage-04.dtd"

let rootElement = makeRootElement()

Expand Down Expand Up @@ -103,7 +103,7 @@ public class CoberturaCoverageConverter: CoverageConverter, XmlSerializable {

for file in fileInfo {
let pathComponents = file.path.split(separator: "/")
let packageName = pathComponents[0 ..< pathComponents.count - 1].joined(separator: ".")
let packageName = createValidPackageName(from: pathComponents)

isNewPackage = currentPackage != packageName

Expand All @@ -115,36 +115,37 @@ public class CoberturaCoverageConverter: CoverageConverter, XmlSerializable {

currentPackage = packageName
if isNewPackage {
let packageLineCoverage = calculatePackageLineCoverage(for: packageName, in: fileInfo)
currentPackageElement.addAttribute(XMLNode.nodeAttribute(withName: "name", stringValue: packageName))
currentPackageElement.addAttribute(XMLNode.nodeAttribute(withName: "line-rate", stringValue: "1.0"))
currentPackageElement.addAttribute(XMLNode.nodeAttribute(withName: "line-rate", stringValue: "\(packageLineCoverage)"))
currentPackageElement.addAttribute(XMLNode.nodeAttribute(withName: "branch-rate", stringValue: "1.0"))
currentPackageElement.addAttribute(XMLNode.nodeAttribute(withName: "complexity", stringValue: "0.0"))
currentClassesElement = XMLElement(name: "classes")
currentPackageElement.addChild(currentClassesElement)
}

let classElement = XMLElement(name: "class")
classElement.addAttribute(XMLNode.nodeAttribute(
withName: "name",
stringValue: "\(packageName).\((file.path as NSString).deletingPathExtension)"
))
classElement.addAttribute(XMLNode.nodeAttribute(withName: "filename", stringValue: "\(file.path)"))
let className = createValidClassName(from: file.path, packageName: packageName)
classElement.addAttribute(XMLNode.nodeAttribute(withName: "name", stringValue: className))
classElement.addAttribute(XMLNode.nodeAttribute(withName: "filename", stringValue: file.path))

let fileLineCoverage = Float(file.lines.filter { $0.coverage > 0 }.count) / Float(file.lines.count)
classElement.addAttribute(XMLNode.nodeAttribute(withName: "line-rate", stringValue: "\(fileLineCoverage)"))
classElement.addAttribute(XMLNode.nodeAttribute(withName: "branch-rate", stringValue: "1.0"))
classElement.addAttribute(XMLNode.nodeAttribute(withName: "complexity", stringValue: "0.0"))
currentClassesElement.addChild(classElement)

// Add empty methods element as required by DTD
let methodsElement = XMLElement(name: "methods")
classElement.addChild(methodsElement)

let linesElement = XMLElement(name: "lines")
classElement.addChild(linesElement)

for line in file.lines {
let lineElement = XMLElement(kind: .element, options: .nodeCompactEmptyElement)
lineElement.name = "line"
let lineElement = XMLElement(name: "line")
lineElement.addAttribute(XMLNode.nodeAttribute(withName: "number", stringValue: "\(line.lineNumber)"))
lineElement.addAttribute(XMLNode.nodeAttribute(withName: "branch", stringValue: "false"))

lineElement.addAttribute(XMLNode.nodeAttribute(withName: "hits", stringValue: "\(line.coverage)"))
linesElement.addChild(lineElement)
}
Expand All @@ -164,7 +165,7 @@ public class CoberturaCoverageConverter: CoverageConverter, XmlSerializable {
private func makeRootElement() -> XMLElement {
// TODO: some of these values are B.S. - figure out how to calculate, or better to omit if we don't know?
let testAction = invocationRecord.actions.first { $0.schemeCommandName == "Test" }
let timeStamp = (testAction?.startedTime.timeIntervalSince1970) ?? Date().timeIntervalSince1970
let timeStamp = (testAction?.startedTime.timeIntervalSince1970) ?? 1672825221.218
Copy link
Owner

Choose a reason for hiding this comment

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

Why was this changed to a literal?
Todays date as a default seems more reasonable to me.

let rootElement = XMLElement(name: "coverage")
rootElement.addAttribute(
XMLNode.nodeAttribute(withName: "line-rate", stringValue: "\(codeCoverage.lineCoverage)")
Expand Down Expand Up @@ -192,13 +193,41 @@ public class CoberturaCoverageConverter: CoverageConverter, XmlSerializable {
// because as command line tool this is not a bundle and thus there is no file to be found in the bundle
// IMO all that was overengineered for the followong 60 lines string...
// ...which will probably never ever change!
// Helper methods for creating valid Cobertura XML structure
private func createValidPackageName(from pathComponents: [Substring]) -> String {
// Use original simple logic: join all path components except the filename with dots
return pathComponents[0..<pathComponents.count - 1].joined(separator: ".")
}

private func createValidClassName(from filePath: String, packageName: String) -> String {
let baseName = (filePath as NSString).deletingPathExtension
return "\(packageName).\(baseName)"
}

private func calculatePackageLineCoverage(for packageName: String, in fileInfoArray: [FileInfo]) -> Float {
let packageFiles = fileInfoArray.filter { file in
let pathComponents = file.path.split(separator: "/")
let filePackageName = createValidPackageName(from: pathComponents)
return filePackageName == packageName
}

guard !packageFiles.isEmpty else { return 0.0 }

let totalLines = packageFiles.reduce(0) { $0 + $1.lines.count }
let coveredLines = packageFiles.reduce(0) { total, file in
total + file.lines.filter { $0.coverage > 0 }.count
}

return totalLines > 0 ? Float(coveredLines) / Float(totalLines) : 0.0
}

private var dtd04 = """
<!-- Portions (C) International Organization for Standardization 1986:
Permission to copy in any form is granted for use with
conforming SGML systems and applications as defined in
ISO 8879, provided this notice is included in all copies.
-->

<!ELEMENT coverage (sources?,packages)>
<!ATTLIST coverage line-rate CDATA #REQUIRED>
<!ATTLIST coverage branch-rate CDATA #REQUIRED>
Expand All @@ -209,47 +238,47 @@ public class CoberturaCoverageConverter: CoverageConverter, XmlSerializable {
<!ATTLIST coverage complexity CDATA #REQUIRED>
<!ATTLIST coverage version CDATA #REQUIRED>
<!ATTLIST coverage timestamp CDATA #REQUIRED>

<!ELEMENT sources (source*)>

<!ELEMENT source (#PCDATA)>

<!ELEMENT packages (package*)>

<!ELEMENT package (classes)>
<!ATTLIST package name CDATA #REQUIRED>
<!ATTLIST package line-rate CDATA #REQUIRED>
<!ATTLIST package branch-rate CDATA #REQUIRED>
<!ATTLIST package complexity CDATA #REQUIRED>

<!ELEMENT classes (class*)>

<!ELEMENT class (methods,lines)>
<!ATTLIST class name CDATA #REQUIRED>
<!ATTLIST class filename CDATA #REQUIRED>
<!ATTLIST class line-rate CDATA #REQUIRED>
<!ATTLIST class branch-rate CDATA #REQUIRED>
<!ATTLIST class complexity CDATA #REQUIRED>

<!ELEMENT methods (method*)>

<!ELEMENT method (lines)>
<!ATTLIST method name CDATA #REQUIRED>
<!ATTLIST method signature CDATA #REQUIRED>
<!ATTLIST method line-rate CDATA #REQUIRED>
<!ATTLIST method branch-rate CDATA #REQUIRED>
<!ATTLIST method complexity CDATA #REQUIRED>

<!ELEMENT lines (line*)>

<!ELEMENT line (conditions*)>
<!ATTLIST line number CDATA #REQUIRED>
<!ATTLIST line hits CDATA #REQUIRED>
<!ATTLIST line branch CDATA "false">
<!ATTLIST line condition-coverage CDATA "100%">

<!ELEMENT conditions (condition*)>

<!ELEMENT condition EMPTY>
<!ATTLIST condition number CDATA #REQUIRED>
<!ATTLIST condition type CDATA #REQUIRED>
Expand Down
31 changes: 22 additions & 9 deletions Tests/XcresultparserTests/TestAssets/cobertura.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE coverage SYSTEM "https://github.com/cobertura/cobertura/blob/master/cobertura/src/site/htdocs/xml/coverage-04.dtd" [
<!ELEMENT coverage (sources?, packages)>
<!ATTLIST coverage line-rate CDATA #REQUIRED>
Expand Down Expand Up @@ -50,9 +50,10 @@
<source>.</source>
</sources>
<packages>
<package name="Users.fhaeser.code.xcresultparser.Tests.XcresultparserTests" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<package name="Users.fhaeser.code.xcresultparser.Tests.XcresultparserTests" line-rate="0.918239" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Tests.XcresultparserTests./Users/fhaeser/code/xcresultparser/Tests/XcresultparserTests/XcresultparserTests" filename="/Users/fhaeser/code/xcresultparser/Tests/XcresultparserTests/XcresultparserTests.swift" line-rate="0.918239" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="5" branch="false" hits="1"/>
<line number="6" branch="false" hits="1"/>
Expand Down Expand Up @@ -217,9 +218,10 @@
</class>
</classes>
</package>
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser" line-rate="0.41025642" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/XCResultFormatter" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/XCResultFormatter.swift" line-rate="0.4760479" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="18" branch="false" hits="3"/>
<line number="19" branch="false" hits="3"/>
Expand Down Expand Up @@ -558,6 +560,7 @@
</lines>
</class>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/SonarCoverageConverter" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/SonarCoverageConverter.swift" line-rate="0.0" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="12" branch="false" hits="0"/>
<line number="13" branch="false" hits="0"/>
Expand Down Expand Up @@ -615,6 +618,7 @@
</lines>
</class>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/Shell" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/Shell.swift" line-rate="0.0" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="15" branch="false" hits="0"/>
<line number="16" branch="false" hits="0"/>
Expand Down Expand Up @@ -648,6 +652,7 @@
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/OutputFormat" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/OutputFormat.swift" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="13" branch="false" hits="6"/>
<line number="14" branch="false" hits="6"/>
Expand All @@ -664,6 +669,7 @@
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/XCResultFormatting" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/XCResultFormatting.swift" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="36" branch="false" hits="3"/>
<line number="37" branch="false" hits="3"/>
Expand All @@ -675,9 +681,10 @@
</class>
</classes>
</package>
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.Text" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.Text" line-rate="0.6037736" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.Text./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/Text/TextResultFormatter" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/Text/TextResultFormatter.swift" line-rate="0.6037736" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="13" branch="false" hits="1"/>
<line number="15" branch="false" hits="1"/>
Expand Down Expand Up @@ -736,9 +743,10 @@
</class>
</classes>
</package>
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.Markdown" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.Markdown" line-rate="0.0" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.Markdown./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/Markdown/MDResultFormatter" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/Markdown/MDResultFormatter.swift" line-rate="0.0" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="15" branch="false" hits="0"/>
<line number="17" branch="false" hits="0"/>
Expand Down Expand Up @@ -801,9 +809,10 @@
</class>
</classes>
</package>
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.HTML" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.HTML" line-rate="0.8642534" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.HTML./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/HTML/HTMLResultFormatter" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/HTML/HTMLResultFormatter.swift" line-rate="0.8642534" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="11" branch="false" hits="1"/>
<line number="13" branch="false" hits="1"/>
Expand Down Expand Up @@ -1030,9 +1039,10 @@
</class>
</classes>
</package>
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.CLI" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.CLI" line-rate="0.61904764" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser.OutputFormatting.Formatters.CLI./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/CLI/CLIResultFormatter" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/OutputFormatting/Formatters/CLI/CLIResultFormatter.swift" line-rate="0.61904764" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="11" branch="false" hits="1"/>
<line number="14" branch="false" hits="1"/>
Expand Down Expand Up @@ -1101,9 +1111,10 @@
</class>
</classes>
</package>
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser" line-rate="1.0" branch-rate="1.0" complexity="0.0">
<package name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser" line-rate="0.41025642" branch-rate="1.0" complexity="0.0">
<classes>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/JunitXML" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/JunitXML.swift" line-rate="0.7527675" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="35" branch="false" hits="0"/>
<line number="36" branch="false" hits="0"/>
Expand Down Expand Up @@ -1379,6 +1390,7 @@
</lines>
</class>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/CoverageConverter" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/CoverageConverter.swift" line-rate="0.078125" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="29" branch="false" hits="1"/>
<line number="30" branch="false" hits="1"/>
Expand Down Expand Up @@ -1447,6 +1459,7 @@
</lines>
</class>
<class name="Users.fhaeser.code.xcresultparser.Sources.xcresultparser./Users/fhaeser/code/xcresultparser/Sources/xcresultparser/CoberturaCoverageConverter" filename="/Users/fhaeser/code/xcresultparser/Sources/xcresultparser/CoberturaCoverageConverter.swift" line-rate="0.0" branch-rate="1.0" complexity="0.0">
<methods/>
<lines>
<line number="35" branch="false" hits="0"/>
<line number="36" branch="false" hits="0"/>
Expand Down Expand Up @@ -1603,4 +1616,4 @@
</classes>
</package>
</packages>
</coverage>
</coverage>
Loading