Skip to content

Commit 86dce59

Browse files
authored
Introduce extensions module (#309)
* Add extensions module & introduce GrantPermissionExtension to it * Remove deployment switch for Compose vs non-Compose No longer needed since the minimum AGP has been bumped to 7 globally. To work around the enforced single version per project by the Nexus Publishing plugin, bump the Compose artifact to the same 1.4.0-SNAPSHOT line as the other instrumentation artifacts, f it
1 parent b51d126 commit 86dce59

File tree

12 files changed

+343
-75
lines changed

12 files changed

+343
-75
lines changed

.circleci/config.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defaults: &defaults
88
GRADLE_OPTS: -Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.daemon=false -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false
99

1010
cache_key: &cache_key
11-
key: jars-{{ checksum "plugin/build.gradle.kts" }}-{{ checksum "plugin/android-junit5/build.gradle.kts" }}-{{ checksum "plugin/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "instrumentation/build.gradle.kts" }}-{{ checksum "instrumentation/runner/build.gradle.kts" }}-{{ checksum "instrumentation/sample/build.gradle.kts" }}-{{ checksum "instrumentation/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "build-logic/src/main/kotlin/Environment.kt" }}-{{ checksum "build-logic/src/main/kotlin/Dependencies.kt" }}
11+
key: jars-{{ checksum "plugin/build.gradle.kts" }}-{{ checksum "plugin/android-junit5/build.gradle.kts" }}-{{ checksum "plugin/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "instrumentation/build.gradle.kts" }}-{{ checksum "instrumentation/core/build.gradle.kts" }}-{{ checksum "instrumentation/compose/build.gradle.kts" }}-{{ checksum "instrumentation/extensions/build.gradle.kts" }}-{{ checksum "instrumentation/runner/build.gradle.kts" }}-{{ checksum "instrumentation/sample/build.gradle.kts" }}-{{ checksum "instrumentation/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "build-logic/src/main/kotlin/Environment.kt" }}-{{ checksum "build-logic/src/main/kotlin/Dependencies.kt" }}
1212

1313
commands:
1414
construct_signing_key:
@@ -42,11 +42,12 @@ jobs:
4242
./gradlew assembleRelease :core:assembleDebug \
4343
:core:assembleDebugAndroidTest \
4444
:compose:assembleDebugAndroidTest \
45+
:extensions:assembleDebug \
4546
:runner:assembleDebug \
46-
:sample:assembleDebug --stacktrace
47+
:sample:assembleDebug --stacktrace
4748
- run:
4849
name: (Instrumentation) Test
49-
command: cd instrumentation && ./gradlew :core:check :runner:check :compose:check --stacktrace
50+
command: cd instrumentation && ./gradlew :core:check :extensions:check :runner:check :compose:check --stacktrace
5051

5152
- save_cache:
5253
<<: *cache_key
@@ -95,6 +96,9 @@ jobs:
9596
- store_artifacts:
9697
path: test-lab-results
9798
destination: instrumentation-core/test-lab-results
99+
- store_artifacts:
100+
path: instrumentation/extensions/build/reports
101+
destination: instrumentation-extensions
98102
- store_artifacts:
99103
path: instrumentation/runner/build/reports
100104
destination: instrumentation-runner
@@ -126,6 +130,9 @@ jobs:
126130
- store_artifacts:
127131
path: instrumentation/core/build/publications
128132
destination: instrumentation-core/publications/snapshots
133+
- store_artifacts:
134+
path: instrumentation/extensions/build/publications
135+
destination: instrumentation-extensions/publications/snapshots
129136
- store_artifacts:
130137
path: instrumentation/runner/build/publications
131138
destination: instrumentation-runner/publications/snapshots

build-logic/src/main/kotlin/Deployment.kt

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,6 @@ fun Project.configureDeployment(deployConfig: Deployed) {
2525
throw IllegalStateException("This method can not be called on the root project")
2626
}
2727

28-
// Deployment of modules needs to be conditionally locked.
29-
// If the project is set to Compose mode, only the Compose modules may be deployed.
30-
// On the other hand, if the project is set to Default mode, only the ordinary
31-
// instrumentation modules are deployed. This has to do with the restrictions
32-
// of the Nexus Publishing plugin, which must use the same group and version declaration
33-
// for all modules. It's impossible to use Version A for instrumentation modules and Version B
34-
// for Compose modules at the same time, hence this conditional.
35-
if (shouldSkipDeployment(deployConfig)) {
36-
return
37-
}
38-
3928
val credentials = DeployedCredentials(this)
4029

4130
// Configure root project (this only happens once
@@ -127,16 +116,6 @@ fun Project.configureDeployment(deployConfig: Deployed) {
127116

128117
/* Private */
129118

130-
private fun Project.shouldSkipDeployment(deployConfig: Deployed): Boolean {
131-
return if (this.isComposeIncluded) {
132-
// If Compose is included, any non-compose module should be skipped
133-
deployConfig != Artifacts.Instrumentation.Compose
134-
} else {
135-
// If Compose is disabled, any compose module should be skipped
136-
deployConfig == Artifacts.Instrumentation.Compose
137-
}
138-
}
139-
140119
private fun Project.configureRootDeployment(deployConfig: Deployed, credentials: DeployedCredentials) {
141120
if (this != rootProject) {
142121
throw IllegalStateException("This method can only be called on the root project")

build-logic/src/main/kotlin/Environment.kt

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import Platform.Android
22
import Platform.Java
33
import org.gradle.api.Project
44
import java.io.File
5-
import java.util.*
5+
import java.util.Properties
66

77
enum class SupportedAgp(
8-
val version: String,
9-
val gradle: String? = null
8+
val version: String,
9+
val gradle: String? = null
1010
) {
1111
AGP_7_0("7.0.4", gradle = "7.0.2"),
1212
AGP_7_1("7.1.3", gradle = "7.2"),
@@ -55,13 +55,13 @@ sealed class Platform(val name: String) {
5555
* containing all sorts of configuration related to Maven coordinates, for instance.
5656
*/
5757
class Deployed internal constructor(
58-
val platform: Platform,
59-
val groupId: String,
60-
val artifactId: String,
61-
val currentVersion: String,
62-
val latestStableVersion: String,
63-
val description: String,
64-
val license: String
58+
val platform: Platform,
59+
val groupId: String,
60+
val artifactId: String,
61+
val currentVersion: String,
62+
val latestStableVersion: String,
63+
val description: String,
64+
val license: String
6565
)
6666

6767
object Artifacts {
@@ -74,24 +74,24 @@ object Artifacts {
7474
* Return null if none can be found
7575
*/
7676
fun from(project: Project) =
77-
when (project.name) {
78-
"core" -> Instrumentation.Core
79-
"runner" -> Instrumentation.Runner
80-
"android-junit5" -> Plugin
81-
else -> null
82-
}
77+
when (project.name) {
78+
"core" -> Instrumentation.Core
79+
"runner" -> Instrumentation.Runner
80+
"android-junit5" -> Plugin
81+
else -> null
82+
}
8383

8484
/**
8585
* Gradle Plugin artifact
8686
*/
8787
val Plugin = Deployed(
88-
platform = Java,
89-
groupId = "de.mannodermaus.gradle.plugins",
90-
artifactId = "android-junit5",
91-
currentVersion = "1.10.0.0-SNAPSHOT",
92-
latestStableVersion = "1.9.3.0",
93-
license = license,
94-
description = "Unit Testing with JUnit 5 for Android."
88+
platform = Java,
89+
groupId = "de.mannodermaus.gradle.plugins",
90+
artifactId = "android-junit5",
91+
currentVersion = "1.10.0.0-SNAPSHOT",
92+
latestStableVersion = "1.9.3.0",
93+
license = license,
94+
description = "Unit Testing with JUnit 5 for Android."
9595
)
9696

9797
/**
@@ -103,30 +103,40 @@ object Artifacts {
103103
const val latestStableVersion = "1.3.0"
104104

105105
val Core = Deployed(
106-
platform = Android(minSdk = 14),
107-
groupId = groupId,
108-
artifactId = "android-test-core",
109-
currentVersion = currentVersion,
110-
latestStableVersion = latestStableVersion,
111-
license = license,
112-
description = "Extensions for instrumented Android tests with JUnit 5."
106+
platform = Android(minSdk = 14),
107+
groupId = groupId,
108+
artifactId = "android-test-core",
109+
currentVersion = currentVersion,
110+
latestStableVersion = latestStableVersion,
111+
license = license,
112+
description = "Extensions for instrumented Android tests with JUnit 5."
113+
)
114+
115+
val Extensions = Deployed(
116+
platform = Android(minSdk = 14),
117+
groupId = groupId,
118+
artifactId = "android-test-extensions",
119+
currentVersion = currentVersion,
120+
latestStableVersion = latestStableVersion,
121+
license = license,
122+
description = "Optional extensions for instrumented Android tests with JUnit 5."
113123
)
114124

115125
val Runner = Deployed(
116-
platform = Android(minSdk = 14),
117-
groupId = groupId,
118-
artifactId = "android-test-runner",
119-
currentVersion = currentVersion,
120-
latestStableVersion = latestStableVersion,
121-
license = license,
122-
description = "Runner for integration of instrumented Android tests with JUnit 5."
126+
platform = Android(minSdk = 14),
127+
groupId = groupId,
128+
artifactId = "android-test-runner",
129+
currentVersion = currentVersion,
130+
latestStableVersion = latestStableVersion,
131+
license = license,
132+
description = "Runner for integration of instrumented Android tests with JUnit 5."
123133
)
124134

125135
val Compose = Deployed(
126136
platform = Android(minSdk = 21),
127137
groupId = groupId,
128138
artifactId = "android-test-compose",
129-
currentVersion = "1.0.0-SNAPSHOT",
139+
currentVersion = currentVersion,
130140
latestStableVersion = "1.0.0-SNAPSHOT",
131141
license = license,
132142
description = "Extensions for Jetpack Compose tests with JUnit 5."
@@ -166,5 +176,5 @@ class DeployedCredentials(private val project: Project) {
166176
}
167177

168178
private fun Properties.getOrEnvvar(key: String): String? =
169-
getProperty(key, System.getenv(key))
179+
getProperty(key, System.getenv(key))
170180
}

build-logic/src/main/kotlin/Utilities.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,6 @@ fun Project.findLocalPluginJar(): File? {
7777
return localPluginJar
7878
}
7979

80-
/**
81-
* Returns whether or not the Compose library module is included in the project.
82-
* This depends on the presence of the :compose module, which is configured
83-
* in settings.gradle.
84-
*/
85-
val Project.isComposeIncluded: Boolean get() {
86-
return findProject(":compose") != null
87-
}
88-
8980
/* File */
9081

9182
/**

instrumentation/.idea/runConfigurations/Core__Run_Unit_Tests__Gradle_.xml renamed to instrumentation/.idea/runConfigurations/Extensions__Run_Unit_Tests__Gradle_.xml

Lines changed: 6 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

instrumentation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Change Log
88
- Only autoconfigure JUnit 5 for instrumentation tests when the user explicitly adds junit-jupiter-api as a dependency
99
- Prevent noisy logs in Logcat complaining about unresolvable annotation classes (#306)
1010
- Add support for parallel execution of non-UI instrumentation tests (#295)
11+
- Introduce `android-test-extensions` artifact with optional extensions, starting with a port of JUnit 4's `GrantPermissionRule` (#251)
1112

1213
## 1.3.0 (2021-09-17)
1314

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
public final class de/mannodermaus/junit5/extensions/GrantPermissionExtension : org/junit/jupiter/api/extension/BeforeEachCallback {
2+
public static final field Companion Lde/mannodermaus/junit5/extensions/GrantPermissionExtension$Companion;
3+
public fun beforeEach (Lorg/junit/jupiter/api/extension/ExtensionContext;)V
4+
public static final fun grant ([Ljava/lang/String;)Lde/mannodermaus/junit5/extensions/GrantPermissionExtension;
5+
}
6+
7+
public final class de/mannodermaus/junit5/extensions/GrantPermissionExtension$Companion {
8+
public final fun grant ([Ljava/lang/String;)Lde/mannodermaus/junit5/extensions/GrantPermissionExtension;
9+
}
10+
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import libs.plugins.android
2+
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
3+
import org.gradle.api.tasks.testing.logging.TestLogEvent
4+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
5+
6+
buildscript {
7+
repositories {
8+
google()
9+
mavenCentral()
10+
sonatypeSnapshots()
11+
}
12+
13+
dependencies {
14+
val latest = Artifacts.Plugin.latestStableVersion
15+
classpath("de.mannodermaus.gradle.plugins:android-junit5:$latest")
16+
}
17+
}
18+
19+
plugins {
20+
id("com.android.library")
21+
kotlin("android")
22+
id("explicit-api-mode")
23+
}
24+
25+
apply {
26+
plugin("de.mannodermaus.android-junit5")
27+
}
28+
29+
val javaVersion = JavaVersion.VERSION_1_8
30+
31+
android {
32+
compileSdk = Android.compileSdkVersion
33+
34+
defaultConfig {
35+
minSdk = Android.testRunnerMinSdkVersion
36+
targetSdk = Android.targetSdkVersion
37+
}
38+
39+
compileOptions {
40+
sourceCompatibility = javaVersion
41+
targetCompatibility = javaVersion
42+
}
43+
44+
buildFeatures {
45+
buildConfig = false
46+
resValues = false
47+
}
48+
49+
lint {
50+
// JUnit 4 refers to java.lang.management APIs, which are absent on Android.
51+
warning("InvalidPackage")
52+
}
53+
54+
packagingOptions {
55+
resources.excludes.add("META-INF/LICENSE.md")
56+
resources.excludes.add("META-INF/LICENSE-notice.md")
57+
}
58+
59+
testOptions {
60+
unitTests.isReturnDefaultValues = true
61+
}
62+
}
63+
64+
tasks.withType<KotlinCompile> {
65+
kotlinOptions.jvmTarget = javaVersion.toString()
66+
}
67+
68+
tasks.withType<Test> {
69+
failFast = true
70+
testLogging {
71+
events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
72+
exceptionFormat = TestExceptionFormat.FULL
73+
}
74+
}
75+
76+
configurations.all {
77+
// The Instrumentation Test Runner uses the plugin,
78+
// which in turn provides the Instrumentation Test Runner again -
79+
// that's kind of deep.
80+
// To avoid conflicts, prefer using the local classes
81+
// and exclude the dependency from being pulled in externally.
82+
exclude(module = Artifacts.Instrumentation.Extensions.artifactId)
83+
}
84+
85+
dependencies {
86+
implementation(libs.androidXTestRunner)
87+
implementation(libs.junitJupiterApi)
88+
89+
testImplementation(project(":testutil"))
90+
testRuntimeOnly(libs.junitJupiterEngine)
91+
}
92+
93+
project.configureDeployment(Artifacts.Instrumentation.Extensions)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<manifest package="de.mannodermaus.junit5.extensions"/>

0 commit comments

Comments
 (0)