diff --git a/.circleci/config.yml b/.circleci/config.yml index d94686f8..8db1088c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -118,12 +118,12 @@ jobs: name: (Plugin) Build & Deploy command: | cd plugin - ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository --stacktrace + ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepositories --stacktrace - run: name: (Instrumentation) Build & Deploy command: | cd instrumentation - ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository --stacktrace + ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepositories --stacktrace - store_artifacts: path: plugin/android-junit5/build/publications destination: plugin/publications/snapshots diff --git a/README.md.template b/README.md.template index 83c15cf9..ceff9701 100644 --- a/README.md.template +++ b/README.md.template @@ -200,7 +200,7 @@ Then, add the integration library for Jetpack Compose to the `androidTestImpleme [The wiki][wiki-home] includes a section on how to test your Composables with JUnit 5. -# Official Support +## Official Support At this time, Google hasn't shared any immediate plans to bring first-party support for JUnit 5 to Android. The following list is an aggregation of pending feature requests: @@ -208,13 +208,27 @@ At this time, Google hasn't shared any immediate plans to bring first-party supp - [Add support for JUnit 5 (issuetracker.google.com)](https://issuetracker.google.com/issues/127100532) - [JUnit 5 support (github.com/android/android-test)](https://github.com/android/android-test/issues/224) -# Building Locally +## Building Locally This repository contains multiple modules, divided into two sub-projects. The repository's root directory contains build logic shared across the sub-projects, which in turn use symlinks to connect to the common build scripts in their parent folder. - `instrumentation`: The root folder for Android-based modules, namely the instrumentation libraries & a sample application. After cloning, open this project in Android Studio. - `plugin`: The root folder for Java-based modules, namely the Gradle plugin for JUnit 5 on Android, as well as its test module. After cloning, open this project in IntelliJ IDEA. +## Plugin Compatibility Map + +For users that cannot match the current minimum version requirement of the Android Gradle Plugin requested by this plugin, +refer to the table below to find a suitable alternative version. Note that **no active development will go into these +legacy versions**, so please consider upgrading to at least Android Gradle Plugin ${constants.minimumRequiredAgpVersion} +before filing an issue with the latest one. + +|Your AGP Version|Suggested JUnit5 Plugin Version| +|---|---| +|`7.0.0` - `7.4.2`|`1.10.0.0`| +|`4.0.0` - `4.2.2`|`1.8.2.1`| +|`3.5.0` - `3.6.4`|`1.7.1.1`| +|`< 3.5.0`|none; you should **really** update your build env, bro| + ## License ``` diff --git a/build-logic/src/main/kotlin/Dependencies.kt b/build-logic/src/main/kotlin/Dependencies.kt index fc109780..cec34331 100644 --- a/build-logic/src/main/kotlin/Dependencies.kt +++ b/build-logic/src/main/kotlin/Dependencies.kt @@ -2,21 +2,36 @@ object libs { object versions { - const val kotlin = "1.8.21" - const val junitJupiter = "5.10.0" - const val junitVintage = "5.10.0" - const val junitPlatform = "1.10.0" - const val truth = "1.1.3" - const val androidXTest = "1.4.0" - const val composeCompiler = "1.4.7" - const val composeBom = "2023.05.01" + const val kotlin = "1.9.23" + const val junitJupiter = "5.10.2" + const val junitVintage = "5.10.2" + const val junitPlatform = "1.10.2" + + const val composeBom = "2024.04.00" + const val androidXTest = "1.5.0" + const val composeCompiler = "1.5.11" + + const val activityCompose = "1.8.2" + const val apiGuardian = "1.1.2" + const val coroutines = "1.8.0" + const val dokka = "1.9.20" + const val espresso = "3.5.1" + const val javaSemver = "0.10.2" + const val junit4 = "4.13.2" + const val konfToml = "1.1.2" + const val korte = "2.4.12" + const val mockitoCore = "5.11.0" + const val mockitoKotlin = "5.2.1" + const val robolectric = "4.12" + const val shadow = "8.1.1" + const val truth = "1.4.2" } object plugins { fun android(version: SupportedAgp) = "com.android.tools.build:gradle:${version.version}" const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin}" - const val shadow = "com.github.jengelman.gradle.plugins:shadow:6.1.0" - const val dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.7.0" + const val shadow = "com.github.johnrengelman:shadow:${libs.versions.shadow}" + const val dokka = "org.jetbrains.dokka:dokka-gradle-plugin:${libs.versions.dokka}" } // Libraries @@ -29,8 +44,8 @@ object libs { } const val kotlinStdLib = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}" - const val kotlinCoroutinesCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4" - const val javaSemver = "com.github.zafarkhaja:java-semver:0.9.0" + const val kotlinCoroutinesCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${versions.coroutines}" + const val javaSemver = "com.github.zafarkhaja:java-semver:${versions.javaSemver}" const val junitJupiterApi = "org.junit.jupiter:junit-jupiter-api:${versions.junitJupiter}" const val junitJupiterParams = "org.junit.jupiter:junit-jupiter-params:${versions.junitJupiter}" @@ -38,29 +53,29 @@ object libs { const val junitVintageEngine = "org.junit.vintage:junit-vintage-engine:${versions.junitVintage}" const val junitPlatformCommons = "org.junit.platform:junit-platform-commons:${versions.junitPlatform}" const val junitPlatformRunner = "org.junit.platform:junit-platform-runner:${versions.junitPlatform}" - const val apiguardianApi = "org.apiguardian:apiguardian-api:1.1.2" + const val apiguardianApi = "org.apiguardian:apiguardian-api:${versions.apiGuardian}" const val composeBom = "androidx.compose:compose-bom:${versions.composeBom}" const val composeUi = "androidx.compose.ui:ui" const val composeUiTooling = "androidx.compose.ui:ui-tooling" const val composeFoundation = "androidx.compose.foundation:foundation" const val composeMaterial = "androidx.compose.material:material" - const val composeActivity = "androidx.activity:activity-compose:1.7.1" + const val composeActivity = "androidx.activity:activity-compose:${versions.activityCompose}" // Testing - const val junit4 = "junit:junit:4.13.2" - const val korte = "com.soywiz.korlibs.korte:korte:2.2.0" - const val konfToml = "com.uchuhimo:konf-toml:1.1.2" - const val mockitoCore = "org.mockito:mockito-core:3.11.1" - const val mockitoKotlin = "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" + const val junit4 = "junit:junit:${versions.junit4}" + const val korte = "com.soywiz.korlibs.korte:korte:${versions.korte}" + const val konfToml = "com.uchuhimo:konf-toml:${versions.konfToml}" + const val mockitoCore = "org.mockito:mockito-core:${versions.mockitoCore}" + const val mockitoKotlin = "org.mockito.kotlin:mockito-kotlin:${versions.mockitoKotlin}" const val truth = "com.google.truth:truth:${versions.truth}" const val truthJava8Extensions = "com.google.truth.extensions:truth-java8-extension:${versions.truth}" - const val robolectric = "org.robolectric:robolectric:4.8.1" + const val robolectric = "org.robolectric:robolectric:${versions.robolectric}" const val androidXTestCore = "androidx.test:core:${versions.androidXTest}" const val androidXTestRunner = "androidx.test:runner:${versions.androidXTest}" const val androidXTestMonitor = "androidx.test:monitor:${versions.androidXTest}" - const val espressoCore = "androidx.test.espresso:espresso-core:3.4.0" + const val espressoCore = "androidx.test.espresso:espresso-core:${versions.espresso}" const val composeUiTest = "androidx.compose.ui:ui-test" const val composeUiTestJUnit4 = "androidx.compose.ui:ui-test-junit4" diff --git a/build-logic/src/main/kotlin/Environment.kt b/build-logic/src/main/kotlin/Environment.kt index 8557546a..6a7aa9fb 100644 --- a/build-logic/src/main/kotlin/Environment.kt +++ b/build-logic/src/main/kotlin/Environment.kt @@ -8,11 +8,6 @@ enum class SupportedAgp( val version: String, val gradle: String? = null ) { - AGP_7_0("7.0.4", gradle = "7.0.2"), - AGP_7_1("7.1.3", gradle = "7.2"), - AGP_7_2("7.2.2", gradle = "7.3.3"), - AGP_7_3("7.3.1", gradle = "7.4.2"), - AGP_7_4("7.4.2", gradle = "7.5.1"), AGP_8_0("8.0.2", gradle = "8.0"), AGP_8_1("8.1.4", gradle = "8.0"), AGP_8_2("8.2.2", gradle = "8.2"), @@ -22,6 +17,7 @@ enum class SupportedAgp( companion object { val oldest = values().first() + val newestStable = values().reversed().first { '-' !in it.version } } val shortVersion: String = run { @@ -38,9 +34,9 @@ enum class SupportedAgp( } object Android { - const val compileSdkVersion = 33 - const val targetSdkVersion = 32 - const val sampleMinSdkVersion = 14 + const val compileSdkVersion = 34 + const val targetSdkVersion = 34 + const val sampleMinSdkVersion = 21 val testRunnerMinSdkVersion = (Artifacts.Instrumentation.Runner.platform as Android).minSdk val testCoreMinSdkVersion = (Artifacts.Instrumentation.Core.platform as Android).minSdk val testComposeMinSdkVersion = (Artifacts.Instrumentation.Compose.platform as Android).minSdk diff --git a/build-logic/src/main/kotlin/Tasks.kt b/build-logic/src/main/kotlin/Tasks.kt index 82ffe5df..e92f0d6f 100644 --- a/build-logic/src/main/kotlin/Tasks.kt +++ b/build-logic/src/main/kotlin/Tasks.kt @@ -16,7 +16,7 @@ import java.io.File import java.time.ZonedDateTime import java.util.* -private const val minimumGradleVersion = "7.0" +private const val minimumGradleVersion = "8.0" @Suppress("DEPRECATION") fun Project.configureTestResources() { diff --git a/instrumentation/build.gradle.kts b/instrumentation/build.gradle.kts index 5eae21cc..fc1f0b4e 100644 --- a/instrumentation/build.gradle.kts +++ b/instrumentation/build.gradle.kts @@ -1,7 +1,6 @@ plugins { - id("io.github.gradle-nexus.publish-plugin").version("1.1.0") - id("com.github.ben-manes.versions").version("0.42.0") - id("org.jetbrains.kotlinx.binary-compatibility-validator").version("0.11.0") + id("io.github.gradle-nexus.publish-plugin").version("2.0.0") + id("org.jetbrains.kotlinx.binary-compatibility-validator").version("0.14.0") } buildscript { @@ -15,7 +14,7 @@ buildscript { dependencies { classpath(libs.plugins.kotlin) classpath(libs.plugins.dokka) - classpath(libs.plugins.android(SupportedAgp.oldest)) + classpath(libs.plugins.android(SupportedAgp.newestStable)) } } diff --git a/instrumentation/compose/build.gradle.kts b/instrumentation/compose/build.gradle.kts index cc43fe95..79e2f57a 100644 --- a/instrumentation/compose/build.gradle.kts +++ b/instrumentation/compose/build.gradle.kts @@ -11,11 +11,11 @@ plugins { val javaVersion = JavaVersion.VERSION_11 android { + namespace = "de.mannodermaus.junit5.compose" compileSdk = Android.compileSdkVersion defaultConfig { minSdk = Android.testComposeMinSdkVersion - targetSdk = Android.targetSdkVersion testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments["runnerBuilder"] = "de.mannodermaus.junit5.AndroidJUnit5Builder" @@ -42,9 +42,14 @@ android { testOptions { unitTests.isReturnDefaultValues = true + targetSdk = Android.targetSdkVersion + } + + lint { + targetSdk = Android.targetSdkVersion } - packagingOptions { + packaging { resources.excludes.add("META-INF/AL2.0") resources.excludes.add("META-INF/LGPL2.1") } diff --git a/instrumentation/compose/src/androidTest/AndroidManifest.xml b/instrumentation/compose/src/debug/AndroidManifest.xml similarity index 76% rename from instrumentation/compose/src/androidTest/AndroidManifest.xml rename to instrumentation/compose/src/debug/AndroidManifest.xml index 5ffdba91..4efa7a8e 100644 --- a/instrumentation/compose/src/androidTest/AndroidManifest.xml +++ b/instrumentation/compose/src/debug/AndroidManifest.xml @@ -1,6 +1,4 @@ - - + diff --git a/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ExistingActivity.kt b/instrumentation/compose/src/debug/java/de/mannodermaus/junit5/compose/ExistingActivity.kt similarity index 81% rename from instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ExistingActivity.kt rename to instrumentation/compose/src/debug/java/de/mannodermaus/junit5/compose/ExistingActivity.kt index 3d9f4fde..41823d61 100644 --- a/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ExistingActivity.kt +++ b/instrumentation/compose/src/debug/java/de/mannodermaus/junit5/compose/ExistingActivity.kt @@ -7,17 +7,17 @@ import androidx.compose.foundation.layout.Column import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -class ExistingActivity : ComponentActivity() { +public class ExistingActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Column { - var counter by remember { mutableStateOf(0) } + var counter by remember { mutableIntStateOf(0) } Text(text = "Clicked: $counter") Button(onClick = { counter++ }) { diff --git a/instrumentation/compose/src/main/AndroidManifest.xml b/instrumentation/compose/src/main/AndroidManifest.xml deleted file mode 100644 index fd03ccb3..00000000 --- a/instrumentation/compose/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/instrumentation/core/build.gradle.kts b/instrumentation/core/build.gradle.kts index 66bac19b..ff45c7e8 100644 --- a/instrumentation/core/build.gradle.kts +++ b/instrumentation/core/build.gradle.kts @@ -9,14 +9,14 @@ plugins { id("de.mannodermaus.android-junit5").version(Artifacts.Plugin.latestStableVersion) } -val javaVersion = JavaVersion.VERSION_1_8 +val javaVersion = JavaVersion.VERSION_11 android { + namespace = "de.mannodermaus.junit5" compileSdk = Android.compileSdkVersion defaultConfig { minSdk = Android.testCoreMinSdkVersion - targetSdk = Android.targetSdkVersion multiDexEnabled = true testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -35,16 +35,18 @@ android { lint { // JUnit 4 refers to java.lang.management APIs, which are absent on Android. - warning("InvalidPackage") + warning.add("InvalidPackage") + targetSdk = Android.targetSdkVersion } - packagingOptions { + packaging { resources.excludes.add("META-INF/LICENSE.md") resources.excludes.add("META-INF/LICENSE-notice.md") } testOptions { unitTests.isReturnDefaultValues = true + targetSdk = Android.targetSdkVersion } } diff --git a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/JavaInstrumentationTests.java b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/JavaInstrumentationTests.java index abcc8b9a..52b66f85 100644 --- a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/JavaInstrumentationTests.java +++ b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/JavaInstrumentationTests.java @@ -11,10 +11,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestTemplate; -import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; -import org.junit.jupiter.api.condition.EnabledIfSystemProperty; -import org.junit.jupiter.api.condition.EnabledOnJre; -import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.Extension; import org.junit.jupiter.api.extension.ExtensionContext; diff --git a/instrumentation/core/src/androidTest/AndroidManifest.xml b/instrumentation/core/src/debug/AndroidManifest.xml similarity index 80% rename from instrumentation/core/src/androidTest/AndroidManifest.xml rename to instrumentation/core/src/debug/AndroidManifest.xml index a010fbd9..d9f1529e 100644 --- a/instrumentation/core/src/androidTest/AndroidManifest.xml +++ b/instrumentation/core/src/debug/AndroidManifest.xml @@ -1,4 +1,4 @@ - + diff --git a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/TestActivities.kt b/instrumentation/core/src/debug/java/de/mannodermaus/junit5/TestActivity.kt similarity index 92% rename from instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/TestActivities.kt rename to instrumentation/core/src/debug/java/de/mannodermaus/junit5/TestActivity.kt index 79a6ea66..4eb19513 100644 --- a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/TestActivities.kt +++ b/instrumentation/core/src/debug/java/de/mannodermaus/junit5/TestActivity.kt @@ -3,7 +3,6 @@ package de.mannodermaus.junit5 import android.app.Activity import android.os.Bundle import android.widget.TextView -import de.mannodermaus.junit5.test.R class TestActivity : Activity() { diff --git a/instrumentation/core/src/androidTest/res/layout/activity_test.xml b/instrumentation/core/src/debug/res/layout/activity_test.xml similarity index 100% rename from instrumentation/core/src/androidTest/res/layout/activity_test.xml rename to instrumentation/core/src/debug/res/layout/activity_test.xml diff --git a/instrumentation/core/src/main/AndroidManifest.xml b/instrumentation/core/src/main/AndroidManifest.xml deleted file mode 100644 index 2b80fac9..00000000 --- a/instrumentation/core/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/AbstractExecutionConditionTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/AbstractExecutionConditionTests.kt index b1c22de7..cabe47ee 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/AbstractExecutionConditionTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/AbstractExecutionConditionTests.kt @@ -1,8 +1,6 @@ package de.mannodermaus.junit5.condition -import com.google.common.truth.Truth8.assertThat -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.whenever +import com.google.common.truth.Truth.assertThat import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.TestInfo @@ -10,6 +8,8 @@ import org.junit.jupiter.api.extension.ConditionEvaluationResult import org.junit.jupiter.api.extension.ExecutionCondition import org.junit.jupiter.api.extension.ExtensionContext import org.junit.platform.commons.util.ReflectionUtils +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.lang.reflect.AnnotatedElement import java.util.* diff --git a/instrumentation/extensions/build.gradle.kts b/instrumentation/extensions/build.gradle.kts index 4866db3e..a4af274e 100644 --- a/instrumentation/extensions/build.gradle.kts +++ b/instrumentation/extensions/build.gradle.kts @@ -26,14 +26,14 @@ apply { plugin("de.mannodermaus.android-junit5") } -val javaVersion = JavaVersion.VERSION_1_8 +val javaVersion = JavaVersion.VERSION_11 android { + namespace = "de.mannodermaus.junit5.extensions" compileSdk = Android.compileSdkVersion defaultConfig { minSdk = Android.testRunnerMinSdkVersion - targetSdk = Android.targetSdkVersion } compileOptions { @@ -48,16 +48,18 @@ android { lint { // JUnit 4 refers to java.lang.management APIs, which are absent on Android. - warning("InvalidPackage") + warning.add("InvalidPackage") + targetSdk = Android.targetSdkVersion } - packagingOptions { + packaging { resources.excludes.add("META-INF/LICENSE.md") resources.excludes.add("META-INF/LICENSE-notice.md") } testOptions { unitTests.isReturnDefaultValues = true + targetSdk = Android.targetSdkVersion } } diff --git a/instrumentation/extensions/src/main/AndroidManifest.xml b/instrumentation/extensions/src/main/AndroidManifest.xml deleted file mode 100644 index 3b196a14..00000000 --- a/instrumentation/extensions/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/instrumentation/extensions/src/main/kotlin/de/mannodermaus/junit5/extensions/GrantPermissionExtension.kt b/instrumentation/extensions/src/main/kotlin/de/mannodermaus/junit5/extensions/GrantPermissionExtension.kt index ff5e905a..0f88f75f 100644 --- a/instrumentation/extensions/src/main/kotlin/de/mannodermaus/junit5/extensions/GrantPermissionExtension.kt +++ b/instrumentation/extensions/src/main/kotlin/de/mannodermaus/junit5/extensions/GrantPermissionExtension.kt @@ -1,8 +1,10 @@ package de.mannodermaus.junit5.extensions import android.Manifest +import android.annotation.SuppressLint import android.os.Build import androidx.annotation.VisibleForTesting +import androidx.test.annotation.ExperimentalTestApi import androidx.test.internal.platform.ServiceLoaderWrapper.loadSingleService import androidx.test.internal.platform.content.PermissionGranter import androidx.test.runner.permission.PermissionRequester @@ -23,6 +25,7 @@ import org.junit.jupiter.api.extension.ExtensionContext * Instrumentation. There is no way of revoking a permission after it was granted. Attempting to do * so will crash the Instrumentation process. */ +@SuppressLint("RestrictedApi") public class GrantPermissionExtension internal constructor(private val permissionGranter: PermissionGranter) : BeforeEachCallback { @@ -35,6 +38,7 @@ internal constructor(private val permissionGranter: PermissionGranter) : BeforeE * * @see android.Manifest.permission */ + @ExperimentalTestApi @JvmStatic public fun grant(vararg permissions: String): GrantPermissionExtension { val granter = loadSingleService(PermissionGranter::class.java, ::PermissionRequester) diff --git a/instrumentation/gradle.properties b/instrumentation/gradle.properties index a7150d00..772823f7 100644 --- a/instrumentation/gradle.properties +++ b/instrumentation/gradle.properties @@ -1,3 +1,2 @@ -android.useAndroidX = true -android.disableAutomaticComponentCreation = true -org.gradle.jvmargs = -XX:MaxMetaspaceSize=512m +android.useAndroidX = true +org.gradle.jvmargs = -XX:MaxMetaspaceSize=512m diff --git a/instrumentation/gradle/wrapper/gradle-wrapper.jar b/instrumentation/gradle/wrapper/gradle-wrapper.jar index 7454180f..e6441136 100644 Binary files a/instrumentation/gradle/wrapper/gradle-wrapper.jar and b/instrumentation/gradle/wrapper/gradle-wrapper.jar differ diff --git a/instrumentation/gradle/wrapper/gradle-wrapper.properties b/instrumentation/gradle/wrapper/gradle-wrapper.properties index ae04661e..b82aa23a 100644 --- a/instrumentation/gradle/wrapper/gradle-wrapper.properties +++ b/instrumentation/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/instrumentation/gradlew b/instrumentation/gradlew index 744e882e..1aa94a42 100755 --- a/instrumentation/gradlew +++ b/instrumentation/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,99 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/instrumentation/gradlew.bat b/instrumentation/gradlew.bat index ac1b06f9..7101f8e4 100644 --- a/instrumentation/gradlew.bat +++ b/instrumentation/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/instrumentation/runner/build.gradle.kts b/instrumentation/runner/build.gradle.kts index 85ee2982..31bbb01a 100644 --- a/instrumentation/runner/build.gradle.kts +++ b/instrumentation/runner/build.gradle.kts @@ -25,14 +25,14 @@ apply { plugin("de.mannodermaus.android-junit5") } -val javaVersion = JavaVersion.VERSION_1_8 +val javaVersion = JavaVersion.VERSION_11 android { + namespace = "de.mannodermaus.junit5.runner" compileSdk = Android.compileSdkVersion defaultConfig { minSdk = Android.testRunnerMinSdkVersion - targetSdk = Android.targetSdkVersion } compileOptions { @@ -47,16 +47,18 @@ android { lint { // JUnit 4 refers to java.lang.management APIs, which are absent on Android. - warning("InvalidPackage") + warning.add("InvalidPackage") + targetSdk = Android.targetSdkVersion } - packagingOptions { + packaging { resources.excludes.add("META-INF/LICENSE.md") resources.excludes.add("META-INF/LICENSE-notice.md") } testOptions { unitTests.isReturnDefaultValues = true + targetSdk = Android.targetSdkVersion } } diff --git a/instrumentation/runner/src/main/AndroidManifest.xml b/instrumentation/runner/src/main/AndroidManifest.xml deleted file mode 100644 index 2524cefb..00000000 --- a/instrumentation/runner/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformTestTree.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformTestTree.kt index e4c5f90a..3633947d 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformTestTree.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformTestTree.kt @@ -1,8 +1,11 @@ +@file:Suppress("DEPRECATION") + package de.mannodermaus.junit5.internal.runners import android.annotation.SuppressLint import de.mannodermaus.junit5.internal.extensions.isDynamicTest import org.junit.platform.commons.util.AnnotationUtils +import org.junit.platform.engine.UniqueId import org.junit.platform.engine.support.descriptor.ClassSource import org.junit.platform.engine.support.descriptor.MethodSource import org.junit.platform.launcher.TestIdentifier @@ -231,10 +234,20 @@ internal class AndroidJUnitPlatformTestTree( return delegate.getChildren(parent) } + override fun getChildren(parentId: UniqueId): MutableSet { + return delegate.getChildren(parentId) + } + + @Suppress("OVERRIDE_DEPRECATION") override fun getChildren(parentId: String): Set { return delegate.getChildren(parentId) } + override fun getTestIdentifier(uniqueId: UniqueId): TestIdentifier { + return delegate.getTestIdentifier(uniqueId) + } + + @Suppress("OVERRIDE_DEPRECATION") override fun getTestIdentifier(uniqueId: String): TestIdentifier { return delegate.getTestIdentifier(uniqueId) } diff --git a/instrumentation/sample/build.gradle.kts b/instrumentation/sample/build.gradle.kts index 7805855b..03cf17e3 100644 --- a/instrumentation/sample/build.gradle.kts +++ b/instrumentation/sample/build.gradle.kts @@ -7,9 +7,10 @@ plugins { id("de.mannodermaus.android-junit5").version(Artifacts.Plugin.latestStableVersion) } -val javaVersion = JavaVersion.VERSION_1_8 +val javaVersion = JavaVersion.VERSION_11 android { + namespace = "de.mannodermaus.junit5.sample" compileSdk = Android.compileSdkVersion defaultConfig { @@ -24,6 +25,10 @@ android { testInstrumentationRunnerArguments["runnerBuilder"] = "de.mannodermaus.junit5.AndroidJUnit5Builder" testInstrumentationRunnerArguments["configurationParameters"] = "junit.jupiter.execution.parallel.enabled=true,junit.jupiter.execution.parallel.mode.default=concurrent" + buildFeatures { + buildConfig = true + } + buildConfigField("boolean", "MY_VALUE", "true") testOptions { diff --git a/instrumentation/sample/src/androidTest/AndroidManifest.xml b/instrumentation/sample/src/androidTest/AndroidManifest.xml index a4d58a25..390a64f2 100644 --- a/instrumentation/sample/src/androidTest/AndroidManifest.xml +++ b/instrumentation/sample/src/androidTest/AndroidManifest.xml @@ -1,5 +1,3 @@ - - + diff --git a/instrumentation/sample/src/main/AndroidManifest.xml b/instrumentation/sample/src/main/AndroidManifest.xml index 83bd13b3..9a3cbdbf 100644 --- a/instrumentation/sample/src/main/AndroidManifest.xml +++ b/instrumentation/sample/src/main/AndroidManifest.xml @@ -1,8 +1,14 @@ - + - - - + + + + + + + + diff --git a/instrumentation/sample/src/test/kotlin/de/mannodermaus/sample/ExampleKotlinTest.kt b/instrumentation/sample/src/test/kotlin/de/mannodermaus/sample/ExampleKotlinTest.kt index ffa81e92..093ca19b 100644 --- a/instrumentation/sample/src/test/kotlin/de/mannodermaus/sample/ExampleKotlinTest.kt +++ b/instrumentation/sample/src/test/kotlin/de/mannodermaus/sample/ExampleKotlinTest.kt @@ -108,7 +108,7 @@ class ExampleKotlinTest { @ParameterizedTest(name = "Upper case for {0}") @MethodSource("getNames") fun parameterizedMethodTest (names: Pair) { - assertEquals(names.second, names.first.toUpperCase()) + assertEquals(names.second, names.first.uppercase()) } @Nested @@ -129,10 +129,10 @@ class ExampleKotlinTest { return listOf( dynamicTest("Length of input") { assertEquals(18, input.length) }, dynamicTest("Lowercase of input") { - assertEquals("dynamic test input", input.toLowerCase()) + assertEquals("dynamic test input", input.lowercase()) }, dynamicTest("Uppercase of input") { - assertEquals("DYNAMIC TEST INPUT", input.toUpperCase()) + assertEquals("DYNAMIC TEST INPUT", input.uppercase()) }) } } diff --git a/instrumentation/testutil-reflect/src/main/kotlin/de/mannodermaus/junit5/testutil/reflect/Reflections.kt b/instrumentation/testutil-reflect/src/main/kotlin/de/mannodermaus/junit5/testutil/reflect/Reflections.kt index f4a37f02..bb4c86d7 100644 --- a/instrumentation/testutil-reflect/src/main/kotlin/de/mannodermaus/junit5/testutil/reflect/Reflections.kt +++ b/instrumentation/testutil-reflect/src/main/kotlin/de/mannodermaus/junit5/testutil/reflect/Reflections.kt @@ -1,4 +1,4 @@ -@file:Suppress("removal") +@file:Suppress("removal", "DEPRECATION") package de.mannodermaus.junit5.testutil.reflect diff --git a/instrumentation/testutil/build.gradle.kts b/instrumentation/testutil/build.gradle.kts index be1d66e6..fc53f9db 100644 --- a/instrumentation/testutil/build.gradle.kts +++ b/instrumentation/testutil/build.gradle.kts @@ -7,14 +7,14 @@ plugins { kotlin("android") } -val javaVersion = JavaVersion.VERSION_1_8 +val javaVersion = JavaVersion.VERSION_11 android { + namespace = "de.mannodermaus.junit5.testutil" compileSdk = Android.compileSdkVersion defaultConfig { minSdk = 4 - targetSdk = Android.targetSdkVersion } compileOptions { @@ -29,16 +29,18 @@ android { lint { // JUnit 4 refers to java.lang.management APIs, which are absent on Android. - warning("InvalidPackage") + warning.add("InvalidPackage") + targetSdk = Android.targetSdkVersion } - packagingOptions { + packaging { resources.excludes.add("META-INF/LICENSE.md") resources.excludes.add("META-INF/LICENSE-notice.md") } testOptions { unitTests.isReturnDefaultValues = true + targetSdk = Android.targetSdkVersion } } diff --git a/instrumentation/testutil/src/main/AndroidManifest.xml b/instrumentation/testutil/src/main/AndroidManifest.xml deleted file mode 100644 index d5e6cd78..00000000 --- a/instrumentation/testutil/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/instrumentation/testutil/src/main/kotlin/de/mannodermaus/junit5/testutil/StubInstrumentation.kt b/instrumentation/testutil/src/main/kotlin/de/mannodermaus/junit5/testutil/StubInstrumentation.kt index 13596719..e5652f4e 100644 --- a/instrumentation/testutil/src/main/kotlin/de/mannodermaus/junit5/testutil/StubInstrumentation.kt +++ b/instrumentation/testutil/src/main/kotlin/de/mannodermaus/junit5/testutil/StubInstrumentation.kt @@ -4,10 +4,10 @@ import android.annotation.SuppressLint import android.app.Instrumentation import android.content.Context import android.content.res.Resources -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.doThrow -import com.nhaarman.mockitokotlin2.mock +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.mock internal class StubInstrumentation : Instrumentation() { private val targetContext = createMockTargetContext() diff --git a/plugin/CHANGELOG.md b/plugin/CHANGELOG.md index 17651627..e98a0aa7 100644 --- a/plugin/CHANGELOG.md +++ b/plugin/CHANGELOG.md @@ -2,6 +2,9 @@ Change Log ========== ## Unreleased +- 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 ## 1.10.0.0 (2023-11-05) - JUnit 5.10.0 diff --git a/plugin/android-junit5/build.gradle.kts b/plugin/android-junit5/build.gradle.kts index 29bf090f..675f87f9 100644 --- a/plugin/android-junit5/build.gradle.kts +++ b/plugin/android-junit5/build.gradle.kts @@ -122,16 +122,6 @@ dependencies { testImplementation(libs.junitJupiterApi) testImplementation(libs.junitJupiterParams) testRuntimeOnly(libs.junitJupiterEngine) - - // Bugfix for missing service injection in Gradle tests - // FIXME Track progress here and remove once updated to Gradle 7.6 Stable - // https://github.com/gradle/gradle/issues/16774 - testRuntimeOnly( - files( - serviceOf().getModule("gradle-tooling-api-builders") - .classpath.asFiles.first() - ) - ) } project.configureDeployment(Artifacts.Plugin) diff --git a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/config/Constants.kt b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/config/Constants.kt index 95fdc8d3..478e078d 100644 --- a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/config/Constants.kt +++ b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/config/Constants.kt @@ -2,8 +2,8 @@ package de.mannodermaus.gradle.plugins.junit5.internal.config -internal const val MIN_REQUIRED_GRADLE_VERSION = "7.0" // When updating this, check buildSrc/Tasks.kt and update it there, too -internal const val MIN_REQUIRED_AGP_VERSION = "7.0.0" +internal const val MIN_REQUIRED_GRADLE_VERSION = "8.0" // When updating this, check buildSrc/Tasks.kt and update it there, too +internal const val MIN_REQUIRED_AGP_VERSION = "8.0.0" internal const val EXTENSION_NAME = "junitPlatform" diff --git a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/configureJUnit5.kt b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/configureJUnit5.kt index 4125abb0..77cb455c 100644 --- a/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/configureJUnit5.kt +++ b/plugin/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/internal/configureJUnit5.kt @@ -4,8 +4,8 @@ package de.mannodermaus.gradle.plugins.junit5.internal import com.android.build.api.dsl.CommonExtension import com.android.build.api.variant.Variant -import com.android.builder.core.VariantType.Companion.UNIT_TEST_PREFIX -import com.android.builder.core.VariantType.Companion.UNIT_TEST_SUFFIX +import com.android.builder.core.ComponentType.Companion.UNIT_TEST_PREFIX +import com.android.builder.core.ComponentType.Companion.UNIT_TEST_SUFFIX import de.mannodermaus.Libraries import de.mannodermaus.gradle.plugins.junit5.dsl.AndroidJUnitPlatformExtension import de.mannodermaus.gradle.plugins.junit5.internal.config.ANDROID_JUNIT5_RUNNER_BUILDER_CLASS @@ -95,13 +95,12 @@ private fun prepareUnitTests(project: Project, android: AndroidExtension) { val options = excludedPackagingOptions() try { - android.packagingOptions.resources.excludes.addAll(options) + android.packaging.resources.excludes.addAll(options) } catch (e: NoSuchMethodError) { // TODO Because of https://issuetracker.google.com/issues/263387063, // there is a breaking API change in AGP 8.x that causes a NoSuchMethodError // (renaming PackagingOptions to Packaging without any fallback). // Fall back to the old DSL when this happens - @Suppress("DEPRECATION") options.forEach(project.android.packagingOptions::exclude) } } diff --git a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/FunctionalTests.kt b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/FunctionalTests.kt index 6a6ab05d..d027f277 100644 --- a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/FunctionalTests.kt +++ b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/FunctionalTests.kt @@ -8,6 +8,7 @@ import de.mannodermaus.gradle.plugins.junit5.util.TestedAgp import de.mannodermaus.gradle.plugins.junit5.util.prettyPrint import de.mannodermaus.gradle.plugins.junit5.util.projects.FunctionalTestProjectCreator import de.mannodermaus.gradle.plugins.junit5.util.withPrunedPluginClasspath +import org.gradle.configurationcache.extensions.capitalized import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome @@ -146,7 +147,7 @@ class FunctionalTests { // Examples: // - buildType="debug", productFlavor=null --> ":testDebugUnitTest" // - buildType="debug", productFlavor="free" --> ":testFreeDebugUnitTest" - val taskName = ":test${productFlavor?.capitalize() ?: ""}${buildType.capitalize()}UnitTest" + val taskName = ":test${productFlavor?.capitalized() ?: ""}${buildType.capitalized()}UnitTest" // Perform assertions assertWithMessage("AGP Tests for '$taskName' did not match expectations") diff --git a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/VersionCheckerTests.kt b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/VersionCheckerTests.kt index b8fb67c8..f176bc48 100644 --- a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/VersionCheckerTests.kt +++ b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/VersionCheckerTests.kt @@ -14,17 +14,20 @@ import org.junit.jupiter.params.provider.CsvSource class VersionCheckerTests { @CsvSource( - "4.0.0-alpha01, false", + "7.0.0-alpha01, false", "7.0.0-alpha01, false", "7.0.0-beta01, false", "7.0.0-rc01, false", - "7.0.0, true", - "7.0.1, true", - "7.0.1-alpha01, true", - "7.1.0, true", - "7.1.0-beta01, true", - "7.2.0, true", - "7.3.0-rc01, true", + "7.0.0, false", + "8.0.0-beta01, false", + "8.0.0, true", + "8.0.1, true", + "8.0.1-alpha01, true", + "8.1.0, true", + "8.1.0-beta01, true", + "8.2.0, true", + "8.3.0-rc01, true", + "8.4.0-alpha05, true", ) @ParameterizedTest fun `check AGP compatibility`(version: String, compatible: Boolean) { diff --git a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/TestKitTruth.kt b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/TestKitTruth.kt index d745196d..33bb5310 100644 --- a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/TestKitTruth.kt +++ b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/TestKitTruth.kt @@ -1,6 +1,11 @@ package de.mannodermaus.gradle.plugins.junit5.util -import com.google.common.truth.* +import com.google.common.truth.Fact +import com.google.common.truth.FailureMetadata +import com.google.common.truth.IntegerSubject +import com.google.common.truth.StringSubject +import com.google.common.truth.Subject +import com.google.common.truth.Truth import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.BuildTask import org.gradle.testkit.runner.TaskOutcome @@ -8,40 +13,42 @@ import org.gradle.testkit.runner.TaskOutcome /* Methods */ fun assertThat(actual: BuildResult): BuildResultSubject = - Truth.assertAbout(::BuildResultSubject).that(actual) + Truth.assertAbout(::BuildResultSubject).that(actual) /* Types */ class BuildResultSubject( - metadata: FailureMetadata, - private val actual: BuildResult + metadata: FailureMetadata, + private val actual: BuildResult? ) : Subject(metadata, actual) { fun task(name: String): BuildTaskSubject = check("task()") - .about(::BuildTaskSubject) - .that(actual.task(name)) + .about(::BuildTaskSubject) + .that(actual?.task(name)) fun output(): BuildResultOutputSubject = check("output()") - .about(::BuildResultOutputSubject) - .that(actual.output) + .about(::BuildResultOutputSubject) + .that(actual?.output) } class BuildTaskSubject( - metadata: FailureMetadata, - private val actual: BuildTask + metadata: FailureMetadata, + private val actual: BuildTask? ) : Subject(metadata, actual) { fun hasOutcome(expected: TaskOutcome) = check("hasOutcome()") - .that(actual.outcome) - .isEqualTo(expected) + .that(actual?.outcome) + .isEqualTo(expected) } class BuildResultOutputSubject( - metadata: FailureMetadata, - private val actual: String + metadata: FailureMetadata, + private val actual: String? ) : StringSubject(metadata, actual) { fun ofTask(name: String): BuildTaskOutputSubject { + requireNotNull(actual) + val startIndex = actual.indexOf("> Task $name") if (startIndex == -1) { failWithActual(Fact.simpleFact("Task $name was not executed")) @@ -54,22 +61,24 @@ class BuildResultOutputSubject( val strippedOutput = actual.substring(startIndex, endIndex) return check("ofTask()") - .about(::BuildTaskOutputSubject) - .that(strippedOutput) + .about(::BuildTaskOutputSubject) + .that(strippedOutput) } } class BuildTaskOutputSubject( - metadata: FailureMetadata, - private val actual: String + metadata: FailureMetadata, + private val actual: String? ) : StringSubject(metadata, actual) { fun executedTestCount(): IntegerSubject { + requireNotNull(actual) + // Subtract 1 from the total count because the task name is also preceded by ">" val actualCount = actual.count { it == '>' } - 1 return check("executedTestCount()") - .withMessage("actual test count: $actualCount. full task output: $actual") - .that(actualCount) + .withMessage("actual test count: $actualCount. full task output: $actual") + .that(actualCount) } } diff --git a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/projects/PluginSpecProjectCreator.kt b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/projects/PluginSpecProjectCreator.kt index 2a0ae05a..f847d168 100644 --- a/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/projects/PluginSpecProjectCreator.kt +++ b/plugin/android-junit5/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/util/projects/PluginSpecProjectCreator.kt @@ -45,15 +45,15 @@ class PluginSpecProjectCreator(private val environment: TestEnvironment) { private var applyKotlinPlugin = false private val project = ProjectBuilder.builder() - .withParent(parent) - .run { - if (name != null) { - this.withName(name) - } - - build() + .withParent(parent) + .run { + if (name != null) { + this.withName(name) } + build() + } + fun asAndroidApplication() = setProjectTypeIfUnsetTo(Type.Application) fun asAndroidDynamicFeature() = setProjectTypeIfUnsetTo(Type.DynamicFeature) @@ -79,7 +79,7 @@ class PluginSpecProjectCreator(private val environment: TestEnvironment) { val manifestFile = project.file("src/main/AndroidManifest.xml") if (!manifestFile.exists()) { - manifestFile.writeText(androidManifestString()) + manifestFile.writeText("") } // Apply required plugins @@ -100,6 +100,7 @@ class PluginSpecProjectCreator(private val environment: TestEnvironment) { // Add default configuration try { project.android.compileSdkVersion(environment.compileSdkVersion) + project.android.namespace = appId if (projectType == Type.Application) { project.android.defaultConfig.apply { @@ -133,13 +134,5 @@ class PluginSpecProjectCreator(private val environment: TestEnvironment) { this.projectType = type } - - private fun androidManifestString() = - """ - - - """.trimIndent() } } diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 83560747..b40ca176 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -1,7 +1,6 @@ plugins { - id("io.github.gradle-nexus.publish-plugin").version("1.1.0") - id("com.github.ben-manes.versions").version("0.42.0") - id("org.jetbrains.kotlinx.binary-compatibility-validator").version("0.11.0") + id("io.github.gradle-nexus.publish-plugin").version("2.0.0") + id("org.jetbrains.kotlinx.binary-compatibility-validator").version("0.14.0") } buildscript { @@ -9,7 +8,6 @@ buildscript { google() mavenCentral() gradlePluginPortal() - jitpack() } dependencies {