Skip to content

Commit

Permalink
allow supporting branch coverage (#71)
Browse files Browse the repository at this point in the history
* allow supporting branch coverage

* fix build
  • Loading branch information
nbaztec authored May 6, 2024
1 parent c6870f3 commit 01eaf1d
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 54 deletions.
67 changes: 45 additions & 22 deletions src/main/kotlin/SourceReportParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import java.io.File
import java.math.BigInteger
import java.security.MessageDigest

data class SourceReport(val name: String, val source_digest: String, val coverage: List<Int?>)
data class SourceReport(val name: String, val source_digest: String, val coverage: List<Int?>, val branches: List<Int>)

data class Key(val pkg: String, val file: String)

data class Info(val hits: Int, val branchesMissed: Int, val branchesCovered: Int)

object SourceReportParser {
private val logger: Logger by lazy { LogManager.getLogger(CoverallsReporter::class.java) }

Expand All @@ -31,14 +33,14 @@ object SourceReportParser {
}
}

private fun read(reportPath: String): Map<Key, Map<Int, Int>> {
private fun read(reportPath: String): Map<Key, Map<Int, Info>> {
val reader = SAXReader()
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)

val document = reader.read(File(reportPath))
val root = document.rootElement

val fullCoverage = mutableMapOf<Key, MutableMap<Int, Int>>()
val fullCoverage = mutableMapOf<Key, MutableMap<Int, Info>>()
root.elements("package").forEach { pkg ->
val pkgName = pkg.attributeValue("name")

Expand All @@ -52,9 +54,13 @@ object SourceReportParser {

sf.elements("line").forEach { line ->
val lineIndex = line.attributeValue("nr").toInt() - 1
val branchesMissed = line.attributeValue("mb").toInt()
val branchesCovered = line.attributeValue("cb").toInt()

// jacoco doesn't count hits
fullCoverage.getValue(key)[lineIndex] = if (line.attributeValue("ci").toInt() > 0) 1 else 0
val hits = if (line.attributeValue("ci").toInt() > 0) 1 else 0

fullCoverage.getValue(key)[lineIndex] = Info(hits, branchesMissed, branchesCovered)
}
}
}
Expand All @@ -79,28 +85,36 @@ object SourceReportParser {
project.extensions.findByType(BaseAppModuleExtension::class.java)!!.sourceSets
.getByName("main").java.srcDirs.filterNotNull()
} else // jacocoAggregation plugin
// Gradle 7
// Gradle 7
project.configurations.findByName("allCodeCoverageReportSourceDirectories")
?.incoming?.artifactView { view -> view
.componentFilter { it is ProjectComponentIdentifier }
.lenient(true)
?.incoming?.artifactView { view ->
view
.componentFilter { it is ProjectComponentIdentifier }
.lenient(true)
}?.files?.files
// Gradle 8+
?: project.configurations.findByName("aggregateCodeCoverageReportResults")
?.incoming?.artifactView { view ->
val objects = project.objects
view.withVariantReselection()
view.componentFilter { it is ProjectComponentIdentifier}
view.attributes { attributes -> attributes
.attribute(Bundling.BUNDLING_ATTRIBUTE,
objects.named(Bundling::class.java, Bundling.EXTERNAL))
.attribute(Category.CATEGORY_ATTRIBUTE,
objects.named(Category::class.java, Category.VERIFICATION))
.attribute(VerificationType.VERIFICATION_TYPE_ATTRIBUTE,
objects.named(VerificationType::class.java, VerificationType.MAIN_SOURCES))
view.componentFilter { it is ProjectComponentIdentifier }
view.attributes { attributes ->
attributes
.attribute(
Bundling.BUNDLING_ATTRIBUTE,
objects.named(Bundling::class.java, Bundling.EXTERNAL)
)
.attribute(
Category.CATEGORY_ATTRIBUTE,
objects.named(Category::class.java, Category.VERIFICATION)
)
.attribute(
VerificationType.VERIFICATION_TYPE_ATTRIBUTE,
objects.named(VerificationType::class.java, VerificationType.MAIN_SOURCES)
)
}
}?.files?.files
// main source set
// main source set
?: project.extensions.getByType(SourceSetContainer::class.java)
.getByName("main").allJava.srcDirs.filterNotNull()
} else {
Expand All @@ -121,17 +135,26 @@ object SourceReportParser {

val lines = f.readLines()
val lineHits = arrayOfNulls<Int>(lines.size)

cov.forEach { (line, hits) ->
if (line >=0 && line < lines.size) {
lineHits[line] = hits
val branches = mutableListOf<Int>()

cov.forEach { (line, info) ->
if (line >= 0 && line < lines.size) {
lineHits[line] = info.hits

val totalBranches = info.branchesCovered + info.branchesMissed
if (totalBranches > 0) {
for (branchNumber in 1..totalBranches) {
val covered = if (branchNumber <= info.branchesCovered) 1 else 0
branches.addAll(listOf(line + 1, 0, branchNumber, covered))
}
}
} else {
logger.debug("skipping invalid line $line, (total ${lines.size})")
}
}

val relPath = File(project.rootDir.absolutePath).toURI().relativize(f.toURI()).toString()
SourceReport(relPath, f.md5(), lineHits.toList())
SourceReport(relPath, f.md5(), lineHits.toList(), branches.toList())
}.also {
it
?: logger.info("${key.file} could not be found in any of the source directories, skipping")
Expand Down
6 changes: 3 additions & 3 deletions src/test/kotlin/CoverallsReporterTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ internal class CoverallsReporterTest {
val reporter = spyk(CoverallsReporter(envGetter), recordPrivateCalls = true)
reporter.report(project)

assertEquals(546, coverallsRequest.length())
assertEquals(577, coverallsRequest.length())
}

@Test
Expand Down Expand Up @@ -175,7 +175,7 @@ internal class CoverallsReporterTest {
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: binary
{"repo_token":"test-token","service_name":"github","git":{"head":{"id":"4cd72eadcc34861139b338dd859344d419244e0b","author_name":"John Doe","author_email":"[email protected]","committer_name":"John Doe","committer_email":"[email protected]","message":"test commit"},"branch":"master","remotes":[{"name":"origin","url":"[email protected]:test/testrepo.git"}]},"source_files":[{"name":"javaStyleSrc/main/kotlin/foo/bar/baz/Main.kt","source_digest":"36083cd4c2ac736f9210fd3ed23504b5","coverage":[null,null,null,null,1,1,1,1,null,1,1,0,0,1,1,null,1,1,1]}]}
{"repo_token":"test-token","service_name":"github","git":{"head":{"id":"4cd72eadcc34861139b338dd859344d419244e0b","author_name":"John Doe","author_email":"[email protected]","committer_name":"John Doe","committer_email":"[email protected]","message":"test commit"},"branch":"master","remotes":[{"name":"origin","url":"[email protected]:test/testrepo.git"}]},"source_files":[{"name":"javaStyleSrc/main/kotlin/foo/bar/baz/Main.kt","source_digest":"36083cd4c2ac736f9210fd3ed23504b5","coverage":[null,null,null,null,1,1,1,1,null,1,1,0,0,1,1,null,1,1,1],"branches":[10,0,1,1,10,0,2,0]}]}
""".trimIndent()

assertEquals(expected, actual)
Expand Down Expand Up @@ -216,7 +216,7 @@ Content-Transfer-Encoding: binary
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: binary
{"repo_token":"test-token","service_name":"other","git":{"head":{"id":"4cd72eadcc34861139b338dd859344d419244e0b","author_name":"John Doe","author_email":"[email protected]","committer_name":"John Doe","committer_email":"[email protected]","message":"test commit"},"branch":"master","remotes":[{"name":"origin","url":"[email protected]:test/testrepo.git"}]},"source_files":[{"name":"javaStyleSrc/main/kotlin/foo/bar/baz/Main.kt","source_digest":"36083cd4c2ac736f9210fd3ed23504b5","coverage":[null,null,null,null,1,1,1,1,null,1,1,0,0,1,1,null,1,1,1]}]}
{"repo_token":"test-token","service_name":"other","git":{"head":{"id":"4cd72eadcc34861139b338dd859344d419244e0b","author_name":"John Doe","author_email":"[email protected]","committer_name":"John Doe","committer_email":"[email protected]","message":"test commit"},"branch":"master","remotes":[{"name":"origin","url":"[email protected]:test/testrepo.git"}]},"source_files":[{"name":"javaStyleSrc/main/kotlin/foo/bar/baz/Main.kt","source_digest":"36083cd4c2ac736f9210fd3ed23504b5","coverage":[null,null,null,null,1,1,1,1,null,1,1,0,0,1,1,null,1,1,1],"branches":[10,0,1,1,10,0,2,0]}]}
""".trimIndent()

assertEquals(expected, actual)
Expand Down
4 changes: 3 additions & 1 deletion src/test/kotlin/DataClassTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ internal class DataClassTest {
@Test
fun `data class SourceReport`() {
val cov = arrayListOf(1, null)
val srcReport = SourceReport("1", "2", cov)
val branches = arrayListOf(1, 0, 0, 1)
val srcReport = SourceReport("1", "2", cov, branches)
assertEquals("1", srcReport.name)
assertEquals("2", srcReport.source_digest)
assertEquals(cov, srcReport.coverage)
assertEquals(branches, srcReport.branches)
}

@Test
Expand Down
71 changes: 47 additions & 24 deletions src/test/kotlin/SourceReportParserTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ internal class SourceReportParserTest {
SourceReport(
"javaStyleSrc/main/kotlin/foo/bar/baz/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1),
listOf(10, 0, 1, 1, 10, 0, 2, 0)
)
)
assertEquals(expected, actual)
Expand All @@ -88,12 +89,14 @@ internal class SourceReportParserTest {
SourceReport(
"src/main/kotlin/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1),
listOf(10, 0, 1, 1, 10, 0, 2, 0)
),
SourceReport(
"src/main/kotlin/internal/Util.kt",
"805ee340f4d661be591b4eb42f6164d2",
listOf(null, null, null, null, 1, 1, 1, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null),
emptyList()
)
)
assertEquals(expected, actual)
Expand All @@ -118,12 +121,14 @@ internal class SourceReportParserTest {
SourceReport(
"src/main/kotlin/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1),
listOf(10, 0, 1, 1, 10, 0, 2, 0)
),
SourceReport(
"src/main/kotlin/internal/Util.kt",
"805ee340f4d661be591b4eb42f6164d2",
listOf(null, null, null, null, 1, 1, 1, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null),
emptyList()
)
)
assertEquals(expected, actual)
Expand All @@ -148,12 +153,14 @@ internal class SourceReportParserTest {
SourceReport(
"src/main/kotlin/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1),
listOf(10, 0, 1, 1, 10, 0, 2, 0)
),
SourceReport(
"src/main/kotlin/internal/Util.kt",
"805ee340f4d661be591b4eb42f6164d2",
listOf(null, null, null, null, 1, 1, 1, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null),
emptyList()
)
)
assertEquals(expected, actual)
Expand All @@ -178,17 +185,20 @@ internal class SourceReportParserTest {
SourceReport(
"src/main/kotlin/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1),
listOf(10, 0, 1, 1, 10, 0, 2, 0)
),
SourceReport(
"src/main/kotlin/internal/Util.kt",
"805ee340f4d661be591b4eb42f6164d2",
listOf(null, null, null, null, 1, 1, 1, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null),
emptyList()
),
SourceReport(
"src/anotherMain/kotlin/Lib.kt",
"8b5c1c773cf81996efc19a08f0ac3648",
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null),
emptyList()
)
)
assertEquals(expected, actual)
Expand All @@ -211,8 +221,10 @@ internal class SourceReportParserTest {
})
mockk {
every { files } returns mockk {
every { files } returns setOf( testKotlinStyleSourceDir,
testKotlinStyleSourceDirAdditional)
every { files } returns setOf(
testKotlinStyleSourceDir,
testKotlinStyleSourceDirAdditional
)
}
}
}
Expand All @@ -229,17 +241,20 @@ internal class SourceReportParserTest {
SourceReport(
"src/main/kotlin/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1),
listOf(10, 0, 1, 1, 10, 0, 2, 0)
),
SourceReport(
"src/main/kotlin/internal/Util.kt",
"805ee340f4d661be591b4eb42f6164d2",
listOf(null, null, null, null, 1, 1, 1, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null),
emptyList()
),
SourceReport(
"src/anotherMain/kotlin/Lib.kt",
"8b5c1c773cf81996efc19a08f0ac3648",
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null),
emptyList()
)
)
assertEquals(expected, actual)
Expand All @@ -265,7 +280,7 @@ internal class SourceReportParserTest {
every {
artifactView(capture(artifactViewConfigAction))
} answers {
artifactViewConfigAction.captured.execute(mockk ArtifactViewConfig@ {
artifactViewConfigAction.captured.execute(mockk ArtifactViewConfig@{
every { withVariantReselection() } returns this
every { componentFilter(any()) } returns this
val attributeContainerAction = slot<Action<AttributeContainer>>()
Expand All @@ -284,8 +299,10 @@ internal class SourceReportParserTest {
})
mockk {
every { files } returns mockk {
every { files } returns setOf( testKotlinStyleSourceDir,
testKotlinStyleSourceDirAdditional)
every { files } returns setOf(
testKotlinStyleSourceDir,
testKotlinStyleSourceDirAdditional
)
}
}
}
Expand All @@ -302,17 +319,20 @@ internal class SourceReportParserTest {
SourceReport(
"src/main/kotlin/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1),
listOf(10, 0, 1, 1, 10, 0, 2, 0)
),
SourceReport(
"src/main/kotlin/internal/Util.kt",
"805ee340f4d661be591b4eb42f6164d2",
listOf(null, null, null, null, 1, 1, 1, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null),
emptyList()
),
SourceReport(
"src/anotherMain/kotlin/Lib.kt",
"8b5c1c773cf81996efc19a08f0ac3648",
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null),
emptyList()
)
)
assertEquals(expected, actual)
Expand All @@ -337,17 +357,20 @@ internal class SourceReportParserTest {
SourceReport(
"src/main/kotlin/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1),
listOf(10, 0, 1, 1, 10, 0, 2, 0)
),
SourceReport(
"src/main/kotlin/internal/Util.kt",
"805ee340f4d661be591b4eb42f6164d2",
listOf(null, null, null, null, 1, 1, 1, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null),
emptyList()
),
SourceReport(
"src/anotherMain/kotlin/Lib.kt",
"8b5c1c773cf81996efc19a08f0ac3648",
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null)
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null),
emptyList()
)
)
assertEquals(expected, actual)
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/testreports/jacocoTestReport.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<line nr="6" mi="3" ci="1" mb="0" cb="0"/>
<line nr="7" mi="3" ci="1" mb="0" cb="0"/>
<line nr="8" mi="3" ci="1" mb="0" cb="0"/>
<line nr="10" mi="3" ci="1" mb="0" cb="0"/>
<line nr="10" mi="3" ci="1" mb="1" cb="1"/>
<line nr="11" mi="3" ci="1" mb="0" cb="0"/>
<line nr="12" mi="3" ci="0" mb="0" cb="0"/>
<line nr="13" mi="3" ci="0" mb="0" cb="0"/>
Expand Down
Loading

0 comments on commit 01eaf1d

Please sign in to comment.