Skip to content

Commit 562af69

Browse files
authored
Add apiguardian-api runtime dependency to satisfy ART's internal runtime annotation loader (#306)
Essentially, `@API` is added to most of the JUnit 5 annotations. This is an annotation from a library called "API Guardian", which declares a `RUNTIME` visibility. For Android specifically, this visibility makes it eligible for native annotation scanning when calling `Class.isAnnotationPresent()` on any of the JUnit 5 annotations with that meta-annotation. The problem is that JUnit Jupier declares its transitive dependency as "compile-only", causing `@API` to be absent at runtime. This creates a log statement every time an annotation is queried, causing very noisy logs. The fix is to submit API Guardian as a runtime-only dependency to the instrumentation core. Refs: https://github.com/junit-team/junit5/blob/70e33483530259edef1ab3c1ba12971ac3fc7db7/junit-platform-commons/src/main/java/org/junit/platform/commons/util/AnnotationUtils.java#L136C38-L136C57 https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/dex/dex_file_annotations.cc;l=780-781 Resolves #291.
1 parent 4c200a0 commit 562af69

File tree

3 files changed

+20
-0
lines changed

3 files changed

+20
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ object libs {
3838
const val junitVintageEngine = "org.junit.vintage:junit-vintage-engine:${versions.junitVintage}"
3939
const val junitPlatformCommons = "org.junit.platform:junit-platform-commons:${versions.junitPlatform}"
4040
const val junitPlatformRunner = "org.junit.platform:junit-platform-runner:${versions.junitPlatform}"
41+
const val apiguardianApi = "org.apiguardian:apiguardian-api:1.1.2"
4142

4243
const val composeBom = "androidx.compose:compose-bom:${versions.composeBom}"
4344
const val composeUi = "androidx.compose.ui:ui"

instrumentation/core/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ dependencies {
7676
runtimeOnly(libs.junitPlatformRunner)
7777
runtimeOnly(libs.junitJupiterEngine)
7878

79+
// This transitive dependency of JUnit 5 is required to be on the runtime classpath,
80+
// since otherwise ART will print noisy logs to console when trying to resolve any
81+
// of the annotations of JUnit 5 (see #291 for more info)
82+
runtimeOnly(libs.apiguardianApi)
83+
7984
androidTestImplementation(libs.junitJupiterApi)
8085
androidTestImplementation(libs.junitJupiterParams)
8186
androidTestImplementation(libs.espressoCore)

instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformRunnerListener.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import android.annotation.SuppressLint
44
import android.util.Log
55
import de.mannodermaus.junit5.internal.LOG_TAG
66
import org.junit.platform.engine.TestExecutionResult
7+
import org.junit.platform.engine.reporting.ReportEntry
78
import org.junit.platform.launcher.TestExecutionListener
89
import org.junit.platform.launcher.TestIdentifier
10+
import org.junit.platform.launcher.TestPlan
911
import org.junit.runner.Description
1012
import org.junit.runner.notification.Failure
1113
import org.junit.runner.notification.RunNotifier
@@ -19,6 +21,18 @@ internal class AndroidJUnitPlatformRunnerListener(
1921
private val notifier: RunNotifier
2022
) : TestExecutionListener {
2123

24+
override fun testPlanExecutionStarted(testPlan: TestPlan) {
25+
// No-op, but must be declared to avoid AbstractMethodError
26+
}
27+
28+
override fun testPlanExecutionFinished(testPlan: TestPlan) {
29+
// No-op, but must be declared to avoid AbstractMethodError
30+
}
31+
32+
override fun reportingEntryPublished(testIdentifier: TestIdentifier?, entry: ReportEntry?) {
33+
// No-op, but must be declared to avoid AbstractMethodError
34+
}
35+
2236
override fun executionStarted(testIdentifier: TestIdentifier) {
2337
val description = testTree.getDescription(testIdentifier)
2438
if (testIdentifier.isTest) {

0 commit comments

Comments
 (0)