{
20 |
21 | override fun apply(project: Project) {
22 | requireGradle(
23 | actual = GradleVersion.current(),
24 | required = MIN_REQUIRED_GRADLE_VERSION
25 | ) {
26 | "android-junit5 plugin requires Gradle $MIN_REQUIRED_GRADLE_VERSION or later"
27 | }
28 |
29 | project.whenAndroidPluginAdded { plugin ->
30 | PluginConfig.find(project, plugin)?.let { config ->
31 | requireAgp(
32 | actual = config.currentAgpVersion,
33 | required = MIN_REQUIRED_AGP_VERSION
34 | ) {
35 | "android-junit5 plugin requires Android Gradle Plugin $MIN_REQUIRED_AGP_VERSION or later"
36 | }
37 |
38 | val extension = project.createJUnit5Extension()
39 | configureJUnit5(project, config, extension)
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/FiltersExtension.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.dsl
2 |
3 | import de.mannodermaus.gradle.plugins.junit5.internal.utils.IncludeExcludeContainer
4 |
5 | public abstract class FiltersExtension {
6 |
7 | /**
8 | * Class name patterns in the form of regular expressions for
9 | * classes that should be included in the test plan.
10 | *
11 | * The patterns are combined using OR semantics, i.e. if the fully
12 | * qualified name of a class matches against at least one of the patterns,
13 | * the class will be included in the test plan.
14 | */
15 | internal val patterns = IncludeExcludeContainer()
16 |
17 | /**
18 | * Add a pattern to the list of included patterns
19 | */
20 | public fun includePattern(pattern: String) {
21 | includePatterns(pattern)
22 | }
23 |
24 | /**
25 | * Add patterns to the list of included patterns
26 | */
27 | public fun includePatterns(vararg patterns: String) {
28 | this.patterns.include(*patterns)
29 | }
30 |
31 | /**
32 | * Add a pattern to the list of excluded patterns
33 | */
34 | public fun excludePattern(pattern: String) {
35 | excludePatterns(pattern)
36 | }
37 |
38 | /**
39 | * Add patterns to the list of excluded patterns
40 | */
41 | public fun excludePatterns(vararg patterns: String) {
42 | this.patterns.exclude(*patterns)
43 | }
44 |
45 | /**
46 | * Included & Excluded JUnit 5 tags.
47 | */
48 | internal val tags = IncludeExcludeContainer()
49 |
50 | /**
51 | * Add tags to the list of included tags
52 | */
53 | public fun includeTags(vararg tags: String) {
54 | this.tags.include(*tags)
55 | }
56 |
57 | /**
58 | * Add tags to the list of excluded tags
59 | */
60 | public fun excludeTags(vararg tags: String) {
61 | this.tags.exclude(*tags)
62 | }
63 |
64 | /**
65 | * Included & Excluded JUnit 5 engines.
66 | */
67 | internal val engines = IncludeExcludeContainer()
68 |
69 | /**
70 | * Add engines to the list of included engines
71 | */
72 | public fun includeEngines(vararg engines: String) {
73 | this.engines.include(*engines)
74 | }
75 |
76 | /**
77 | * Add engines to the list of excluded engines
78 | */
79 | public fun excludeEngines(vararg engines: String) {
80 | this.engines.exclude(*engines)
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/dsl/InstrumentationTestOptions.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.dsl
2 |
3 | import org.gradle.api.provider.Property
4 | import org.gradle.api.tasks.Input
5 |
6 | /**
7 | * Options for controlling instrumentation test execution
8 | */
9 | public abstract class InstrumentationTestOptions {
10 |
11 | /**
12 | * Whether to configure JUnit 5 instrumentation tests automatically
13 | * when junit-jupiter-api is added as an androidTestImplementation dependency.
14 | */
15 | @get:Input
16 | public abstract val enabled: Property
17 |
18 | /**
19 | * The version of the instrumentation libraries to autoconfigure.
20 | */
21 | @get:Input
22 | public abstract val version: Property
23 |
24 | /**
25 | * Whether to include a dependency on the android-test-extensions library
26 | * on top of the main instrumentation artifacts.
27 | */
28 | @get:Input
29 | public abstract val includeExtensions: Property
30 |
31 | /**
32 | * Whether to use configuration parameters configured via the plugin DSL
33 | * for instrumentation tests, too.
34 | */
35 | @get:Input
36 | public abstract val useConfigurationParameters: Property
37 | }
38 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/config/Constants.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("unused")
2 |
3 | package de.mannodermaus.gradle.plugins.junit5.internal.config
4 |
5 | import com.android.build.api.AndroidPluginVersion
6 | import org.gradle.util.GradleVersion
7 |
8 | // When updating this, check buildSrc/Tasks.kt and update it there, too
9 | internal val MIN_REQUIRED_GRADLE_VERSION = GradleVersion.version("8.2")
10 | internal val MIN_REQUIRED_AGP_VERSION = AndroidPluginVersion(8, 2)
11 |
12 | internal const val EXTENSION_NAME = "junitPlatform"
13 |
14 | internal const val ANDROID_JUNIT5_RUNNER_BUILDER_CLASS = "de.mannodermaus.junit5.AndroidJUnit5Builder"
15 | internal const val INSTRUMENTATION_RUNNER_LIBRARY_GROUP = "de.mannodermaus.junit5"
16 | internal const val INSTRUMENTATION_RUNNER_LIBRARY_ARTIFACT = "android-test-runner"
17 |
18 | // Android doesn't allow '.' in resource file names,
19 | // saying that it is not a valid file-based resource name character:
20 | // File-based resource names must contain only lowercase a-z, 0-9, or underscore
21 | internal const val INSTRUMENTATION_FILTER_RES_FILE_NAME = "de_mannodermaus_junit5_filters"
22 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/config/JUnit5TaskConfig.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnstableApiUsage")
2 |
3 | package de.mannodermaus.gradle.plugins.junit5.internal.config
4 |
5 | import com.android.build.api.variant.Variant
6 | import de.mannodermaus.gradle.plugins.junit5.dsl.AndroidJUnitPlatformExtension
7 | import de.mannodermaus.gradle.plugins.junit5.dsl.FiltersExtension
8 | import de.mannodermaus.gradle.plugins.junit5.internal.utils.IncludeExcludeContainer
9 |
10 | internal class JUnit5TaskConfig(
11 | private val variant: Variant,
12 | private val extension: AndroidJUnitPlatformExtension,
13 | ) {
14 |
15 | // There is a distinct application order, which determines how values are merged and overwritten.
16 | // From top to bottom, this list goes as follows (values on the bottom will override conflicting
17 | // entries specified above them):
18 | // 1) Default ("filters")
19 | // 2) Build-type-specific (e.g. "debug")
20 | // 3) Flavor-specific (e.g. "free")
21 | // 4) Variant-specific (e.g. "freeDebug")
22 | private fun collect(func: FiltersExtension.() -> IncludeExcludeContainer): IncludeExcludeContainer {
23 | // 1)
24 | val layer1 = filtersOf(null, func)
25 | // 2)
26 | val layer2 = layer1 + filtersOf(variant.buildType, func)
27 | // 3)
28 | val layer3 = variant.productFlavors
29 | .map { filtersOf(it.second, func) }
30 | .fold(layer2) { a, b -> a + b }
31 | // 4)
32 | return layer3 + filtersOf(variant.name, func)
33 | }
34 |
35 | private inline fun filtersOf(
36 | qualifier: String?,
37 | func: FiltersExtension.() -> IncludeExcludeContainer
38 | ): IncludeExcludeContainer = extension.filters(qualifier).run { func() }
39 |
40 | val combinedIncludePatterns = this.collect { patterns }.include.toTypedArray()
41 | val combinedExcludePatterns = this.collect { patterns }.exclude.toTypedArray()
42 | val combinedIncludeTags = this.collect { tags }.include.toTypedArray()
43 | val combinedExcludeTags = this.collect { tags }.exclude.toTypedArray()
44 | val combinedIncludeEngines = this.collect { engines }.include.toTypedArray()
45 | val combinedExcludeEngines = this.collect { engines }.exclude.toTypedArray()
46 | }
47 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/BaseVariantExt.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("DEPRECATION")
2 |
3 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
4 |
5 | import com.android.build.gradle.api.BaseVariant
6 | import com.android.build.gradle.api.UnitTestVariant
7 | import com.android.build.gradle.internal.api.TestedVariant
8 |
9 | internal val BaseVariant.unitTestVariant: UnitTestVariant
10 | get() {
11 | if (this !is TestedVariant) {
12 | throw IllegalArgumentException("Argument is not TestedVariant: $this")
13 | }
14 |
15 | return requireNotNull(this.unitTestVariant)
16 | }
17 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/ConfigurableReportExt.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
2 |
3 | import org.gradle.api.file.FileSystemLocationProperty
4 | import org.gradle.api.reporting.ConfigurableReport
5 | import java.lang.reflect.Method
6 |
7 | internal val ConfigurableReport.outputLocationFile: FileSystemLocationProperty<*>
8 | get() = try {
9 | outputLocation as FileSystemLocationProperty<*>
10 | } catch (e: NoSuchMethodError) {
11 | // Observed before Gradle 8.x
12 | getOutputLocationMethod.invoke(this) as FileSystemLocationProperty<*>
13 | }
14 |
15 | private val ConfigurableReport.getOutputLocationMethod: Method
16 | get() = javaClass.declaredMethods.first { method ->
17 | method.name == "getOutputLocation" && method.returnType == FileSystemLocationProperty::class.java
18 | }
19 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/ExtensionAwareExt.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
2 |
3 | import org.gradle.api.plugins.ExtensionAware
4 |
5 | @Suppress("UNCHECKED_CAST")
6 | internal fun ExtensionAware.extensionByName(name: String): T {
7 | return this.extensions.getByName(name) as T
8 | }
9 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/LoggerExt.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
2 |
3 | import org.gradle.api.logging.LogLevel
4 | import org.gradle.api.logging.Logger
5 |
6 | internal fun Logger.agpLog(level: LogLevel, message: String) {
7 | val pair: Pair Unit> = when (level) {
8 | LogLevel.ERROR -> "error" to { s -> error(s) }
9 | LogLevel.WARN -> "warning" to { s -> warn(s) }
10 | LogLevel.INFO -> "info" to { s -> info(s) }
11 | else -> "debug" to { s -> debug(s) }
12 | }
13 | val (kind, log) = pair
14 | log("""AGBPI: {"kind": "$kind","text":"$message"}""")
15 | }
16 |
17 | internal fun Logger.junit5Info(text: String) {
18 | info("[android-junit5]: $text")
19 | }
20 |
21 | internal fun Logger.junit5Warn(text: String) {
22 | warn("[android-junit5]: $text")
23 | }
24 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/MapExt.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
2 |
3 | internal fun Map.getAsList(key: String, delimiter: String = ","): List =
4 | this[key]?.split(delimiter) ?: emptyList()
5 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/ProjectExt.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
2 |
3 | import com.android.build.gradle.BaseExtension
4 | import com.android.build.gradle.BasePlugin
5 | import de.mannodermaus.gradle.plugins.junit5.dsl.AndroidJUnitPlatformExtension
6 | import de.mannodermaus.gradle.plugins.junit5.internal.config.EXTENSION_NAME
7 | import org.gradle.api.Project
8 | import org.gradle.api.artifacts.Dependency
9 | import java.util.concurrent.atomic.AtomicBoolean
10 | import kotlin.contracts.ExperimentalContracts
11 | import kotlin.contracts.InvocationKind
12 | import kotlin.contracts.contract
13 |
14 | internal val Project.junitPlatform
15 | get() = extensionByName(EXTENSION_NAME)
16 |
17 | internal val Project.android
18 | get() = extensionByName("android")
19 |
20 | @OptIn(ExperimentalContracts::class)
21 | internal fun Project.whenAndroidPluginAdded(block: (BasePlugin) -> Unit) {
22 | contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
23 |
24 | val configured = AtomicBoolean(false)
25 | plugins.withType(BasePlugin::class.java) { plugin ->
26 | // Prevent duplicate configuration
27 | if (!configured.getAndSet(true)) {
28 | block(plugin)
29 | }
30 | }
31 |
32 | afterEvaluate {
33 | // If no Android plugin was applied by this point, fail
34 | if (!configured.get()) {
35 | throw IllegalStateException("An Android plugin must be applied in order for android-junit5 to work correctly!")
36 | }
37 | }
38 | }
39 |
40 | internal fun Project.hasDependency(configurationName: String, matching: (Dependency) -> Boolean): Boolean {
41 | val configuration = project.configurations.getByName(configurationName)
42 |
43 | return configuration.dependencies.any(matching)
44 | }
45 |
46 | internal fun Project.usesJUnitJupiterIn(configurationName: String): Boolean {
47 | return project.hasDependency(configurationName) {
48 | it.group == "org.junit.jupiter" && it.name == "junit-jupiter-api"
49 | }
50 | }
51 |
52 | internal fun Project.usesComposeIn(configurationName: String): Boolean {
53 | return project.hasDependency(configurationName) {
54 | it.group?.startsWith("androidx.compose") ?: false
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/StringExt.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
2 |
3 | import java.util.*
4 |
5 | /**
6 | * Replacement for Kotlin's deprecated [capitalize] method on strings
7 | */
8 | internal fun String.capitalized() = replaceFirstChar {
9 | if (it.isLowerCase()) {
10 | it.titlecase(Locale.getDefault())
11 | } else {
12 | it.toString()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/TaskContainerExt.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
2 |
3 | import org.gradle.api.Task
4 | import org.gradle.api.UnknownTaskException
5 | import org.gradle.api.tasks.TaskContainer
6 | import org.gradle.api.tasks.TaskProvider
7 |
8 | internal inline fun TaskContainer.namedOrNull(name: String): TaskProvider? =
9 | try {
10 | named(name, T::class.java)
11 | } catch (e: UnknownTaskException) {
12 | null
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/extensions/VariantExt.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.extensions
2 |
3 | import com.android.build.api.variant.AndroidTest
4 | import com.android.build.api.variant.HasAndroidTest
5 | import com.android.build.api.variant.Variant
6 |
7 | internal fun Variant.getTaskName(prefix: String = "", suffix: String = ""): String {
8 | // At least one value must be provided
9 | require(prefix.isNotEmpty() || suffix.isNotEmpty())
10 |
11 | return StringBuilder().apply {
12 | append(prefix)
13 | append(
14 | if (isEmpty()) {
15 | name
16 | } else {
17 | name.capitalized()
18 | }
19 | )
20 | append(suffix.capitalized())
21 | }.toString()
22 | }
23 |
24 | internal val Variant.instrumentationTestVariant: AndroidTest?
25 | get() = (this as? HasAndroidTest)?.androidTest
26 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/providers/DirectoryProvider.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.providers
2 |
3 | import java.io.File
4 |
5 | /**
6 | * General interface for providers of class & source directories
7 | * towards the construction of JUnit 5 tasks and its companions.
8 | *
9 | * Registered through the plugin, integrations with different languages
10 | * and frameworks can provide their own collection of directories.
11 | * The most prominent example consists of the opt-in Kotlin support,
12 | * which provides the "/kotlin" directories to each JUnit 5 task,
13 | * allowing Kotlin classes to be used for test detection & execution.
14 | */
15 | internal interface DirectoryProvider {
16 | /**
17 | * The locations of compiled class files
18 | */
19 | fun mainClassDirectories(): Set
20 |
21 | /**
22 | * The locations of compiled test class files
23 | */
24 | fun testClassDirectories(): Set
25 |
26 | /**
27 | * The locations of source files
28 | */
29 | fun mainSourceDirectories(): Set
30 |
31 | /**
32 | * The locations of test source files
33 | */
34 | fun testSourceDirectories(): Set
35 | }
36 |
37 | /* Extensions */
38 |
39 | internal fun Iterable.mainClassDirectories() = flatMap { it.mainClassDirectories() }.distinct()
40 | internal fun Iterable.mainSourceDirectories() = flatMap { it.mainSourceDirectories() }.distinct()
41 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/providers/JavaDirectoryProvider.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("DEPRECATION")
2 |
3 | package de.mannodermaus.gradle.plugins.junit5.internal.providers
4 |
5 | import com.android.build.gradle.api.BaseVariant
6 | import de.mannodermaus.gradle.plugins.junit5.internal.extensions.unitTestVariant
7 |
8 | /**
9 | * Default Provider implementation for Java-based test root directories.
10 | * This will look up the main & test root directories
11 | * of the variant connected to a given JUnit 5 task.
12 | */
13 | internal class JavaDirectoryProvider(private val variant: BaseVariant) : DirectoryProvider {
14 |
15 | override fun mainSourceDirectories() = sourceFoldersOf(variant)
16 | override fun testSourceDirectories() = sourceFoldersOf(variant.unitTestVariant)
17 | override fun mainClassDirectories() = classFoldersOf(variant)
18 | override fun testClassDirectories() = classFoldersOf(variant.unitTestVariant)
19 |
20 | /* Private */
21 |
22 | private fun sourceFoldersOf(variant: BaseVariant) =
23 | variant.sourceSets
24 | .flatMap { it.javaDirectories }
25 | .toSet()
26 |
27 | private fun classFoldersOf(variant: BaseVariant) =
28 | setOfNotNull(variant.javaCompileProvider.map { it.destinationDirectory.asFile }.get().orNull)
29 | }
30 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/providers/KotlinDirectoryProvider.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("DEPRECATION")
2 |
3 | package de.mannodermaus.gradle.plugins.junit5.internal.providers
4 |
5 | import com.android.build.gradle.api.BaseVariant
6 | import de.mannodermaus.gradle.plugins.junit5.internal.extensions.agpLog
7 | import de.mannodermaus.gradle.plugins.junit5.internal.extensions.unitTestVariant
8 | import org.gradle.api.Project
9 | import org.gradle.api.logging.LogLevel.WARN
10 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
11 | import java.io.File
12 |
13 | /* Types */
14 |
15 | /**
16 | * Provides test root directories for Kotlin sources,
17 | * with which a JUnit 5 Task can be enhanced.
18 | */
19 | internal class KotlinDirectoryProvider(
20 | private val project: Project,
21 | private val variant: BaseVariant
22 | ) : DirectoryProvider {
23 |
24 | override fun mainSourceDirectories() = sourceFoldersOf(variant)
25 | override fun testSourceDirectories() = sourceFoldersOf(variant.unitTestVariant)
26 | override fun mainClassDirectories() = classFoldersOf(variant)
27 | override fun testClassDirectories() = classFoldersOf(variant.unitTestVariant)
28 |
29 | /* Private */
30 |
31 | private fun sourceFoldersOf(variant: BaseVariant) =
32 | variant.sourceSets
33 | .flatMap { it.javaDirectories + it.kotlinDirectories }
34 | .toSet()
35 |
36 | private fun classFoldersOf(variant: BaseVariant): Set {
37 | val kotlinTask = project.tasks.findByName(variant.kotlinTaskName)
38 | return if (kotlinTask != null) {
39 | // Read folder directly from the Kotlin task
40 | setOfNotNull((kotlinTask as KotlinCompile).destinationDirectory.asFile.orNull)
41 | } else {
42 | // If the Kotlin plugin is applied _after_ JUnit 5 in the build file,
43 | // fall back to the expected path… However, make sure to log a warning to users!
44 | project.logger.agpLog(
45 | WARN,
46 | "The kotlin-android plugin is currently applied after android-junit5! To guarantee full compatibility, please declare it above the JUnit 5 plugin."
47 | )
48 | setOf(File(project.buildDir, "tmp/kotlin-classes/${variant.name}"))
49 | }
50 | }
51 | }
52 |
53 | /* Extensions */
54 |
55 | private val BaseVariant.kotlinTaskName
56 | get() = "compile${this.name.capitalize()}Kotlin"
57 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/utils/Functions.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.utils
2 |
3 | import com.android.build.api.AndroidPluginVersion
4 | import org.gradle.api.GradleException
5 | import org.gradle.util.GradleVersion
6 |
7 | internal fun excludedPackagingOptions() = listOf(
8 | "/META-INF/LICENSE.md",
9 | "/META-INF/LICENSE-notice.md"
10 | )
11 |
12 | internal fun requireGradle(actual: GradleVersion, required: GradleVersion, message: () -> String) {
13 | require(actual >= required) {
14 | throw GradleException(message())
15 | }
16 | }
17 |
18 | internal fun requireAgp(actual: AndroidPluginVersion, required: AndroidPluginVersion, message: () -> String) {
19 | require(actual >= required) {
20 | throw GradleException(message())
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/utils/IncludeExcludeContainer.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.internal.utils
2 |
3 | @Suppress("ConvertArgumentToSet")
4 | internal class IncludeExcludeContainer {
5 |
6 | private val _include = mutableSetOf()
7 | private val _exclude = mutableSetOf()
8 |
9 | val include
10 | get() = _include.toSet()
11 |
12 | fun include(vararg items: String) = this.apply {
13 | this._include.addAll(items)
14 | this._exclude.removeAll(items)
15 | }
16 |
17 | val exclude
18 | get() = _exclude.toSet()
19 |
20 | fun exclude(vararg items: String) = this.apply {
21 | this._exclude.addAll(items)
22 | this._include.removeAll(items)
23 | }
24 |
25 | fun isEmpty() =
26 | _include.isEmpty() && _exclude.isEmpty()
27 |
28 | operator fun plus(other: IncludeExcludeContainer): IncludeExcludeContainer {
29 | // Fast path, where nothing needs to be merged
30 | if (this.isEmpty()) return other
31 | if (other.isEmpty()) return this
32 |
33 | // Slow path, where rules need to be merged
34 | val result = IncludeExcludeContainer()
35 |
36 | result._include.addAll(this.include)
37 | result._include.addAll(other.include)
38 | result._include.removeAll(other.exclude)
39 |
40 | result._exclude.addAll(this.exclude)
41 | result._exclude.addAll(other.exclude)
42 | result._exclude.removeAll(other.include)
43 |
44 | return result
45 | }
46 |
47 | override fun toString(): String {
48 | return "${super.toString()}(include=$_include, exclude=$_exclude)"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/main/templates/Libraries.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus
2 |
3 | internal object Libraries {
4 | const val instrumentationVersion = "@INSTRUMENTATION_VERSION@"
5 | const val instrumentationCompose = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_COMPOSE@"
6 | const val instrumentationCore = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_CORE@"
7 | const val instrumentationExtensions = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_EXTENSIONS@"
8 | const val instrumentationRunner = "@INSTRUMENTATION_GROUP@:@INSTRUMENTATION_RUNNER@"
9 |
10 | const val junitPlatformLauncher = "@JUNIT_PLATFORM_LAUNCHER@"
11 | }
12 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/VersionCheckerTests.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5
2 |
3 | import com.android.build.api.AndroidPluginVersion
4 | import com.google.common.truth.Truth.assertThat
5 | import de.mannodermaus.gradle.plugins.junit5.internal.config.MIN_REQUIRED_AGP_VERSION
6 | import de.mannodermaus.gradle.plugins.junit5.internal.utils.requireAgp
7 | import org.junit.jupiter.params.ParameterizedTest
8 | import org.junit.jupiter.params.provider.CsvSource
9 |
10 | /**
11 | * Created by Marcel Schnelle on 2018/06/19.
12 | *
13 | * Sanity checks for the external Semver library, used to determine compatibility of the AGP.
14 | */
15 | class VersionCheckerTests {
16 |
17 | @CsvSource(
18 | "7.0.0-alpha1, false",
19 | "7.0.0-alpha1, false",
20 | "7.0.0-beta1, false",
21 | "7.0.0-rc1, false",
22 | "7.0.0, false",
23 | "8.0.0-beta1, false",
24 | "8.0.0, false",
25 | "8.0.1, false",
26 | "8.0.1-alpha1, false",
27 | "8.1.0, false",
28 | "8.1.0-beta1, false",
29 | "8.2.0, true",
30 | "8.3.0-rc1, true",
31 | "8.4.0-alpha5, true",
32 | "8.10.1-alpha11, true",
33 | "8.10.0, true",
34 | "8.11.0-beta1, true",
35 | "8.11.0, true",
36 | )
37 | @ParameterizedTest
38 | fun `check AGP compatibility`(version: String, compatible: Boolean) {
39 | val pluginVersion = version.toAndroidPluginVersion()
40 | assertThat(versionCompatible(pluginVersion)).isEqualTo(compatible)
41 | }
42 |
43 | private fun versionCompatible(version: AndroidPluginVersion): Boolean {
44 | return try {
45 | requireAgp(
46 | actual = version,
47 | required = MIN_REQUIRED_AGP_VERSION,
48 | message = { "" }
49 | )
50 | true
51 | } catch (_: Throwable) {
52 | false
53 | }
54 | }
55 |
56 | private fun String.toAndroidPluginVersion(): AndroidPluginVersion {
57 | // Split into stable and optional preview parts
58 | val firstSplit = split('-')
59 |
60 | // Split first part further into major, minor, patch
61 | val stableComponents = firstSplit[0].split('.')
62 |
63 | var version = AndroidPluginVersion(
64 | major = stableComponents[0].toInt(),
65 | minor = stableComponents[1].toInt(),
66 | micro = stableComponents.getOrNull(2)?.toInt() ?: 0
67 | )
68 |
69 | // Attach preview part
70 | val preview = firstSplit.getOrNull(1)
71 |
72 | version = when {
73 | preview == null -> version
74 | preview.startsWith("alpha") -> version.alpha(preview.substringAfter("alpha").toInt())
75 | preview.startsWith("beta") -> version.beta(preview.substringAfter("beta").toInt())
76 | preview.startsWith("rc") -> version.rc(preview.substringAfter("rc").toInt())
77 | else -> version
78 | }
79 |
80 | // Validate correctness
81 | assertThat(version.toString()).endsWith(this)
82 |
83 | return version
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/annotations/DisabledOnCI.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.annotations
2 |
3 | import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable
4 |
5 | @DisabledIfEnvironmentVariable(named = "CI", matches = "true")
6 | annotation class DisabledOnCI
7 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/AbstractProjectTests.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.plugin
2 |
3 | import com.google.common.truth.Truth.assertThat
4 | import de.mannodermaus.gradle.plugins.junit5.internal.extensions.junitPlatform
5 | import de.mannodermaus.gradle.plugins.junit5.util.projects.PluginSpecProjectCreator
6 | import org.junit.jupiter.api.Test
7 | import org.junit.jupiter.api.extension.RegisterExtension
8 |
9 | /**
10 | * Common baseline for AGP-based testing. Different subclasses extend this
11 | * for every type of Android Gradle Plugin supported by JUnit 5.
12 | */
13 | abstract class AbstractProjectTests(
14 | private val pluginApplier: ((PluginSpecProjectCreator.Builder) -> PluginSpecProjectCreator.Builder)
15 | ) :
16 | AgpConfigurationParameterTests,
17 | AgpFilterTests,
18 | AgpInstrumentationSupportTests,
19 | AgpJacocoBaseTests,
20 | AgpJacocoExclusionRuleTests,
21 | AgpJacocoVariantTests,
22 | AgpVariantTests {
23 |
24 | @RegisterExtension
25 | @JvmField
26 | val projectExtension = TestProjectProviderExtension()
27 |
28 | override fun createProject(): PluginSpecProjectCreator.Builder {
29 | return projectExtension.newProject()
30 | .also { pluginApplier(it) }
31 | }
32 |
33 | override fun defaultBuildTypes() = listOf(
34 | "debug", "release"
35 | )
36 |
37 | override fun defaultProductFlavors() = listOf(
38 | FlavorSpec(name = "free", dimension = "tier"),
39 | FlavorSpec(name = "paid", dimension = "tier")
40 | )
41 |
42 | @Test
43 | fun `add an extension to testOptions`() {
44 | val project = createProject().buildAndEvaluate()
45 |
46 | assertThat(project.junitPlatform).isNotNull()
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/AgpConfigurationParameterTests.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.plugin
2 |
3 | import com.google.common.truth.Truth.assertThat
4 | import de.mannodermaus.gradle.plugins.junit5.internal.extensions.junitPlatform
5 | import org.junit.jupiter.api.Test
6 | import org.junit.jupiter.api.assertThrows
7 | import org.junit.platform.commons.PreconditionViolationException
8 |
9 | interface AgpConfigurationParameterTests : AgpTests {
10 | @Test
11 | fun `throw exception if configuration parameter key is empty`() {
12 | val project = createProject().build()
13 |
14 | val exception = assertThrows {
15 | project.junitPlatform.configurationParameter("", "some-value")
16 | }
17 | assertThat(exception.message).contains("key must not be blank")
18 | }
19 |
20 | @Test
21 | fun `throw exception if configuration parameter key contains illegal characters`() {
22 | val project = createProject().build()
23 |
24 | val exception = assertThrows {
25 | project.junitPlatform.configurationParameter("illegal=key", "some-value")
26 | }
27 | assertThat(exception.message).contains("key must not contain '='")
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/AgpProjectTests.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.plugin
2 |
3 | import de.mannodermaus.gradle.plugins.junit5.util.projects.PluginSpecProjectCreator.Builder
4 |
5 | /**
6 | * Entry point for all supported versions of the Android Gradle Plugin.
7 | * The parent class composes all relevant unit tests for each of the plugin types.
8 | */
9 | class AndroidAppProjectTests : AbstractProjectTests(Builder::asAndroidApplication)
10 | class AndroidLibraryProjectTests : AbstractProjectTests(Builder::asAndroidLibrary)
11 | class AndroidDynamicFeatureProjectTests : AbstractProjectTests(Builder::asAndroidDynamicFeature)
12 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/AgpVariantTests.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.plugin
2 |
3 | import com.google.common.truth.Truth.assertThat
4 | import de.mannodermaus.gradle.plugins.junit5.internal.extensions.junitPlatform
5 | import org.junit.jupiter.api.TestFactory
6 |
7 | interface AgpVariantTests : AgpVariantAwareTests {
8 |
9 | @TestFactory
10 | fun `does not create a build-type-specific jacoco task`() = forEachBuildType { project, buildType ->
11 | val buildTypeName = buildType.capitalize()
12 | val name = "jacocoTestReport$buildTypeName"
13 |
14 | assertThat(project.tasks.findByName(name)).isNull()
15 | }
16 |
17 | @TestFactory
18 | fun `add build-type-specific filter DSL to the extension`() = forEachBuildType { project, buildType ->
19 | assertThat(project.junitPlatform.filters(buildType)).isNotNull()
20 | }
21 |
22 | @TestFactory
23 | fun `add a flavor-specific filter DSL to the extension`() = forEachProductFlavor { project, flavor ->
24 | assertThat(project.junitPlatform.filters(flavor)).isNotNull()
25 | }
26 |
27 | @TestFactory
28 | fun `add a variant-specific filter DSL to the extension`() = forEachVariant { project, variant ->
29 | assertThat(project.junitPlatform.filters(variant)).isNotNull()
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/TestProjectProviderExtension.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.plugin
2 |
3 | import de.mannodermaus.gradle.plugins.junit5.util.TestEnvironment
4 | import de.mannodermaus.gradle.plugins.junit5.util.projects.PluginSpecProjectCreator
5 | import org.gradle.api.Project
6 | import org.junit.jupiter.api.extension.AfterEachCallback
7 | import org.junit.jupiter.api.extension.BeforeEachCallback
8 | import org.junit.jupiter.api.extension.ExtensionContext
9 |
10 | /**
11 | * A Junit 5 extension to provide the handle
12 | * to a Gradle project structure for testing.
13 | * Cleans up automatically after each test.
14 | */
15 | class TestProjectProviderExtension : BeforeEachCallback, AfterEachCallback {
16 |
17 | private var factory: PluginSpecProjectCreator? = null
18 | private var rootProject: Project? = null
19 |
20 | override fun beforeEach(context: ExtensionContext) {
21 | val environment = TestEnvironment()
22 | val factory = PluginSpecProjectCreator(environment)
23 | val rootProject = factory.newRootProject()
24 |
25 | this.factory = factory
26 | this.rootProject = rootProject
27 | }
28 |
29 | override fun afterEach(context: ExtensionContext) {
30 | rootProject?.rootDir?.deleteRecursively()
31 | }
32 |
33 | fun newProject(): PluginSpecProjectCreator.Builder {
34 | val factory = this.factory!!
35 | val rootProject = this.rootProject!!
36 |
37 | return factory.newProject(rootProject)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/plugin/WrongPluginUsageTests.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.plugin
2 |
3 | import com.google.common.truth.Truth.assertThat
4 | import org.gradle.api.ProjectConfigurationException
5 | import org.junit.jupiter.api.Test
6 | import org.junit.jupiter.api.assertThrows
7 | import org.junit.jupiter.api.extension.RegisterExtension
8 |
9 | class WrongPluginUsageTests {
10 |
11 | @RegisterExtension
12 | @JvmField
13 | val projectExtension = TestProjectProviderExtension()
14 |
15 | @Test
16 | fun `not applying any supported Android plugin`() {
17 | val exception = assertThrows {
18 | projectExtension.newProject().buildAndEvaluate()
19 | }
20 | assertThat(exception.cause?.message)
21 | .contains("An Android plugin must be applied in order for android-junit5 to work correctly!")
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/tasks/AndroidJUnit5WriteFiltersTests.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.tasks
2 |
3 | import com.google.common.truth.Truth.assertThat
4 | import de.mannodermaus.gradle.plugins.junit5.internal.config.INSTRUMENTATION_FILTER_RES_FILE_NAME
5 | import de.mannodermaus.gradle.plugins.junit5.plugin.TestProjectProviderExtension
6 | import de.mannodermaus.gradle.plugins.junit5.util.assertAll
7 | import de.mannodermaus.gradle.plugins.junit5.util.evaluate
8 | import org.gradle.api.Project
9 | import org.junit.jupiter.api.BeforeEach
10 | import org.junit.jupiter.api.Test
11 | import org.junit.jupiter.api.extension.RegisterExtension
12 | import java.io.File
13 | import java.nio.file.Paths
14 | import kotlin.io.path.readLines
15 |
16 | class AndroidJUnit5WriteFiltersTests {
17 | @RegisterExtension
18 | @JvmField
19 | val projectExtension = TestProjectProviderExtension()
20 |
21 | private lateinit var project: Project
22 |
23 | @BeforeEach
24 | fun beforeEach() {
25 | project = projectExtension.newProject()
26 | .asAndroidApplication()
27 | .applyJUnit5Plugin(true) { junitPlatform ->
28 | junitPlatform.filters().includeTags("included")
29 | junitPlatform.filters().excludeTags("excluded", "another-group")
30 | }
31 | .build()
32 | project.evaluate()
33 | }
34 |
35 | @Test
36 | fun `generates file structure correctly`() {
37 | // Expect a 'raw' folder inside the output, then the actual filters file in that sub-folder
38 | val output = project.runTaskAndGetOutputFolder()
39 |
40 | File(output, "raw").apply {
41 | assertAll(
42 | "output contains 'raw' folder",
43 | { assertThat(exists()).isTrue() },
44 | { assertThat(isDirectory).isTrue() },
45 | )
46 |
47 | File(this, INSTRUMENTATION_FILTER_RES_FILE_NAME).apply {
48 | assertAll(
49 | "'raw' folder contains filters file'",
50 | { assertThat(exists()).isTrue() },
51 | { assertThat(isFile).isTrue() },
52 | )
53 | }
54 | }
55 | }
56 |
57 | @Test
58 | fun `file contains expected content`() {
59 | val output = project.runTaskAndGetOutputFolder()
60 | val file = Paths.get(output.absolutePath, "raw", INSTRUMENTATION_FILTER_RES_FILE_NAME)
61 |
62 | val content = file.readLines()
63 | assertThat(content).containsExactly(
64 | "-t included",
65 | "-T excluded",
66 | "-T another-group",
67 | )
68 | }
69 |
70 | /* Private */
71 |
72 | private fun Project.runTaskAndGetOutputFolder(): File {
73 | val task = project.tasks.getByName("writeFiltersDebugAndroidTest") as AndroidJUnit5WriteFilters
74 | task.execute()
75 | return requireNotNull(task.outputFolder.get().asFile)
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/GradleTruth.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.util
2 |
3 | import com.google.common.truth.FailureMetadata
4 | import com.google.common.truth.Subject
5 | import com.google.common.truth.Truth
6 | import com.google.common.truth.Truth.assertThat
7 | import com.google.common.truth.Truth.assertWithMessage
8 | import org.gradle.api.Project
9 | import org.gradle.api.Task
10 | import org.gradle.api.artifacts.Configuration
11 |
12 | /* Methods */
13 |
14 | fun assertThat(actual: Project): ProjectSubject =
15 | Truth.assertAbout(::ProjectSubject).that(actual)
16 |
17 | /* Types */
18 |
19 | class ProjectSubject(
20 | metadata: FailureMetadata,
21 | private val actual: Project?,
22 | ) : Subject(metadata, actual) {
23 |
24 | fun configuration(name: String): ConfigurationSubject = check("configuration()")
25 | .about(::ConfigurationSubject)
26 | .that(actual?.configurations?.getByName(name))
27 |
28 | fun task(name: String): TaskSubject = check("task()")
29 | .about(::TaskSubject)
30 | .that(actual?.tasks?.findByName(name))
31 | }
32 |
33 | class ConfigurationSubject(
34 | metadata: FailureMetadata,
35 | private val actual: Configuration?,
36 | ) : Subject(metadata, actual) {
37 | private val dependencyNames by lazy {
38 | actual?.dependencies
39 | ?.map { "${it.group}:${it.name}:${it.version}" }
40 | .orEmpty()
41 | }
42 |
43 | fun hasDependency(notation: String) {
44 | containsDependency(notation, expectExists = true)
45 | }
46 |
47 | fun doesNotHaveDependency(notation: String) {
48 | containsDependency(notation, expectExists = false)
49 | }
50 |
51 | /* Private */
52 |
53 | private fun containsDependency(notation: String, expectExists: Boolean) {
54 | // If the expected dependency has a version component,
55 | // include it in the check. Otherwise, check for the existence
56 | // of _any_ version for the dependency in question
57 | val notationIncludesVersion = notation.count { it == ':' } > 1
58 | val hasMatch = if (notationIncludesVersion) {
59 | notation in dependencyNames
60 | } else {
61 | dependencyNames.any { it.startsWith("$notation:") }
62 | }
63 |
64 | val messagePrefix = if (expectExists) {
65 | "Expected to have a dependency on '$notation' in configuration '${actual?.name}', but did not."
66 | } else {
67 | "Expected not to have a dependency on '$notation' in configuration '${actual?.name}', but did."
68 | }
69 |
70 | assertWithMessage(
71 | "$messagePrefix\nDependencies in this configuration: $dependencyNames"
72 | ).that(hasMatch).isEqualTo(expectExists)
73 | }
74 | }
75 |
76 | class TaskSubject(
77 | metadata: FailureMetadata,
78 | private val actual: Task?,
79 | ) : Subject(metadata, actual) {
80 | fun exists() {
81 | assertThat(actual).isNotNull()
82 | }
83 |
84 | fun doesNotExist() {
85 | assertThat(actual).isNull()
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/TestKitTruth.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.util
2 |
3 | import com.google.common.truth.Fact
4 | import com.google.common.truth.FailureMetadata
5 | import com.google.common.truth.IntegerSubject
6 | import com.google.common.truth.StringSubject
7 | import com.google.common.truth.Subject
8 | import com.google.common.truth.Truth
9 | import org.gradle.testkit.runner.BuildResult
10 | import org.gradle.testkit.runner.BuildTask
11 | import org.gradle.testkit.runner.TaskOutcome
12 |
13 | /* Methods */
14 |
15 | fun assertThat(actual: BuildResult): BuildResultSubject =
16 | Truth.assertAbout(::BuildResultSubject).that(actual)
17 |
18 | /* Types */
19 |
20 | class BuildResultSubject(
21 | metadata: FailureMetadata,
22 | private val actual: BuildResult?
23 | ) : Subject(metadata, actual) {
24 |
25 | fun task(name: String): BuildTaskSubject = check("task()")
26 | .about(::BuildTaskSubject)
27 | .that(actual?.task(name))
28 |
29 | fun output(): BuildResultOutputSubject = check("output()")
30 | .about(::BuildResultOutputSubject)
31 | .that(actual?.output)
32 | }
33 |
34 | class BuildTaskSubject(
35 | metadata: FailureMetadata,
36 | private val actual: BuildTask?
37 | ) : Subject(metadata, actual) {
38 |
39 | fun hasOutcome(expected: TaskOutcome) = check("hasOutcome()")
40 | .that(actual?.outcome)
41 | .isEqualTo(expected)
42 | }
43 |
44 | class BuildResultOutputSubject(
45 | metadata: FailureMetadata,
46 | private val actual: String?
47 | ) : StringSubject(metadata, actual) {
48 |
49 | fun ofTask(name: String): BuildTaskOutputSubject {
50 | requireNotNull(actual)
51 |
52 | val startIndex = actual.indexOf("> Task $name")
53 | if (startIndex == -1) {
54 | failWithActual(Fact.simpleFact("Task $name was not executed"))
55 | }
56 |
57 | var endIndex = actual.indexOf("> Task", startIndex + 1)
58 | if (endIndex == -1) {
59 | endIndex = actual.length - 1
60 | }
61 |
62 | val strippedOutput = actual.substring(startIndex, endIndex)
63 | return check("ofTask()")
64 | .about(::BuildTaskOutputSubject)
65 | .that(strippedOutput)
66 | }
67 | }
68 |
69 | class BuildTaskOutputSubject(
70 | metadata: FailureMetadata,
71 | private val actual: String?
72 | ) : StringSubject(metadata, actual) {
73 |
74 | fun executedTestCount(): IntegerSubject {
75 | requireNotNull(actual)
76 |
77 | // Subtract 1 from the total count because the task name is also preceded by ">"
78 | val actualCount = actual.count { it == '>' } - 1
79 |
80 | return check("executedTestCount()")
81 | .withMessage("actual test count: $actualCount. full task output: $actual")
82 | .that(actualCount)
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/TestedAgp.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.util
2 |
3 | data class TestedAgp(
4 | val shortVersion: String,
5 | val version: String,
6 | val requiresGradle: String,
7 | val requiresCompileSdk: Int?
8 | ) {
9 | val fileKey: String = "agp${shortVersion.replace(".", "")}x"
10 | }
11 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/projects/BuildScriptTemplateProcessor.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.util.projects
2 |
3 | import com.soywiz.korte.TeFunction
4 | import com.soywiz.korte.TemplateConfig
5 | import com.soywiz.korte.TemplateProvider
6 | import com.soywiz.korte.Templates
7 | import kotlinx.coroutines.runBlocking
8 | import java.io.File
9 |
10 | /**
11 | * Processor class for virtual build script files, used by Functional Tests.
12 | * It utilizes a template engine to customize the processed output for the build scripts
13 | * injected into the virtual projects, based around template files located within src/test/resources.
14 | */
15 | class BuildScriptTemplateProcessor(
16 | folder: File,
17 | private val replacements: Map,
18 | private val agpVersion: String,
19 | private val gradleVersion: String
20 | ) {
21 |
22 | private val renderer = Templates(
23 | root = FileReadingTemplateProvider(folder),
24 | cache = true,
25 | config = TemplateConfig(
26 | // Allow checking for AGP & Gradle versions inside the templates
27 | extraFunctions = listOf(
28 | TeFunction("atLeastAgp") { args ->
29 | isVersionAtLeast(agpVersion, args[0].toDynamicString())
30 | },
31 | TeFunction("atLeastGradle") { args ->
32 | isVersionAtLeast(gradleVersion, args[0].toDynamicString())
33 | }
34 | )
35 | )
36 | )
37 |
38 | fun process(fileName: String): String = runBlocking {
39 | renderer.render(fileName, replacements)
40 | }
41 |
42 | /* Private */
43 |
44 | private fun isVersionAtLeast(actual: String, required: String): Boolean {
45 | val actualVersion = SemanticVersion(actual)
46 | val requiredVersion = SemanticVersion(required)
47 | return actualVersion >= requiredVersion
48 | }
49 |
50 | private class FileReadingTemplateProvider(private val folder: File) : TemplateProvider {
51 | override suspend fun get(template: String): String {
52 | return File(folder, template).readText()
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/projects/SemanticVersion.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.gradle.plugins.junit5.util.projects
2 |
3 | import java.util.*
4 |
5 | private val NUMERICAL_REGEX = Regex("(\\d+)")
6 |
7 | /**
8 | * Wrapper for a semantic version string (e.g. "6.0" or "7.1.5-alpha-12"),
9 | * interpreting that string as a numerical value eligible for comparisons against other objects.
10 | */
11 | class SemanticVersion(version: String): Comparable {
12 | val stableValue: Int = version.extractStableValue()
13 | val suffixValue: Int = version.extractSuffixValue()
14 |
15 | override fun compareTo(other: SemanticVersion): Int {
16 | val result = this.stableValue.compareTo(other.stableValue)
17 | return if (result == 0) {
18 | this.suffixValue.compareTo(other.suffixValue)
19 | } else {
20 | result
21 | }
22 | }
23 | }
24 |
25 | /* Private */
26 |
27 | private fun String.extractStableValue(): Int {
28 | val stripped = this.substringBefore('-')
29 | val split = stripped.split('.').map {
30 | it.toIntOrNull() ?: throw IllegalArgumentException("unknown stable value for version: $this")
31 | }
32 |
33 | require(split.size in 2..3) {
34 | "unsupported number of components for version: $this"
35 | }
36 |
37 | // Add up the components, with the patch component being optional
38 | return split[0] * 10000 +
39 | split[1] * 100 +
40 | if (split.size > 2) split[2] else 0
41 | }
42 |
43 | private fun String.extractSuffixValue(): Int {
44 | if ('-' in this) {
45 | val suffix = this
46 | .substringAfter('-')
47 | .toLowerCase(Locale.ROOT)
48 |
49 | // Find known suffix types
50 | val suffixMultiplier = when {
51 | "alpha" in suffix -> 1
52 | "beta" in suffix -> 100
53 | "rc" in suffix -> 10000
54 | else -> throw IllegalArgumentException("unknown suffix category for version: $this")
55 | }
56 |
57 | // Find numerical value of suffix
58 | val numericalSuffix = NUMERICAL_REGEX.find(suffix)?.groupValues?.lastOrNull()?.toIntOrNull()
59 | ?: throw IllegalArgumentException("unknown numerical suffix value for version: $this")
60 |
61 | return suffixMultiplier * numericalSuffix
62 |
63 | } else {
64 | // Not a preview version - use highest possible suffix value to be "newer" than any preview could be
65 | return Int.MAX_VALUE
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/de/mannodermaus/gradle/plugins/junit5/testenv.properties:
--------------------------------------------------------------------------------
1 | # suppress inspection "UnusedProperty" for whole file
2 | # (Populated from the Gradle "processTestResources" task, used by the test runtime)
3 | COMPILE_SDK_VERSION = android-@COMPILE_SDK_VERSION@
4 | MIN_SDK_VERSION = @MIN_SDK_VERSION@
5 | TARGET_SDK_VERSION = @TARGET_SDK_VERSION@
6 |
7 | KOTLIN_VERSION = @KOTLIN_VERSION@
8 | JUNIT_JUPITER_VERSION = @JUNIT_JUPITER_VERSION@
9 | JUNIT5_ANDROID_LIBS_VERSION = @JUNIT5_ANDROID_LIBS_VERSION@
10 |
11 | AGP_VERSIONS = @AGP_VERSIONS@
12 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/custom-build-type/config.toml:
--------------------------------------------------------------------------------
1 | [settings]
2 | useCustomBuildType = "staging"
3 |
4 | [[expectations]]
5 | buildType = "debug"
6 | tests = "JavaTest"
7 |
8 | [[expectations]]
9 | buildType = "release"
10 | tests = "JavaTest,JavaReleaseTest"
11 |
12 | [[expectations]]
13 | buildType = "staging"
14 | tests = "JavaTest,JavaStagingTest"
15 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/custom-build-type/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/custom-build-type/src/main/java/de/mannodermaus/app/Adder.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | public class Adder {
4 | public int add(int a, int b) {
5 | return a + b;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/custom-build-type/src/test/java/de/mannodermaus/app/JavaTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/custom-build-type/src/testRelease/java/de/mannodermaus/app/JavaReleaseTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaReleaseTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/custom-build-type/src/testStaging/java/de/mannodermaus/app/JavaStagingTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaStagingTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/default-values/config.toml:
--------------------------------------------------------------------------------
1 | [settings]
2 | returnDefaultValues = true
3 |
4 | [[expectations]]
5 | buildType = "debug"
6 | tests = "JavaTest,AndroidTest"
7 |
8 | [[expectations]]
9 | buildType = "release"
10 | tests = "JavaTest,AndroidTest"
11 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/default-values/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/default-values/src/main/java/de/mannodermaus/app/Adder.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | public class Adder {
4 | public int add(int a, int b) {
5 | return a + b;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/default-values/src/test/java/de/mannodermaus/app/AndroidTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertNull;
4 |
5 | import org.junit.jupiter.api.Test;
6 | import android.content.Intent;
7 |
8 | class AndroidTest {
9 | @Test
10 | void test() {
11 | Intent intent = new Intent();
12 | assertNull(intent.getAction());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/default-values/src/test/java/de/mannodermaus/app/JavaTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/include-android-resources/config.toml:
--------------------------------------------------------------------------------
1 | [settings]
2 | includeAndroidResources = true
3 |
4 | [[expectations]]
5 | buildType = "debug"
6 | tests = "AndroidTest"
7 |
8 | [[expectations]]
9 | buildType = "release"
10 | tests = "AndroidTest"
11 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/include-android-resources/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/include-android-resources/src/main/java/de/mannodermaus/app/Adder.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | public class Adder {
4 | public int add(int a, int b) {
5 | return a + b;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/include-android-resources/src/test/java/de/mannodermaus/app/AndroidTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertNotNull;
4 |
5 | import org.junit.jupiter.api.Test;
6 | import java.io.InputStream;
7 |
8 | class AndroidTest {
9 | @Test
10 | void test() {
11 | InputStream is = getClass().getResourceAsStream("/com/android/tools/test_config.properties");
12 | assertNotNull(is);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/instrumentation-tests/config.toml:
--------------------------------------------------------------------------------
1 | [settings]
2 | includeAndroidResources = true
3 |
4 | [[expectations]]
5 | buildType = "debug"
6 | tests = "AndroidTest"
7 |
8 | [[expectations]]
9 | buildType = "release"
10 | tests = "AndroidTest"
11 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/instrumentation-tests/src/androidTest/java/de/mannodermaus/app/InstrumentationTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | class InstrumentationTest {
6 | @Test
7 | void test() {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/instrumentation-tests/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/instrumentation-tests/src/main/java/de/mannodermaus/app/Adder.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | public class Adder {
4 | public int add(int a, int b) {
5 | return a + b;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/instrumentation-tests/src/test/java/de/mannodermaus/app/AndroidTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertNotNull;
4 |
5 | import org.junit.jupiter.api.Test;
6 | import java.io.InputStream;
7 |
8 | class AndroidTest {
9 | @Test
10 | void test() {
11 | InputStream is = getClass().getResourceAsStream("/com/android/tools/test_config.properties");
12 | assertNotNull(is);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/jacoco/config.toml:
--------------------------------------------------------------------------------
1 | [settings]
2 | useJacoco = true
3 | task = "jacocoTestReportDebug"
4 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/jacoco/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/jacoco/src/main/java/de/mannodermaus/app/Adder.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | public class Adder {
4 | public int add(int a, int b) {
5 | return a + b;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/jacoco/src/test/java/de/mannodermaus/app/AdderTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/new-variant-api/config.toml:
--------------------------------------------------------------------------------
1 | [settings]
2 | minAgpVersion = "4.0"
3 | useFlavors = true
4 | useKotlin = true
5 | disableTestsForBuildTypes = "debug"
6 |
7 | [[expectations]]
8 | buildType = "release"
9 | productFlavor = "free"
10 | tests = "JavaTest,KotlinReleaseTest,JavaFreeReleaseTest"
11 |
12 | [[expectations]]
13 | buildType = "release"
14 | productFlavor = "paid"
15 | tests = "JavaTest,KotlinReleaseTest"
16 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/new-variant-api/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/new-variant-api/src/main/java/de/mannodermaus/app/Adder.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | public class Adder {
4 | public int add(int a, int b) {
5 | return a + b;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/new-variant-api/src/test/java/de/mannodermaus/app/JavaTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/new-variant-api/src/testFreeRelease/java/de/mannodermaus/app/JavaFreeReleaseTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaFreeReleaseTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/new-variant-api/src/testPaidDebug/java/de/mannodermaus/app/KotlinPaidDebugTest.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app
2 |
3 | import org.junit.jupiter.api.Assertions.assertEquals
4 | import org.junit.jupiter.api.Test
5 |
6 | class KotlinPaidDebugTest {
7 | @Test
8 | fun test() {
9 | val adder = Adder()
10 | assertEquals(4, adder.add(2, 2), "This should succeed!")
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/new-variant-api/src/testRelease/java/de/mannodermaus/app/KotlinReleaseTest.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app
2 |
3 | import org.junit.jupiter.api.Assertions.assertEquals
4 | import org.junit.jupiter.api.Test
5 |
6 | class KotlinReleaseTest {
7 | @Test
8 | fun test() {
9 | val adder = Adder()
10 | assertEquals(4, adder.add(2, 2), "This should succeed!")
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/product-flavors/config.toml:
--------------------------------------------------------------------------------
1 | [settings]
2 | useFlavors = true
3 | useKotlin = true
4 |
5 | [[expectations]]
6 | buildType = "debug"
7 | productFlavor = "free"
8 | tests = "JavaTest"
9 |
10 | [[expectations]]
11 | buildType = "debug"
12 | productFlavor = "paid"
13 | tests = "JavaTest,KotlinPaidDebugTest"
14 |
15 | [[expectations]]
16 | buildType = "release"
17 | productFlavor = "free"
18 | tests = "JavaTest,KotlinReleaseTest,JavaFreeReleaseTest"
19 |
20 | [[expectations]]
21 | buildType = "release"
22 | productFlavor = "paid"
23 | tests = "JavaTest,KotlinReleaseTest"
24 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/product-flavors/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/product-flavors/src/main/java/de/mannodermaus/app/Adder.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | public class Adder {
4 | public int add(int a, int b) {
5 | return a + b;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/product-flavors/src/test/java/de/mannodermaus/app/JavaTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/product-flavors/src/testFreeRelease/java/de/mannodermaus/app/JavaFreeReleaseTest.java:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class JavaFreeReleaseTest {
8 | @Test
9 | void test() {
10 | Adder adder = new Adder();
11 | assertEquals(4, adder.add(2, 2), "This should succeed!");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/product-flavors/src/testPaidDebug/java/de/mannodermaus/app/KotlinPaidDebugTest.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app
2 |
3 | import org.junit.jupiter.api.Assertions.assertEquals
4 | import org.junit.jupiter.api.Test
5 |
6 | class KotlinPaidDebugTest {
7 | @Test
8 | fun test() {
9 | val adder = Adder()
10 | assertEquals(4, adder.add(2, 2), "This should succeed!")
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/product-flavors/src/testRelease/java/de/mannodermaus/app/KotlinReleaseTest.kt:
--------------------------------------------------------------------------------
1 | package de.mannodermaus.app
2 |
3 | import org.junit.jupiter.api.Assertions.assertEquals
4 | import org.junit.jupiter.api.Test
5 |
6 | class KotlinReleaseTest {
7 | @Test
8 | fun test() {
9 | val adder = Adder()
10 | assertEquals(4, adder.add(2, 2), "This should succeed!")
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugin/android-junit5/src/test/resources/test-projects/settings.gradle.kts.template:
--------------------------------------------------------------------------------
1 | // This template is the baseline for
2 | // all functional tests executed against the android-junit5 plugin.
3 | // It is based on the Gradle Kotlin DSL (.kts) and provides several additional
4 | // placeholder markers, which are substituted upon creating virtual projects
5 | // in which the test code is being executed for every supported Android Gradle Plugin.
6 | //
7 | // The individual configuration of each test depends on the config.toml file,
8 | // located in the sub-folder next to its source code.
9 |
10 | pluginManagement {
11 | repositories {
12 | google()
13 | mavenCentral()
14 | }
15 | resolutionStrategy {
16 | eachPlugin {
17 | val androidGradlePluginVersion = "{{ AGP_VERSION }}"
18 | val kotlinVersion = "{{ KOTLIN_VERSION }}"
19 |
20 | if (requested.id.id == "com.android.application") {
21 | useModule("com.android.tools.build:gradle:${androidGradlePluginVersion}")
22 | }
23 | if (requested.id.id == "org.jetbrains.kotlin.android") {
24 | useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/plugin/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("io.github.gradle-nexus.publish-plugin").version(libs.versions.nexusPublish)
3 | id("org.jetbrains.kotlinx.binary-compatibility-validator").version(libs.versions.kotlinxBinaryCompatibilityValidator)
4 | }
5 |
6 | buildscript {
7 | repositories {
8 | google()
9 | mavenCentral()
10 | gradlePluginPortal()
11 | }
12 |
13 | dependencies {
14 | classpath(libs.plugins.kotlin)
15 | classpath(libs.plugins.dokka)
16 | classpath(libs.plugins.shadow)
17 | }
18 | }
19 |
20 | allprojects {
21 | repositories {
22 | google()
23 | mavenCentral()
24 | sonatypeSnapshots()
25 | }
26 |
27 | configurations.all {
28 | resolutionStrategy.eachDependency {
29 | if (requested.group == "org.jetbrains.kotlin") {
30 | useVersion(libs.versions.kotlin)
31 | }
32 | }
33 | }
34 | }
35 |
36 | apiValidation {
37 | ignoredPackages.add("de.mannodermaus.gradle.plugins.junit5.internal")
38 | }
39 |
40 | tasks.create("generateReadme") {
41 | // Find folder containing README.md
42 | // (required because this script file is included through symlinks in subprojects)
43 | var rootFolder: File? = project.rootDir
44 | while (rootFolder != null && rootFolder.exists()) {
45 | val inFile = File(rootFolder, "README.md.template")
46 | val outFile = File(rootFolder, "README.md")
47 |
48 | if (inFile.exists() && outFile.exists()) {
49 | this.inputTemplateFile = inFile
50 | this.outputFile = outFile
51 | break
52 | }
53 |
54 | rootFolder = rootFolder.parentFile
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/plugin/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | }
8 |
9 | sourceSets {
10 | main {
11 | java.srcDir(file("../../build-logic/src/main/kotlin"))
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/gradle.properties:
--------------------------------------------------------------------------------
1 | # Dokka V2 (https://kotlinlang.org/docs/dokka-migration.html)
2 | org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
3 | org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
4 |
--------------------------------------------------------------------------------
/plugin/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mannodermaus/android-junit5/f761c0f15619cb8caa9ac44daa50864329153d30/plugin/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/plugin/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/plugin/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo. 1>&2
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
48 | echo. 1>&2
49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
50 | echo location of your Java installation. 1>&2
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo. 1>&2
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
62 | echo. 1>&2
63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
64 | echo location of your Java installation. 1>&2
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/plugin/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "android-junit5-plugin"
2 | includeBuild("../build-logic")
3 | include(":android-junit5")
4 |
--------------------------------------------------------------------------------