Skip to content

Commit

Permalink
Use Provider API for Jacoco & instrumentation test DSLs in the plugin (
Browse files Browse the repository at this point in the history
  • Loading branch information
mannodermaus committed Apr 9, 2024
1 parent d1642aa commit ed63e4e
Show file tree
Hide file tree
Showing 14 changed files with 121 additions and 138 deletions.
2 changes: 2 additions & 0 deletions plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Change Log
- JUnit 5.10.2
- Raise minimum supported versions for AGP and Gradle to 8.0.x and 8.0, respectively
- Allow overriding the version of the instrumentation libraries applied with the plugin
- Update Jacoco & instrumentation test DSLs of the plugin to use Gradle Providers for their input parameters (e.g. `instrumentationTests.enabled.set(true)` instead of `instrumentationTests.enabled = true`)
- Removed deprecated `integrityCheckEnabled` flag from the plugin DSL's instrumentation test options

## 1.10.0.0 (2023-11-05)
- JUnit 5.10.0
Expand Down
28 changes: 8 additions & 20 deletions plugin/android-junit5/api/android-junit5.api
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,26 @@ public abstract class de/mannodermaus/gradle/plugins/junit5/dsl/FiltersExtension

public abstract class de/mannodermaus/gradle/plugins/junit5/dsl/InstrumentationTestOptions {
public fun <init> ()V
public final fun enabled (Z)V
public final fun getEnabled ()Z
public final fun getIntegrityCheckEnabled ()Z
public final fun integrityCheckEnabled (Z)V
public final fun setEnabled (Z)V
public final fun setIntegrityCheckEnabled (Z)V
public abstract fun getEnabled ()Lorg/gradle/api/provider/Property;
public abstract fun getIncludeExtensions ()Lorg/gradle/api/provider/Property;
public abstract fun getVersion ()Lorg/gradle/api/provider/Property;
}

public abstract class de/mannodermaus/gradle/plugins/junit5/dsl/JacocoOptions {
public fun <init> (Lorg/gradle/api/model/ObjectFactory;)V
public final fun excludedClasses ([Ljava/lang/String;)V
public final fun getCsv ()Lde/mannodermaus/gradle/plugins/junit5/dsl/JacocoOptions$Report;
public final fun getExcludedClasses ()Ljava/util/List;
public abstract fun getExcludedClasses ()Lorg/gradle/api/provider/ListProperty;
public final fun getHtml ()Lde/mannodermaus/gradle/plugins/junit5/dsl/JacocoOptions$Report;
public final fun getOnlyGenerateTasksForVariants ()Ljava/util/Set;
public final fun getTaskGenerationEnabled ()Z
public abstract fun getOnlyGenerateTasksForVariants ()Lorg/gradle/api/provider/SetProperty;
public abstract fun getTaskGenerationEnabled ()Lorg/gradle/api/provider/Property;
public final fun getXml ()Lde/mannodermaus/gradle/plugins/junit5/dsl/JacocoOptions$Report;
public final fun onlyGenerateTasksForVariants ([Ljava/lang/String;)V
public final fun setExcludedClasses (Ljava/util/List;)V
public final fun setTaskGenerationEnabled (Z)V
public final fun taskGenerationEnabled (Z)V
}

public abstract class de/mannodermaus/gradle/plugins/junit5/dsl/JacocoOptions$Report {
public fun <init> ()V
public final fun destination (Ljava/io/File;)V
public final fun enabled (Z)V
public final fun getDestination ()Ljava/io/File;
public final fun getEnabled ()Z
public abstract fun getDestination ()Lorg/gradle/api/file/RegularFileProperty;
public abstract fun getEnabled ()Lorg/gradle/api/provider/Property;
public final fun invoke (Lkotlin/jvm/functions/Function1;)V
public final fun setDestination (Ljava/io/File;)V
public final fun setEnabled (Z)V
}

public abstract class de/mannodermaus/gradle/plugins/junit5/tasks/AndroidJUnit5JacocoReport : org/gradle/testing/jacoco/tasks/JacocoReport {
Expand Down
1 change: 1 addition & 0 deletions plugin/android-junit5/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ val versionClassTask = tasks.register<Copy>("createVersionClass") {
"tokens" to mapOf(
"INSTRUMENTATION_GROUP" to Artifacts.Instrumentation.groupId,
"INSTRUMENTATION_CORE" to Artifacts.Instrumentation.Core.artifactId,
"INSTRUMENTATION_EXTENSIONS" to Artifacts.Instrumentation.Extensions.artifactId,
"INSTRUMENTATION_RUNNER" to Artifacts.Instrumentation.Runner.artifactId,
"INSTRUMENTATION_VERSION" to Artifacts.Instrumentation.latestStableVersion,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.mannodermaus.gradle.plugins.junit5.dsl

import de.mannodermaus.Libraries
import de.mannodermaus.gradle.plugins.junit5.internal.config.EXTENSION_NAME
import groovy.lang.Closure
import groovy.lang.GroovyObjectSupport
Expand All @@ -9,14 +10,15 @@ import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.MapProperty
import org.gradle.api.tasks.Input
import org.junit.platform.commons.util.Preconditions
import java.io.File
import javax.inject.Inject

public abstract class AndroidJUnitPlatformExtension @Inject constructor(
private val objects: ObjectFactory
) : GroovyObjectSupport() {

internal companion object {
fun Project.createJUnit5Extension() =
fun Project.createJUnit5Extension(): AndroidJUnitPlatformExtension =
extensions.create(EXTENSION_NAME, AndroidJUnitPlatformExtension::class.java)
}

Expand Down Expand Up @@ -85,14 +87,18 @@ public abstract class AndroidJUnitPlatformExtension @Inject constructor(

return null
}

/* Android Instrumentation Test support */

/**
* Options for controlling instrumentation test execution with JUnit 5
*/
public val instrumentationTests: InstrumentationTestOptions =
objects.newInstance(InstrumentationTestOptions::class.java)
objects.newInstance(InstrumentationTestOptions::class.java).apply {
enabled.convention(true)
version.convention(Libraries.instrumentationVersion)
includeExtensions.convention(false)
}

public fun instrumentationTests(action: Action<InstrumentationTestOptions>) {
action.execute(instrumentationTests)
Expand All @@ -103,8 +109,19 @@ public abstract class AndroidJUnitPlatformExtension @Inject constructor(
/**
* Options for controlling Jacoco reporting
*/
@Suppress("CAST_NEVER_SUCCEEDS")
public val jacocoOptions: JacocoOptions =
objects.newInstance(JacocoOptions::class.java)
objects.newInstance(JacocoOptions::class.java).apply {
taskGenerationEnabled.convention(true)
onlyGenerateTasksForVariants.convention(emptySet())
excludedClasses.set(listOf("**/R.class", "**/R$*.class", "**/BuildConfig.*"))
html.enabled.convention(true)
html.destination.set(null as? File)
csv.enabled.convention(true)
csv.destination.set(null as? File)
xml.enabled.convention(true)
xml.destination.set(null as? File)
}

public fun jacocoOptions(action: Action<JacocoOptions>) {
action.execute(jacocoOptions)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.mannodermaus.gradle.plugins.junit5.dsl

import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input

/**
Expand All @@ -12,42 +13,18 @@ public abstract class InstrumentationTestOptions {
* when junit-jupiter-api is added as an androidTestImplementation dependency.
*/
@get:Input
public var enabled: Boolean = true
public abstract val enabled: Property<Boolean>

/**
* Whether to configure JUnit 5 instrumentation tests automatically
* when junit-jupiter-api is added as an androidTestImplementation dependency.
*/
public fun enabled(state: Boolean) {
this.enabled = state
}

/**
* Whether to check if the instrumentation tests
* are correctly set up. If this is disabled, the plugin
* won't raise an error during evaluation if the instrumentation
* libraries or the test runner are missing.
* The version of the instrumentation libraries to autoconfigure.
*/
@get:Input
@Deprecated(
message = "Starting with android-junit5 1.9.0.0, instrumentation tests are automatically configured correctly " +
"when the junit-jupiter-api dependency is added as an androidTestImplementation dependency; " +
"this flag no longer does anything and can be safely removed. " +
"If you don't want to automatically configure JUnit 5 instrumentation tests, use the `enabled` flag."
)
public var integrityCheckEnabled: Boolean = false
public abstract val version: Property<String>

/**
* Whether to check if the instrumentation tests
* are correctly set up. If this is disabled, the plugin
* won't raise an error during evaluation if the instrumentation
* libraries or the test runner are missing.
* Whether to include a dependency on the android-test-extensions library
* on top of the main instrumentation artifacts.
*/
@Deprecated(
message = "Starting with android-junit5 1.9.0.0, instrumentation tests are automatically configured correctly " +
"when the junit-jupiter-api dependency is added as an androidTestImplementation dependency; " +
"this flag no longer does anything and can be safely removed. " +
"If you don't want to automatically configure JUnit 5 instrumentation tests, use the `enabled` flag."
)
public fun integrityCheckEnabled(state: Boolean) {}
@get:Input
public abstract val includeExtensions: Property<Boolean>
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package de.mannodermaus.gradle.plugins.junit5.dsl

import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.Input
import java.io.File
import org.gradle.internal.enterprise.test.FileProperty
import javax.inject.Inject

/**
Expand All @@ -16,27 +20,17 @@ public abstract class JacocoOptions @Inject constructor(
* Whether to enable Jacoco task integration
*/
@get:Input
public var taskGenerationEnabled: Boolean = true

public fun taskGenerationEnabled(state: Boolean) {
this.taskGenerationEnabled = state
}

private val _onlyGenerateTasksForVariants = mutableSetOf<String>()

@get:Input
public val onlyGenerateTasksForVariants: Set<String>
get() = _onlyGenerateTasksForVariants
public abstract val taskGenerationEnabled: Property<Boolean>

/**
* Filter the generated Jacoco tasks,
* so that only the given build variants are provided with a companion task.
* Make sure to add the full product flavor name if necessary
* (i.e. "paidDebug" if you use a "paid" product flavor and the "debug" build type)
* (i.e. "paidDebug" if you use a "paid" product flavor and the "debug" build type).
* By default, this set is empty, meaning that tasks are generated for all variants.
*/
public fun onlyGenerateTasksForVariants(vararg variants: String) {
_onlyGenerateTasksForVariants.addAll(variants)
}
@get:Input
public abstract val onlyGenerateTasksForVariants: SetProperty<String>

/**
* Options for controlling the HTML Report generated by Jacoco
Expand All @@ -57,12 +51,8 @@ public abstract class JacocoOptions @Inject constructor(
* List of class name patterns that should be excluded from being processed by Jacoco.
* By default, this will exclude R.class & BuildConfig.class
*/
public var excludedClasses: MutableList<String> =
mutableListOf("**/R.class", "**/R$*.class", "**/BuildConfig.*")

public fun excludedClasses(vararg classes: String) {
excludedClasses.addAll(classes)
}
@get:Input
public abstract val excludedClasses: ListProperty<String>

public abstract class Report {

Expand All @@ -71,23 +61,17 @@ public abstract class JacocoOptions @Inject constructor(
}

/**
* Whether or not this report should be generated
* Whether this report should be generated
*/
public var enabled: Boolean = true

public fun enabled(state: Boolean) {
this.enabled = state
}
@get:Input
public abstract val enabled: Property<Boolean>

/**
* Name of the file to be generated; note that
* due to the variant-aware nature of the plugin,
* each variant will be assigned a distinct folder if necessary
*/
public var destination: File? = null

public fun destination(file: File?) {
this.destination = file
}
@get:Input
public abstract val destination: RegularFileProperty
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private fun prepareUnitTests(project: Project, android: AndroidExtension) {
}

private fun AndroidJUnitPlatformExtension.prepareInstrumentationTests(project: Project, android: AndroidExtension) {
if (!instrumentationTests.enabled) return
if (!instrumentationTests.enabled.get()) return

// Automatically configure instrumentation tests when JUnit 5 is detected in that configuration
val hasJupiterApi = project.configurations
Expand All @@ -124,14 +124,23 @@ private fun AndroidJUnitPlatformExtension.prepareInstrumentationTests(project: P
.joinToString(",")
}

val version = instrumentationTests.version.get()

project.dependencies.add(
"androidTestImplementation",
Libraries.instrumentationCore
"${Libraries.instrumentationCore}:$version"
)
project.dependencies.add(
"androidTestRuntimeOnly",
Libraries.instrumentationRunner
"${Libraries.instrumentationRunner}:$version"
)

if (instrumentationTests.includeExtensions.get()) {
project.dependencies.add(
"androidTestImplementation",
"${Libraries.instrumentationExtensions}:$version"
)
}
}

private fun AndroidJUnitPlatformExtension.configureUnitTests(project: Project, variant: Variant) {
Expand Down Expand Up @@ -163,11 +172,11 @@ private fun AndroidJUnitPlatformExtension.configureJacoco(
variant: Variant
) {
// Connect a Code Coverage report to it if Jacoco is enabled
if (jacocoOptions.taskGenerationEnabled && config.hasJacocoPlugin) {
if (jacocoOptions.taskGenerationEnabled.get() && config.hasJacocoPlugin) {
val taskName = variant.getTaskName(prefix = UNIT_TEST_PREFIX, suffix = UNIT_TEST_SUFFIX)
project.tasks.namedOrNull<Test>(taskName)?.get()?.let { testTask ->
// Create a Jacoco friend task
val enabledVariants = jacocoOptions.onlyGenerateTasksForVariants
val enabledVariants = jacocoOptions.onlyGenerateTasksForVariants.get()
if (enabledVariants.isEmpty() || variant.name in enabledVariants) {
val directoryProviders = config.directoryProvidersOf(variant)
val registered = AndroidJUnit5JacocoReport.register(project, variant, testTask, directoryProviders)
Expand All @@ -184,7 +193,7 @@ private fun AndroidJUnitPlatformExtension.configureInstrumentationTests(
config: PluginConfig,
variant: Variant,
) {
if (!instrumentationTests.enabled) return
if (!instrumentationTests.enabled.get()) return

config.instrumentationTestVariantOf(variant)?.let { instrumentationTestVariant ->
AndroidJUnit5WriteFilters.register(project, variant, instrumentationTestVariant)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public abstract class AndroidJUnit5JacocoReport : JacocoReport() {

allReports.forEach { (from, to) ->
to.required.set(from.enabled)
from.destination?.let { to.outputLocationFile.set(it) }
to.outputLocationFile.fileProvider(from.destination.asFile)
}

// Task-level Configuration
Expand All @@ -110,7 +110,7 @@ public abstract class AndroidJUnit5JacocoReport : JacocoReport() {
// Apply exclusion rules to both class & source directories for Jacoco,
// using the sum of all DirectoryProviders' outputs as a foundation:
reportTask.classDirectories.setFrom(
directoryProviders.mainClassDirectories().toFileCollectionExcluding(junit5Jacoco.excludedClasses)
directoryProviders.mainClassDirectories().toFileCollectionExcluding(junit5Jacoco.excludedClasses.get())
)
reportTask.sourceDirectories.setFrom(
directoryProviders.mainSourceDirectories()
Expand Down
6 changes: 4 additions & 2 deletions plugin/android-junit5/src/main/templates/Libraries.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package de.mannodermaus

internal object Libraries {
const val instrumentationCore = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_CORE@:@INSTRUMENTATION_VERSION@"
const val instrumentationRunner = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_RUNNER@:@INSTRUMENTATION_VERSION@"
const val instrumentationVersion = "@INSTRUMENTATION_VERSION@"
const val instrumentationCore = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_CORE@"
const val instrumentationExtensions = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_EXTENSIONS@"
const val instrumentationRunner = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_RUNNER@"
}
Loading

0 comments on commit ed63e4e

Please sign in to comment.