Skip to content

Commit

Permalink
Implemented task to print coverage to the log
Browse files Browse the repository at this point in the history
Added task with name `koverLog`, configured by `log { }` block in report variant's configuration

Resolves #229
  • Loading branch information
shanshin committed Jun 22, 2023
1 parent b16aafc commit 78085ec
Show file tree
Hide file tree
Showing 22 changed files with 701 additions and 22 deletions.
21 changes: 21 additions & 0 deletions kover-gradle-plugin/api/kover-gradle-plugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -174,26 +174,46 @@ public abstract interface class kotlinx/kover/gradle/plugin/dsl/KoverInstrumenta
public abstract fun packages ([Ljava/lang/String;)V
}

public abstract interface class kotlinx/kover/gradle/plugin/dsl/KoverLogReportConfig {
public abstract fun filters (Lorg/gradle/api/Action;)V
public abstract fun getAggregationForGroup ()Lkotlinx/kover/gradle/plugin/dsl/AggregationType;
public abstract fun getCoverageUnits ()Lkotlinx/kover/gradle/plugin/dsl/MetricType;
public abstract fun getFormat ()Ljava/lang/String;
public abstract fun getGroupBy ()Lkotlinx/kover/gradle/plugin/dsl/GroupingEntityType;
public abstract fun getHeader ()Ljava/lang/String;
public abstract fun getOnCheck ()Z
public abstract fun setAggregationForGroup (Lkotlinx/kover/gradle/plugin/dsl/AggregationType;)V
public abstract fun setCoverageUnits (Lkotlinx/kover/gradle/plugin/dsl/MetricType;)V
public abstract fun setFormat (Ljava/lang/String;)V
public abstract fun setGroupBy (Lkotlinx/kover/gradle/plugin/dsl/GroupingEntityType;)V
public abstract fun setHeader (Ljava/lang/String;)V
public abstract fun setOnCheck (Z)V
}

public final class kotlinx/kover/gradle/plugin/dsl/KoverNames {
public static final field DEFAULT_HTML_REPORT_NAME Ljava/lang/String;
public static final field DEFAULT_LOG_REPORT_NAME Ljava/lang/String;
public static final field DEFAULT_VERIFY_REPORT_NAME Ljava/lang/String;
public static final field DEFAULT_XML_REPORT_NAME Ljava/lang/String;
public static final field DEPENDENCY_CONFIGURATION_NAME Ljava/lang/String;
public static final field INSTANCE Lkotlinx/kover/gradle/plugin/dsl/KoverNames;
public static final field PROJECT_EXTENSION_NAME Ljava/lang/String;
public static final field REPORT_EXTENSION_NAME Ljava/lang/String;
public final fun androidHtmlReport (Ljava/lang/String;)Ljava/lang/String;
public final fun androidLog (Ljava/lang/String;)Ljava/lang/String;
public final fun androidVerify (Ljava/lang/String;)Ljava/lang/String;
public final fun androidXmlReport (Ljava/lang/String;)Ljava/lang/String;
}

public final class kotlinx/kover/gradle/plugin/dsl/KoverNamesKt {
public static final fun getKoverExtensionName (Lorg/gradle/api/plugins/ExtensionContainer;)Ljava/lang/String;
public static final fun getKoverHtmlReportName (Lorg/gradle/api/tasks/TaskContainer;)Ljava/lang/String;
public static final fun getKoverLogName (Lorg/gradle/api/tasks/TaskContainer;)Ljava/lang/String;
public static final fun getKoverReportExtensionName (Lorg/gradle/api/plugins/ExtensionContainer;)Ljava/lang/String;
public static final fun getKoverVerifyName (Lorg/gradle/api/tasks/TaskContainer;)Ljava/lang/String;
public static final fun getKoverXmlReportName (Lorg/gradle/api/tasks/TaskContainer;)Ljava/lang/String;
public static final fun koverAndroidHtmlReportName (Lorg/gradle/api/tasks/TaskContainer;Ljava/lang/String;)Ljava/lang/String;
public static final fun koverAndroidLogName (Lorg/gradle/api/tasks/TaskContainer;Ljava/lang/String;)Ljava/lang/String;
public static final fun koverAndroidVerifyName (Lorg/gradle/api/tasks/TaskContainer;Ljava/lang/String;)Ljava/lang/String;
public static final fun koverAndroidXmlReportName (Lorg/gradle/api/tasks/TaskContainer;Ljava/lang/String;)Ljava/lang/String;
}
Expand Down Expand Up @@ -241,6 +261,7 @@ public abstract interface class kotlinx/kover/gradle/plugin/dsl/KoverReportFilte
public abstract interface class kotlinx/kover/gradle/plugin/dsl/KoverReportsConfig {
public abstract fun filters (Lorg/gradle/api/Action;)V
public abstract fun html (Lorg/gradle/api/Action;)V
public abstract fun log (Lorg/gradle/api/Action;)V
public abstract fun verify (Lorg/gradle/api/Action;)V
public abstract fun xml (Lorg/gradle/api/Action;)V
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal class AccessorsTests {
dependsOn(tasks.koverHtmlReport)
dependsOn(tasks.koverXmlReport)
dependsOn(tasks.koverVerify)
dependsOn(tasks.koverLog)
}
""".trimIndent()
)
Expand All @@ -46,6 +47,7 @@ internal class AccessorsTests {
assertEquals("SKIPPED", result.taskOutcome(":koverXmlReport"))
assertEquals("SKIPPED", result.taskOutcome(":koverHtmlReport"))
assertEquals("SKIPPED", result.taskOutcome(":koverVerify"))
assertEquals("SKIPPED", result.taskOutcome(":koverLog"))
}

@Test
Expand All @@ -71,6 +73,9 @@ internal class AccessorsTests {
tasks.koverVerifyName mustBe "koverVerify"
tasks.koverVerifyName mustBe KoverNames.DEFAULT_VERIFY_REPORT_NAME
tasks.koverLogName mustBe "koverLog"
tasks.koverLogName mustBe KoverNames.DEFAULT_LOG_REPORT_NAME
Expand All @@ -82,6 +87,9 @@ internal class AccessorsTests {
tasks.koverAndroidVerifyName("variant") mustBe "koverVerifyVariant"
tasks.koverAndroidVerifyName("variant") mustBe KoverNames.androidVerify("variant")
tasks.koverAndroidLogName("variant") mustBe "koverLogVariant"
tasks.koverAndroidLogName("variant") mustBe KoverNames.androidLog("variant")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package kotlinx.kover.gradle.plugin.test.functional.cases

import kotlinx.kover.gradle.plugin.test.functional.framework.configurator.BuildConfigurator
import kotlinx.kover.gradle.plugin.test.functional.framework.starter.GeneratedTest
import kotlin.test.assertTrue


internal class LogTests {
Expand All @@ -20,14 +21,14 @@ internal class LogTests {
run(":koverHtmlReport", "--build-cache") {
checkOutcome("koverHtmlReport", "SUCCESS")
taskOutput("koverHtmlReport") {
contains("Kover: HTML report for")
assertTrue { contains("Kover: HTML report for") }
}
}

run(":koverHtmlReport", "--build-cache") {
checkOutcome("koverHtmlReport", "UP-TO-DATE")
taskOutput("koverHtmlReport") {
contains("Kover: HTML report for")
assertTrue { contains("Kover: HTML report for") }
}
}

Expand All @@ -36,7 +37,7 @@ internal class LogTests {
run(":koverHtmlReport", "--build-cache") {
checkOutcome("koverHtmlReport", "FROM-CACHE")
taskOutput("koverHtmlReport") {
contains("Kover: HTML report for")
assertTrue { contains("Kover: HTML report for") }
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.kover.gradle.plugin.test.functional.cases

import kotlinx.kover.gradle.plugin.commons.CoverageToolVendor
import kotlinx.kover.gradle.plugin.dsl.AggregationType
import kotlinx.kover.gradle.plugin.dsl.GroupingEntityType
import kotlinx.kover.gradle.plugin.dsl.MetricType
import kotlinx.kover.gradle.plugin.test.functional.framework.configurator.BuildConfigurator
import kotlinx.kover.gradle.plugin.test.functional.framework.starter.GeneratedTest
import kotlin.test.assertEquals

internal class LoggingTaskTests {
@GeneratedTest
fun BuildConfigurator.testCaching() {
addProjectWithKover {
sourcesFrom("simple")
useLocalCache()
}

run(":koverLog", "--build-cache") {
checkOutcome("koverLog", "SUCCESS")
checkOutcome("koverPrintCoverage", "SUCCESS")
}
run(":koverLog", "--build-cache") {
checkOutcome("koverLog", "UP-TO-DATE")
checkOutcome("koverPrintCoverage", "SUCCESS")
}
run("clean", "--build-cache")
run(":koverLog", "--build-cache") {
checkOutcome("koverLog", "FROM-CACHE")
checkOutcome("koverPrintCoverage", "SUCCESS")
}
}

@GeneratedTest
fun BuildConfigurator.testDefaultFormat() {
addProjectWithKover {
sourcesFrom("simple")
}

run(":koverLog") {
checkOutcome("koverPrintCoverage", "SUCCESS")
taskOutput("koverPrintCoverage") {
assertEquals("application line coverage: 57.1429%\n\n", this)
}
}
}

@GeneratedTest(tool = CoverageToolVendor.JACOCO)
fun BuildConfigurator.testDefaultFormatJacoco() {
addProjectWithKover {
sourcesFrom("simple")
}

run(":koverLog") {
checkOutcome("koverPrintCoverage", "SUCCESS")
taskOutput("koverPrintCoverage") {
assertEquals("application line coverage: 50%\n\n", this)
}
}
}

@GeneratedTest
fun BuildConfigurator.testHeaderAndFormat() {
addProjectWithKover {
sourcesFrom("simple")

koverReport {
defaults {
log {
header = "Custom header"
format = "My format for <entity> is <value>"
}
}
}
}

run(":koverLog") {
checkOutcome("koverPrintCoverage", "SUCCESS")
taskOutput("koverPrintCoverage") {
assertEquals("Custom header\nMy format for application is 57.1429\n\n", this)
}
}
}

@GeneratedTest
fun BuildConfigurator.testCustomFormatKover() {
addProjectWithKover {
sourcesFrom("simple")

koverReport {
defaults {
log {
header = "Coverage for classes:"
format = "Class <entity> covered instructions=<value>"
groupBy = GroupingEntityType.CLASS
aggregationForGroup = AggregationType.COVERED_COUNT
coverageUnits = MetricType.INSTRUCTION
}
}
}
}

run(":koverLog") {
checkOutcome("koverPrintCoverage", "SUCCESS")
taskOutput("koverPrintCoverage") {
assertEquals(
"Coverage for classes:\n" +
"Class org.jetbrains.ExampleClass covered instructions=5\n" +
"Class org.jetbrains.SecondClass covered instructions=5\n" +
"Class org.jetbrains.Unused covered instructions=0\n\n",
this
)
}
}
}

@GeneratedTest(tool = CoverageToolVendor.JACOCO)
fun BuildConfigurator.testCustomFormatJacoco() {
addProjectWithKover {
sourcesFrom("simple")

koverReport {
defaults {
log {
header = "Coverage for classes:"
format = "Class <entity> covered instructions=<value>"
groupBy = GroupingEntityType.CLASS
aggregationForGroup = AggregationType.COVERED_COUNT
coverageUnits = MetricType.INSTRUCTION
}
}
}
}

run(":koverLog") {
checkOutcome("koverPrintCoverage", "SUCCESS")
taskOutput("koverPrintCoverage") {
assertEquals(
"Coverage for classes:\n" +
"Class org.jetbrains.ExampleClass covered instructions=7\n" +
"Class org.jetbrains.SecondClass covered instructions=7\n" +
"Class org.jetbrains.Unused covered instructions=0\n\n",
this
)
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal class BuildResult(exitCode: Int, private val logFile: File) {
while (index < lines.size) {
val line = lines[index]
index++
if (line.startsWith(prefix)) {
if (line.startsWith("> Task") || line.startsWith("BUILD SUCCESSFUL in")) {
break
}
result += line
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ internal open class KoverReportsWriter(private val writer: FormattedWriter): Kov
override fun verify(config: Action<KoverVerifyReportConfig>) {
writer.call("verify", config) { KoverVerifyReportConfigWriter(it) }
}

override fun log(config: Action<KoverLogReportConfig>) {
writer.call("log", config) { KoverLogReportConfigWriter(it) }
}
}

internal class KoverReportFiltersWriter(private val writer: FormattedWriter) : KoverReportFilters {
Expand Down Expand Up @@ -153,6 +157,67 @@ internal class KoverVerifyReportConfigWriter(private val writer: FormattedWriter
}
}

internal class KoverLogReportConfigWriter(private val writer: FormattedWriter) : KoverLogReportConfig {
override var onCheck: Boolean = true
set(value) {
writer.assign("onCheck", value.toString())
field = value
}

override fun filters(config: Action<KoverReportFilters>) {
writer.call("filters", config) { KoverReportFiltersWriter(it) }
}

override var header: String? = null
set(value) {
if (value == null) {
writer.assign("header", "null")
} else {
writer.assign("header", "\"$value\"")
}
field = value
}

override var format: String? = null
set(value) {
if (value == null) {
writer.assign("format", "null")
} else {
writer.assign("format", "\"$value\"")
}
field = value
}

override var groupBy: GroupingEntityType? = null
set(value) {
if (value == null) {
writer.assign("groupBy", "null")
} else {
writer.assign("groupBy", GroupingEntityType::class.qualifiedName + "." + value)
}
field = value
}

override var coverageUnits: MetricType? = null
set(value) {
if (value == null) {
writer.assign("coverageUnits", "null")
} else {
writer.assign("coverageUnits", MetricType::class.qualifiedName + "." + value)
}
field = value
}
override var aggregationForGroup: AggregationType? = null
set(value) {
if (value == null) {
writer.assign("aggregationForGroup", "null")
} else {
writer.assign("aggregationForGroup", AggregationType::class.qualifiedName + "." + value)
}
field = value
}
}

internal class KoverVerifyRuleWriter(private val writer: FormattedWriter): KoverVerifyRule {
override var isEnabled: Boolean = true
set(value) {
Expand Down
Loading

0 comments on commit 78085ec

Please sign in to comment.