Skip to content

Commit e4a4e72

Browse files
authored
Merge pull request #201 from amosproj/Feature/add-tests-for-result-service
Feature/add tests for result service
2 parents b65464c + 9d32677 commit e4a4e72

File tree

19 files changed

+980
-223
lines changed

19 files changed

+980
-223
lines changed

pitmutationmate/src/main/kotlin/com/amos/pitmutationmate/pitmutationmate/reporting/HTMLParser.kt

Lines changed: 0 additions & 98 deletions
This file was deleted.

pitmutationmate/src/main/kotlin/com/amos/pitmutationmate/pitmutationmate/reporting/XMLParser.kt

Lines changed: 140 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,122 +2,173 @@
22
// SPDX-FileCopyrightText: 2023
33

44
package com.amos.pitmutationmate.pitmutationmate.reporting
5+
6+
import com.intellij.openapi.diagnostic.thisLogger
57
import org.w3c.dom.Document
68
import org.w3c.dom.Element
7-
import org.w3c.dom.Node
89
import java.io.File
910
import javax.xml.parsers.DocumentBuilderFactory
1011

1112
class XMLParser {
1213
fun loadResultsFromXmlReport(xmlMutationReportPath: String, xmlCoverageReportPath: String): ResultData {
14+
thisLogger().info("Loading XML reports from $xmlMutationReportPath and $xmlCoverageReportPath")
1315
val resultData = ResultData()
1416
try {
15-
val documentBuilderFactory = DocumentBuilderFactory.newInstance()
16-
val documentBuilder = documentBuilderFactory.newDocumentBuilder()
17-
val documentMutationReport = documentBuilder.parse(File(xmlMutationReportPath))
18-
val documentCoverageReport = documentBuilder.parse(File(xmlCoverageReportPath))
17+
val documentMutationReport = parseXmlDocument(File(xmlMutationReportPath))
18+
val documentCoverageReport = parseXmlDocument(File(xmlCoverageReportPath))
1919

2020
extractMutationResults(documentMutationReport, resultData)
21-
extractCoverageReports(documentCoverageReport, resultData, false, -1)
22-
extractCoverageReports(documentCoverageReport, resultData, true, resultData.coverageReports.size)
21+
extractCoverageReports(documentCoverageReport, resultData)
22+
extractCoverageReportTotals(documentCoverageReport, resultData)
2323
} catch (e: Exception) {
24-
// TODO: Handle Parser exceptions
25-
e.printStackTrace()
24+
thisLogger().warn("Error while parsing XML reports: ${e.message}")
2625
}
2726

2827
return resultData
2928
}
3029

30+
private fun parseXmlDocument(xmlFile: File): Document {
31+
val factory = DocumentBuilderFactory.newInstance()
32+
val builder = factory.newDocumentBuilder()
33+
return builder.parse(xmlFile)
34+
}
35+
3136
private fun extractMutationResults(document: Document, resultData: ResultData) {
37+
thisLogger().info("Extracting mutation results")
3238
val mutationsNodeList = document.getElementsByTagName("mutation")
3339

3440
for (i in 0 until mutationsNodeList.length) {
35-
val mutationNode = mutationsNodeList.item(i)
36-
37-
if (mutationNode.nodeType == Node.ELEMENT_NODE) {
38-
val element = mutationNode as Element
39-
40-
val detected = getAttribute(element, "detected", false)
41-
val status = getAttribute(element, "status", "N/A")
42-
val numberOfTestsRun = getAttribute(element, "numberOfTestsRun", -1)
43-
val sourceFile = getTextContent(element, "sourceFile")
44-
val mutatedClass = getTextContent(element, "mutatedClass")
45-
val mutatedMethod = getTextContent(element, "mutatedMethod")
46-
val methodDescription = getTextContent(element, "methodDescription")
47-
val lineNumber = getTextContent(element, "lineNumber").toInt()
48-
val mutator = getTextContent(element, "mutator")
49-
val indexes = getListContent(element, "index")
50-
val blocks = getListContent(element, "block")
51-
val killingTest = getTextContent(element, "killingTest")
52-
val description = getTextContent(element, "description")
53-
54-
val mutationResult = MutationResult(
55-
detected,
56-
status,
57-
numberOfTestsRun,
58-
sourceFile,
59-
mutatedClass,
60-
mutatedMethod,
61-
methodDescription,
62-
lineNumber,
63-
mutator,
64-
indexes,
65-
blocks,
66-
killingTest,
67-
description
68-
)
69-
resultData.addMutationResult(mutationResult)
70-
// display color bars for mutation result
71-
resultData.displayResult(mutationResult)
72-
}
41+
val element = mutationsNodeList.item(i) as? Element ?: continue
42+
43+
val detected = getAttribute(element, "detected", false)
44+
val status = getAttribute(element, "status", "N/A")
45+
val numberOfTestsRun = getAttribute(element, "numberOfTestsRun", 0)
46+
val sourceFile = getTextContent(element, "sourceFile")
47+
val mutatedClass = getTextContent(element, "mutatedClass")
48+
val mutatedMethod = getTextContent(element, "mutatedMethod")
49+
val methodDescription = getTextContent(element, "methodDescription")
50+
val lineNumber = getTextContentAsInt(element, "lineNumber")
51+
val mutator = getTextContent(element, "mutator")
52+
val indexes = getListContent(element, "index")
53+
val blocks = getListContent(element, "block")
54+
val killingTest = getTextContent(element, "killingTest")
55+
val description = getTextContent(element, "description")
56+
57+
val mutationResult = MutationResult(
58+
detected,
59+
status,
60+
numberOfTestsRun,
61+
sourceFile,
62+
mutatedClass,
63+
mutatedMethod,
64+
methodDescription,
65+
lineNumber,
66+
mutator,
67+
indexes,
68+
blocks,
69+
killingTest,
70+
description
71+
)
72+
resultData.addMutationResult(mutationResult)
7373
}
7474
}
7575

76-
private fun extractCoverageReports(document: Document, resultData: ResultData, totals: Boolean, totalNumber: Int) {
77-
val mutationsNodeList = document.getElementsByTagName(if (totals) "totalMetaData" else "testMetaData")
76+
private fun extractCoverageReports(document: Document, resultData: ResultData) {
77+
thisLogger().info("Extracting coverage reports")
78+
val mutationsNodeList = document.getElementsByTagName("testMetaData")
7879

7980
for (i in 0 until mutationsNodeList.length) {
80-
val mutationNode = mutationsNodeList.item(i)
81-
82-
if (mutationNode.nodeType == Node.ELEMENT_NODE) {
83-
val element = mutationNode as Element
84-
85-
val fileName = if (totals) "totals" else getTextContent(element, "FileName")
86-
val packageName = if (totals) "totals" else getTextContent(element, "PackageName")
87-
val mutatedClass = if (totals) "totals" else getTextContent(element, "MutatedClass")
88-
val lineCoveragePercentage = getTextContent(element, "LineCoveragePercentage").toInt()
89-
val lineCoverageTextRatio = getTextContent(element, "LineCoverage")
90-
val mutationCoveragePercentage = getTextContent(element, "MutationCoveragePercentage").toInt()
91-
val mutationCoverageTextRatio = getTextContent(element, "MutationCoverage")
92-
val testStrengthPercentage = getTextContent(element, "TestStrengthPercentage").toInt()
93-
val testStrengthTextRatio = getTextContent(element, "TestStrength")
94-
95-
val coverageReport = CoverageReport(
96-
fileName,
97-
packageName,
98-
mutatedClass,
99-
lineCoveragePercentage,
100-
lineCoverageTextRatio,
101-
mutationCoveragePercentage,
102-
mutationCoverageTextRatio,
103-
testStrengthPercentage,
104-
testStrengthTextRatio,
105-
if (totals) totalNumber else 1
106-
)
107-
if (totals) resultData.totalResult = coverageReport else resultData.addCoverageReport(coverageReport)
108-
}
81+
val element = mutationsNodeList.item(i) as? Element ?: continue
82+
83+
val fileName = getTextContent(element, "FileName")
84+
val packageName = getTextContent(element, "PackageName")
85+
val mutatedClass = getTextContent(element, "MutatedClass")
86+
val coverageReport = CoverageReport(
87+
fileName,
88+
packageName,
89+
mutatedClass,
90+
getLineCoveragePercentage(element),
91+
getLineCoverageTextRatio(element),
92+
getMutationCoveragePercentage(element),
93+
getMutationCoverageTextRatio(element),
94+
getTestStrengthPercentage(element),
95+
getTestStrengthTextRatio(element),
96+
if (fileName == "N/A") 0 else 1
97+
)
98+
resultData.addCoverageReport(coverageReport)
99+
}
100+
}
101+
102+
private fun extractCoverageReportTotals(document: Document, resultData: ResultData) {
103+
thisLogger().info("Extracting coverage report totals")
104+
val mutationsNodeList = document.getElementsByTagName("totalMetaData")
105+
106+
for (i in 0 until mutationsNodeList.length) {
107+
val element = mutationsNodeList.item(i) as? Element ?: continue
108+
109+
val coverageReport = CoverageReport(
110+
"totals",
111+
"totals",
112+
"totals",
113+
getLineCoveragePercentage(element),
114+
getLineCoverageTextRatio(element),
115+
getMutationCoveragePercentage(element),
116+
getMutationCoverageTextRatio(element),
117+
getTestStrengthPercentage(element),
118+
getTestStrengthTextRatio(element),
119+
0
120+
)
121+
resultData.addCoverageReportTotals(coverageReport)
109122
}
110123
}
111124

125+
private fun getLineCoveragePercentage(element: Element): Int {
126+
return getTextContentAsInt(element, "LineCoveragePercentage")
127+
}
128+
129+
private fun getLineCoverageTextRatio(element: Element): String {
130+
return getTextContent(element, "LineCoverage")
131+
}
132+
133+
private fun getMutationCoveragePercentage(element: Element): Int {
134+
return getTextContentAsInt(element, "MutationCoveragePercentage")
135+
}
136+
137+
private fun getMutationCoverageTextRatio(element: Element): String {
138+
return getTextContent(element, "MutationCoverage")
139+
}
140+
141+
private fun getTestStrengthPercentage(element: Element): Int {
142+
return getTextContentAsInt(element, "TestStrengthPercentage")
143+
}
144+
145+
private fun getTestStrengthTextRatio(element: Element): String {
146+
return getTextContent(element, "TestStrength")
147+
}
148+
112149
private fun getTextContent(element: Element, tagName: String): String {
113150
val nodeList = element.getElementsByTagName(tagName)
114151
return if (nodeList.length > 0) {
115-
nodeList.item(0).textContent
152+
nodeList.item(0).textContent.trim()
116153
} else {
117154
"N/A"
118155
}
119156
}
120157

158+
private fun getTextContentAsInt(element: Element, tagName: String): Int {
159+
val nodeList = element.getElementsByTagName(tagName)
160+
return if (nodeList.length > 0) {
161+
val content = nodeList.item(0).textContent.trim()
162+
return if (content.toIntOrNull() != null) {
163+
content.toInt()
164+
} else {
165+
0
166+
}
167+
} else {
168+
0
169+
}
170+
}
171+
121172
private fun getListContent(element: Element, tagName: String): List<Int> {
122173
val nodeList = element.getElementsByTagName(tagName)
123174
return if (nodeList.length > 0) {
@@ -127,14 +178,14 @@ class XMLParser {
127178
}
128179
}
129180

130-
private fun <T> getAttribute(element: Element, attributeName: String, defaultValue: T): T {
181+
private inline fun <reified T> getAttribute(element: Element, attributeName: String, defaultValue: T): T {
131182
return try {
132183
val attributeValue = element.getAttribute(attributeName)
133184
if (attributeValue.isNotEmpty()) {
134-
when (defaultValue) {
135-
is Boolean -> attributeValue.toBoolean() as T
136-
is Int -> attributeValue.toInt() as T
137-
is String -> attributeValue as T
185+
when (T::class) {
186+
Boolean::class -> attributeValue.toBoolean() as T
187+
Int::class -> attributeValue.toIntOrNull() as? T ?: defaultValue
188+
String::class -> attributeValue as T
138189
else -> defaultValue
139190
}
140191
} else {
@@ -146,7 +197,6 @@ class XMLParser {
146197
}
147198

148199
data class ResultData(
149-
// placeholder field for coverage report results to be displayed in visualisation
150200
val coverageReports: MutableList<CoverageReport> = mutableListOf(),
151201
val mutationResults: MutableList<MutationResult> = mutableListOf(),
152202
var totalResult: CoverageReport? = null
@@ -159,8 +209,11 @@ class XMLParser {
159209
coverageReports.add(coverageReport)
160210
}
161211

162-
fun displayResult(mutationResult: MutationResult) {
163-
// removed in favor of MutationsAnnotator
212+
fun addCoverageReportTotals(coverageReport: CoverageReport) {
213+
if (coverageReports.isNotEmpty()) {
214+
coverageReport.numberOfClasses = coverageReports.size
215+
}
216+
totalResult = coverageReport
164217
}
165218
}
166219

0 commit comments

Comments
 (0)