Skip to content

Commit

Permalink
scoverage#171 Migrate CoverageChecker (and its test) from Groovy to K…
Browse files Browse the repository at this point in the history
…otlin
  • Loading branch information
eyalroth committed Sep 21, 2021
1 parent 6e95ca2 commit 56192f1
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 132 deletions.
15 changes: 15 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
`java-gradle-plugin`
id("com.gradle.plugin-publish") version "0.15.0"
id("org.jetbrains.gradle.plugin.idea-ext") version "1.0"
kotlin("jvm") version "1.5.31"
}

repositories {
Expand Down Expand Up @@ -38,17 +39,30 @@ pluginBundle {
}

apply(plugin = "maven-publish")
// TODO #171 remove once all groovy classes are migrated to kotlin
apply(plugin = "groovy")

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

// TODO #171 remove once all groovy classes are migrated to kotlin
val compileKotlinTask = tasks.compileKotlin.get()
tasks {
named<GroovyCompile>("compileGroovy") {
dependsOn(compileKotlin)
classpath = classpath.plus(files(compileKotlinTask.destinationDirectory))
}
}

dependencies {
compileOnly("org.scoverage:scalac-scoverage-plugin_2.13:1.4.2")
implementation(group = "commons-io", name = "commons-io", version = "2.6")

implementation(kotlin("script-runtime"))
testImplementation(kotlin("test"))

testImplementation("junit:junit:4.12")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.5.2")
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.5.2")
Expand Down Expand Up @@ -122,6 +136,7 @@ gradlePlugin {
testSourceSets(sourceSets["functionalTest"], sourceSets["crossScalaVersionTest"])
}

// TODO #171 remove once all groovy classes are migrated to kotlin
val groovydocJar by tasks.registering(Jar::class) {
from("$buildDir/docs/groovydoc")
classifier = "groovydoc"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.junit.Assert;
import org.junit.Test;
import org.scoverage.CoverageChecker.CoverageType;

public abstract class MultipleCheckTasksTest extends ScoverageFunctionalTest {

Expand Down Expand Up @@ -88,4 +89,4 @@ protected void assertResult(AssertableBuildResult result) {
assertOutput(result, ScoverageExtension.DEFAULT_COVERAGE_TYPE, ScoverageExtension.DEFAULT_MINIMUM_RATE);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.Assert;
import org.scoverage.CoverageChecker.CoverageType;
import org.xml.sax.SAXException;

import java.io.File;
Expand Down
98 changes: 0 additions & 98 deletions src/main/groovy/org/scoverage/CoverageChecker.groovy

This file was deleted.

1 change: 1 addition & 0 deletions src/main/groovy/org/scoverage/ScoverageExtension.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.scala.ScalaPlugin
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.scoverage.CoverageChecker.CoverageType

/**
* Defines a new SourceSet for the code to be instrumented.
Expand Down
1 change: 1 addition & 0 deletions src/main/groovy/org/scoverage/ScoveragePlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.scala.ScalaCompile
import org.gradle.api.tasks.testing.Test
import org.scoverage.CoverageChecker.CoverageChecker

import java.nio.file.Files
import java.util.concurrent.ConcurrentHashMap
Expand Down
94 changes: 94 additions & 0 deletions src/main/kotlin/org/scoverage/CoverageChecker.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.scoverage

import groovy.xml.XmlParser
import org.gradle.api.GradleException
import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting
import org.slf4j.Logger
import java.io.File
import java.io.FileNotFoundException

import java.text.DecimalFormat
import java.text.NumberFormat
import java.util.*
import kotlin.jvm.Throws

/**
* Handles different types of coverage Scoverage can measure.
*
* @param configurationName Name of enum option the way it appears in the build configuration.
* @param fileName Name of file with coverage data.
* @param paramName Name of param in XML file with coverage value.
* @param factor Used to normalize coverage value.
*/
enum class CoverageType(
private val configurationName: String,
val fileName: String,
val paramName: String,
private val factor: Double
) {
Line("Line", "cobertura.xml", "line-rate", 1.0),
Statement("Statement", "scoverage.xml", "statement-rate", 100.0),
Branch("Branch", "scoverage.xml", "branch-rate", 100.0);

/** Normalize coverage value to [0, 1] */
fun normalize(value: Double): Double = value / factor

companion object {
fun find(configurationName: String): CoverageType? {
return values().find { it -> it.configurationName.lowercase() == configurationName.lowercase() }
}
}
}

/**
* Throws a GradleException if overall coverage dips below the configured percentage.
*/
class CoverageChecker(private val logger: Logger) {

@JvmOverloads
@Throws(GradleException::class)
fun checkLineCoverage(
reportDir: File,
coverageType: CoverageType,
minimumRate: Double,
nf: NumberFormat = NumberFormat.getInstance(Locale.getDefault())
) {
logger.info("Checking coverage. Type: {}. Minimum rate: {}", coverageType, minimumRate)

val parser = XmlParser()
parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)

val df = DecimalFormat("#.##")

try {
val reportFile = File(reportDir, coverageType.fileName)
val xml = parser.parse(reportFile)
val coverageValue: Double = nf.parse(xml.attribute(coverageType.paramName) as String).toDouble()
val overallRate: Double = coverageType.normalize(coverageValue)

val difference = minimumRate - overallRate

if (difference > 1e-7) {
val iss = df.format(overallRate * 100)
val needed = df.format(minimumRate * 100)
throw GradleException(errorMsg(iss, needed, coverageType))
}
} catch (fnfe: FileNotFoundException) {
throw GradleException(fileNotFoundErrorMsg(coverageType), fnfe)
}
}

companion object {
@VisibleForTesting
internal fun errorMsg(actual: String, expected: String, type: CoverageType): String {
return "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)"
}

@VisibleForTesting
internal fun fileNotFoundErrorMsg(coverageType: CoverageType): String {
return "Coverage file (type: $coverageType) not found, check your configuration."
}
}

}
Loading

0 comments on commit 56192f1

Please sign in to comment.