Skip to content

Commit ebee919

Browse files
authored
Merge pull request #2 from thedavidharris/master
chore: add Sonarqube XML exporter
2 parents 1612342 + 447d350 commit ebee919

9 files changed

+818
-12
lines changed

Sources/Core/Commands/GenerateCommand.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ public extension Xccov.Commands {
1414
public extension Xccov.Commands.Generate {
1515
enum Output: String, ExpressibleByArgument {
1616
case coberturaXml = "cobertura-xml"
17+
case sonarqubeXml = "sonarqube-xml"
1718
case failable = "failable"
1819

1920
var converter: Xccov.Converters.Converter {
2021
switch self {
2122
case .coberturaXml:
2223
return Xccov.Converters.CoberturaXml.convert(coverageReport:)
24+
case .sonarqubeXml:
25+
return Xccov.Converters.SonarqubeXml.convert(coverageReport:)
2326
case .failable:
2427
return Xccov.Converters.FailableConverter.convert(coverageReport:)
2528
}
@@ -29,8 +32,11 @@ public extension Xccov.Commands.Generate {
2932
switch self {
3033
case .coberturaXml:
3134
return "cobertura.xml"
35+
case .sonarqubeXml:
36+
return "sonarqube.xml"
3237
case .failable:
3338
return "failable.xml"
39+
3440
}
3541
}
3642
}

Sources/Core/Converters/CoberturaXmlConverter.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,6 @@ public extension Xccov.Converters {
1111
enum CoberturaXml {}
1212
}
1313

14-
extension XMLNode {
15-
static func nodeAttribute(withName name: String, stringValue value: String) -> XMLNode {
16-
guard let attribute = XMLNode.attribute(withName: name, stringValue: value) as? XMLNode else {
17-
return XMLNode()
18-
}
19-
20-
return attribute
21-
}
22-
}
23-
2414
public extension Xccov.Converters.CoberturaXml {
2515
static func convert(coverageReport: CoverageReport) -> Result<String, Xccov.Error> {
2616
Self.convert(coverageReport: coverageReport,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//
2+
// SonarqubeXmlConverter.swift
3+
//
4+
//
5+
// Created by Harris, David (D.A.) on 1/19/21.
6+
//
7+
8+
import Foundation
9+
10+
public extension Xccov.Converters {
11+
enum SonarqubeXml {}
12+
}
13+
14+
public extension Xccov.Converters.SonarqubeXml {
15+
static func convert(coverageReport: CoverageReport) -> Result<String, Xccov.Error> {
16+
let rootElement = XMLElement(name: "coverage")
17+
rootElement.addAttribute(XMLNode.nodeAttribute(withName: "version", stringValue: "1"))
18+
19+
let doc = XMLDocument(rootElement: rootElement)
20+
21+
// Sort files to avoid duplicated packages
22+
let allFiles = coverageReport.targets.flatMap { $0.files }.sorted { $0.path < $1.path }
23+
24+
25+
allFiles.forEach { fileCoverageReport in
26+
let filePath = fileCoverageReport.path
27+
28+
let fileElement = XMLElement(name: "file")
29+
fileElement.addAttribute(XMLNode.nodeAttribute(withName: "path", stringValue: filePath))
30+
31+
rootElement.addChild(fileElement)
32+
33+
for functionCoverageReport in fileCoverageReport.functions {
34+
for index in 0..<functionCoverageReport.executableLines {
35+
let lineElement = XMLElement(kind: .element, options: .nodeCompactEmptyElement)
36+
lineElement.name = "lineToCover"
37+
38+
lineElement.addAttribute(XMLNode.nodeAttribute(withName: "lineNumber", stringValue: "\(functionCoverageReport.lineNumber + index)"))
39+
40+
let lineHits: Int
41+
if index < functionCoverageReport.coveredLines {
42+
lineHits = functionCoverageReport.executionCount
43+
} else {
44+
lineHits = 0
45+
}
46+
47+
if lineHits > 0 {
48+
lineElement.addAttribute(XMLNode.nodeAttribute(withName: "covered", stringValue: "true"))
49+
} else {
50+
lineElement.addAttribute(XMLNode.nodeAttribute(withName: "covered", stringValue: "false"))
51+
}
52+
53+
fileElement.addChild(lineElement)
54+
}
55+
}
56+
57+
}
58+
59+
60+
return .success(doc.xmlString(options: [.nodePrettyPrint]))
61+
}
62+
}
63+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// XMLNode+NodeAttribute.swift
3+
//
4+
//
5+
// Created by Harris, David (D.A.) on 1/20/21.
6+
//
7+
8+
import Foundation
9+
10+
extension XMLNode {
11+
static func nodeAttribute(withName name: String, stringValue value: String) -> XMLNode {
12+
guard let attribute = XMLNode.attribute(withName: name, stringValue: value) as? XMLNode else {
13+
return XMLNode()
14+
}
15+
16+
return attribute
17+
}
18+
}

Tests/CoreTests/Converters/CoberturaXmlConverterTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ final class CoberturaXmlConverterTests: XCTestCase {
2121
let receivedResult = try! result.get()
2222

2323
// Then: the xml is the expected one
24-
XCTAssertEqual(receivedResult, converterFixtureCoverageXml)
24+
XCTAssertEqual(receivedResult, coberturaFixtureCoverageXml)
2525
}
2626

2727
static var allTests = [

Tests/CoreTests/Converters/Fixtures/ConverterCoverageXml.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Created by Thibault Wittemberg on 2020-07-04.
66
//
77

8-
let converterFixtureCoverageXml = """
8+
let coberturaFixtureCoverageXml = """
99
<?xml version="1.0"?>
1010
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd" [
1111
<!ELEMENT coverage (sources?, packages)>

0 commit comments

Comments
 (0)