diff --git a/README.md b/README.md index 15e2e670..f2a12426 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Depending on the Java requirements of the JUnit Framework version, these instrum that meet these requirements, however. These tests are ignored and their execution will be skipped on older devices. - JUnit 5 requires Java 8 and is only supported by devices running Android 8.0 (API 26) or newer -- JUnit 6 requires Java 17 and is only supported by devices running Android 15 (API 35) or newer +- **(Coming soon)** JUnit 6 requires Java 17 and is only supported by devices running Android 15 (API 35) or newer Before you can write instrumentation tests with JUnit Jupiter, make sure that your module is using the `androidx.test.runner.AndroidJUnitRunner` @@ -120,9 +120,11 @@ dependencies { By default, the plugin will make sure to use a compatible version of the instrumentation test libraries when it sets up the artifacts automatically. However, it is possible to choose a custom version instead via its DSL: +```kotlin junitPlatform { instrumentationTests.version.set("1.9.0") } +``` ## Official Support diff --git a/README.md.template b/README.md.template index fbec7198..8982043f 100644 --- a/README.md.template +++ b/README.md.template @@ -58,7 +58,7 @@ Depending on the Java requirements of the JUnit Framework version, these instrum that meet these requirements, however. These tests are ignored and their execution will be skipped on older devices. - JUnit 5 requires Java 8 and is only supported by devices running Android 8.0 (API 26) or newer -- JUnit 6 requires Java 17 and is only supported by devices running Android 15 (API 35) or newer +- **(Coming soon)** JUnit 6 requires Java 17 and is only supported by devices running Android 15 (API 35) or newer Before you can write instrumentation tests with JUnit Jupiter, make sure that your module is using the `androidx.test.runner.AndroidJUnitRunner` @@ -115,9 +115,11 @@ dependencies { By default, the plugin will make sure to use a compatible version of the instrumentation test libraries when it sets up the artifacts automatically. However, it is possible to choose a custom version instead via its DSL: +```kotlin junitPlatform { instrumentationTests.version.set("${instrumentationVersion}") } +``` ## Official Support diff --git a/build-logic/gradle/libs.versions.toml b/build-logic/gradle/libs.versions.toml index d529165f..59c8320c 100644 --- a/build-logic/gradle/libs.versions.toml +++ b/build-logic/gradle/libs.versions.toml @@ -19,6 +19,7 @@ korte = "2.4.12" kotlin = "2.3.0" kotlinBinaryCompValidator = "0.17.0" kotlinCoroutines = "1.10.2" +ktfmt = "0.25.0" mockitoCore = "5.16.0" mockitoKotlin = "5.4.0" nexusPublish = "2.0.0" @@ -37,6 +38,7 @@ dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-binarycompvalidator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "kotlinBinaryCompValidator" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +ktfmt = { id = "com.ncorti.ktfmt.gradle", version.ref = "ktfmt" } publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexusPublish" } shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } diff --git a/instrumentation/build.gradle.kts b/instrumentation/build.gradle.kts index c6732449..efed7b22 100644 --- a/instrumentation/build.gradle.kts +++ b/instrumentation/build.gradle.kts @@ -1,5 +1,6 @@ import com.android.build.api.dsl.LibraryExtension import com.android.build.gradle.BaseExtension +import com.ncorti.ktfmt.gradle.KtfmtExtension import extensions.capitalized import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent @@ -17,6 +18,7 @@ plugins { alias(libs.plugins.dokka).apply(false) alias(libs.plugins.kotlin.android).apply(false) alias(libs.plugins.kotlin.jvm).apply(false) + alias(libs.plugins.ktfmt).apply(false) alias(libs.plugins.kotlin.binarycompvalidator) alias(libs.plugins.publish) @@ -36,6 +38,12 @@ subprojects { val jvmTarget = JvmTarget.JVM_17 val javaVersion = JavaVersion.toVersion(jvmTarget.target) + // Configure code formatting + apply(plugin = "com.ncorti.ktfmt.gradle") + configure { + kotlinLangStyle() + } + // Configure Kotlin plugins.withType { tasks.withType>().configureEach { diff --git a/instrumentation/compose/build.gradle.kts b/instrumentation/compose/build.gradle.kts index 650b0ca4..04a32d7a 100644 --- a/instrumentation/compose/build.gradle.kts +++ b/instrumentation/compose/build.gradle.kts @@ -15,9 +15,7 @@ android { "de.mannodermaus.junit5.AndroidJUnitFrameworkBuilder" } - buildFeatures { - compose = true - } + buildFeatures { compose = true } } junitPlatform { diff --git a/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ClassComposeExtensionTests.kt b/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ClassComposeExtensionTests.kt index 278911d4..39f849b5 100644 --- a/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ClassComposeExtensionTests.kt +++ b/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ClassComposeExtensionTests.kt @@ -19,13 +19,7 @@ import org.junit.jupiter.params.provider.ValueSource @ExtendWith(AndroidComposeExtension::class) class ClassComposeExtensionTests { - @ValueSource( - strings = [ - "click me", - "touch me", - "jfc it actually works" - ] - ) + @ValueSource(strings = ["click me", "touch me", "jfc it actually works"]) @ParameterizedTest fun test(buttonLabel: String, extension: AndroidComposeExtension) = extension.use { @@ -34,9 +28,7 @@ class ClassComposeExtensionTests { var counter by remember { mutableStateOf(0) } Text(text = "Clicked: $counter") - Button(onClick = { counter++ }) { - Text(text = buttonLabel) - } + Button(onClick = { counter++ }) { Text(text = buttonLabel) } } } @@ -46,24 +38,23 @@ class ClassComposeExtensionTests { } @Test - fun anotherTest(extension: ComposeExtension) = extension.use { - setContent { - Column { - var showDetails by remember { mutableStateOf(false) } + fun anotherTest(extension: ComposeExtension) = + extension.use { + setContent { + Column { + var showDetails by remember { mutableStateOf(false) } - Text("Hello world") - if (showDetails) { - Text("Extra details") - } + Text("Hello world") + if (showDetails) { + Text("Extra details") + } - Button(onClick = { showDetails = !showDetails }) { - Text("click") + Button(onClick = { showDetails = !showDetails }) { Text("click") } } } - } - onNodeWithText("Extra details").assertDoesNotExist() - onNodeWithText("click").performClick() - onNodeWithText("Extra details").assertIsDisplayed() - } + onNodeWithText("Extra details").assertDoesNotExist() + onNodeWithText("click").performClick() + onNodeWithText("Extra details").assertIsDisplayed() + } } diff --git a/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ExistingActivityComposeExtensionTests.kt b/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ExistingActivityComposeExtensionTests.kt index 2d6dfa67..f0cf41f7 100644 --- a/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ExistingActivityComposeExtensionTests.kt +++ b/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/ExistingActivityComposeExtensionTests.kt @@ -19,18 +19,9 @@ class ExistingActivityComposeExtensionTests { @OptIn(ExperimentalTestApi::class) val extension = createAndroidComposeExtension() - @BeforeAll - fun beforeAll() = extension.use { - onNodeWithText("click").performClick() - } + @BeforeAll fun beforeAll() = extension.use { onNodeWithText("click").performClick() } - @BeforeEach - fun beforeEach() = extension.use { - onNodeWithText("click").performClick() - } + @BeforeEach fun beforeEach() = extension.use { onNodeWithText("click").performClick() } - @Test - fun test() = extension.use { - onNodeWithText("Clicked: 2").assertIsDisplayed() - } + @Test fun test() = extension.use { onNodeWithText("Clicked: 2").assertIsDisplayed() } } diff --git a/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/FieldComposeExtensionTests.kt b/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/FieldComposeExtensionTests.kt index 070c0333..3a1574bf 100644 --- a/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/FieldComposeExtensionTests.kt +++ b/instrumentation/compose/src/androidTest/java/de/mannodermaus/junit5/compose/FieldComposeExtensionTests.kt @@ -22,28 +22,21 @@ class FieldComposeExtensionTests { @OptIn(ExperimentalTestApi::class) val extension = createComposeExtension() - @ValueSource( - strings = [ - "click me", - "touch me", - "jfc it actually works" - ] - ) + @ValueSource(strings = ["click me", "touch me", "jfc it actually works"]) @ParameterizedTest - fun test(buttonLabel: String) = extension.use { - setContent { - Column { - var counter by remember { mutableStateOf(0) } + fun test(buttonLabel: String) = + extension.use { + setContent { + Column { + var counter by remember { mutableStateOf(0) } - Text(text = "Clicked: $counter") - Button(onClick = { counter++ }) { - Text(text = buttonLabel) + Text(text = "Clicked: $counter") + Button(onClick = { counter++ }) { Text(text = buttonLabel) } } } - } - onNodeWithText("Clicked: 0").assertIsDisplayed() - onNodeWithText(buttonLabel).performClick() - onNodeWithText("Clicked: 1").assertIsDisplayed() - } + onNodeWithText("Clicked: 0").assertIsDisplayed() + onNodeWithText(buttonLabel).performClick() + onNodeWithText("Clicked: 1").assertIsDisplayed() + } } diff --git a/instrumentation/compose/src/debug/java/de/mannodermaus/junit5/compose/ExistingActivity.kt b/instrumentation/compose/src/debug/java/de/mannodermaus/junit5/compose/ExistingActivity.kt index 41823d61..f44348db 100644 --- a/instrumentation/compose/src/debug/java/de/mannodermaus/junit5/compose/ExistingActivity.kt +++ b/instrumentation/compose/src/debug/java/de/mannodermaus/junit5/compose/ExistingActivity.kt @@ -20,9 +20,7 @@ public class ExistingActivity : ComponentActivity() { var counter by remember { mutableIntStateOf(0) } Text(text = "Clicked: $counter") - Button(onClick = { counter++ }) { - Text("click") - } + Button(onClick = { counter++ }) { Text("click") } } } } diff --git a/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/AndroidComposeExtension.kt b/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/AndroidComposeExtension.kt index b21ba917..4bc27779 100644 --- a/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/AndroidComposeExtension.kt +++ b/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/AndroidComposeExtension.kt @@ -18,9 +18,9 @@ import org.junit.jupiter.api.extension.ParameterResolver import org.junit.jupiter.api.extension.RegisterExtension /** - * Factory method to provide a JUnit 5 extension for Compose using its [RegisterExtension] API - * for field injection. Prefer this over [createAndroidComposeExtension] if you don't care - * about the specific activity class to use under the hood. + * Factory method to provide a JUnit 5 extension for Compose using its [RegisterExtension] API for + * field injection. Prefer this over [createAndroidComposeExtension] if you don't care about the + * specific activity class to use under the hood. * * ``` * class MyTests { @@ -35,62 +35,72 @@ public fun createComposeExtension(): ComposeExtension = createAndroidComposeExtension() /** - * Factory method to provide a JUnit 5 extension for Compose using its [RegisterExtension] API - * for field injection. Prefer this over [createComposeExtension] if your tests require a custom Activity. - * This is usually the case for tests where the Compose content is set by that Activity, instead of - * via [ComposeContext.setContent], provided through the extension. Make sure that you add the provided - * Activity to your app's manifest file. + * Factory method to provide a JUnit 5 extension for Compose using its [RegisterExtension] API for + * field injection. Prefer this over [createComposeExtension] if your tests require a custom + * Activity. This is usually the case for tests where the Compose content is set by that Activity, + * instead of via [ComposeContext.setContent], provided through the extension. Make sure that you + * add the provided Activity to your app's manifest file. */ @ExperimentalTestApi -public inline fun createAndroidComposeExtension(): AndroidComposeExtension { +public inline fun createAndroidComposeExtension(): + AndroidComposeExtension { return createAndroidComposeExtension(A::class.java) } /** - * Factory method to provide a JUnit 5 extension for Compose using its [RegisterExtension] API - * for field injection. Prefer this over [createComposeExtension] if your tests require a custom Activity. - * This is usually the case for tests where the Compose content is set by that Activity, instead of - * via [ComposeContext.setContent], provided through the extension. Make sure that you add the provided - * Activity to your app's manifest file. This variant allows you to provide a custom [ActivityScenario] - * which is useful in cases where you may want to launch an activity with a custom intent, for example. + * Factory method to provide a JUnit 5 extension for Compose using its [RegisterExtension] API for + * field injection. Prefer this over [createComposeExtension] if your tests require a custom + * Activity. This is usually the case for tests where the Compose content is set by that Activity, + * instead of via [ComposeContext.setContent], provided through the extension. Make sure that you + * add the provided Activity to your app's manifest file. This variant allows you to provide a + * custom [ActivityScenario] which is useful in cases where you may want to launch an activity with + * a custom intent, for example. */ @ExperimentalTestApi -public inline fun createAndroidComposeExtension(noinline scenarioSupplier: () -> ActivityScenario): AndroidComposeExtension { +public inline fun createAndroidComposeExtension( + noinline scenarioSupplier: () -> ActivityScenario +): AndroidComposeExtension { return createAndroidComposeExtension(A::class.java, scenarioSupplier) } /** - * Factory method to provide a JUnit 5 extension for Compose using its [RegisterExtension] API - * for field injection. Prefer this over [createComposeExtension] if your tests require a custom Activity. - * This is usually the case for tests where the Compose content is set by that Activity, instead of - * via [ComposeContext.setContent], provided through the extension. Make sure that you add the provided - * Activity to your app's manifest file. You may also provide an optional [ActivityScenario] supplier - * which is useful in cases where you may want to launch an activity with a custom intent,for example. + * Factory method to provide a JUnit 5 extension for Compose using its [RegisterExtension] API for + * field injection. Prefer this over [createComposeExtension] if your tests require a custom + * Activity. This is usually the case for tests where the Compose content is set by that Activity, + * instead of via [ComposeContext.setContent], provided through the extension. Make sure that you + * add the provided Activity to your app's manifest file. You may also provide an optional + * [ActivityScenario] supplier which is useful in cases where you may want to launch an activity + * with a custom intent,for example. */ @ExperimentalTestApi -public fun createAndroidComposeExtension(activityClass: Class, - scenarioSupplier: () -> ActivityScenario = { ActivityScenario.launch(activityClass) }): AndroidComposeExtension { +public fun createAndroidComposeExtension( + activityClass: Class, + scenarioSupplier: () -> ActivityScenario = { ActivityScenario.launch(activityClass) }, +): AndroidComposeExtension { return AndroidComposeExtension(scenarioSupplier) } /** - * A JUnit 5 [Extension] that allows you to test and control [Composable]s and application using Compose. - * The functionality of testing Compose is provided by means of the [runComposeTest] method, - * which receives a [ComposeContext] from which the test can be orchestrated. The test will block - * until the app or composable is idle, to ensure the tests are deterministic. + * A JUnit 5 [Extension] that allows you to test and control [Composable]s and application using + * Compose. The functionality of testing Compose is provided by means of the [runComposeTest] + * method, which receives a [ComposeContext] from which the test can be orchestrated. The test will + * block until the app or composable is idle, to ensure the tests are deterministic. * - * This extension can be added to any JUnit 5 class using the [ExtendWith] annotation, - * or registered globally through a configuration file. Alternatively, you can instantiate the extension - * in a field within the test class using any of the [createComposeExtension] or + * This extension can be added to any JUnit 5 class using the [ExtendWith] annotation, or registered + * globally through a configuration file. Alternatively, you can instantiate the extension in a + * field within the test class using any of the [createComposeExtension] or * [createAndroidComposeExtension] factory methods. */ @SuppressLint("NewApi") @OptIn(ExperimentalTestApi::class) public class AndroidComposeExtension -internal constructor( - private val scenarioSupplier: () -> ActivityScenario -) : ComposeExtension, BeforeEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, - AfterEachCallback, ParameterResolver { +internal constructor(private val scenarioSupplier: () -> ActivityScenario) : + ComposeExtension, + BeforeEachCallback, + BeforeTestExecutionCallback, + AfterTestExecutionCallback, + AfterEachCallback, + ParameterResolver { // Management of pending test operations private val pendingPrepareBlocks = mutableListOf Unit>() @@ -99,21 +109,18 @@ internal constructor( // Instantiated by JUnit 5 @Suppress("UNCHECKED_CAST", "unused") - internal constructor() : this( - scenarioSupplier = { - ActivityScenario.launch(ComponentActivity::class.java) as ActivityScenario - } - ) + internal constructor() : + this( + scenarioSupplier = { + ActivityScenario.launch(ComponentActivity::class.java) as ActivityScenario + } + ) public val scenario: ActivityScenario - get() = checkNotNull(_scenario) { - "Activity scenario could not be launched" - } + get() = checkNotNull(_scenario) { "Activity scenario could not be launched" } public val activity: A - get() = checkNotNull(environment?.test?.activity) { - "Host activity not found" - } + get() = checkNotNull(environment?.test?.activity) { "Host activity not found" } private var state = STATE_INIT @@ -136,7 +143,9 @@ internal constructor( } STATE_CALLED -> { - throw IllegalStateException("Only a single call to use() is allowed per @Test method") + throw IllegalStateException( + "Only a single call to use() is allowed per @Test method" + ) } else -> { @@ -150,9 +159,7 @@ internal constructor( override fun beforeEach(context: ExtensionContext) { state = STATE_INIT - environment = AndroidComposeUiTestEnvironment { - getActivityFromScenario(scenario) - } + environment = AndroidComposeUiTestEnvironment { getActivityFromScenario(scenario) } } /* BeforeTestExecutionCallback */ @@ -181,14 +188,14 @@ internal constructor( override fun supportsParameter( parameterContext: ParameterContext, - extensionContext: ExtensionContext + extensionContext: ExtensionContext, ): Boolean { return ComposeExtension::class.java.isAssignableFrom(parameterContext.parameter.type) } override fun resolveParameter( parameterContext: ParameterContext, - extensionContext: ExtensionContext + extensionContext: ExtensionContext, ): Any { return this } diff --git a/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/ComposeContext.kt b/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/ComposeContext.kt index 7d8e1f66..edc206a8 100644 --- a/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/ComposeContext.kt +++ b/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/ComposeContext.kt @@ -15,48 +15,58 @@ import androidx.compose.ui.test.waitUntilExactlyOneExists import androidx.compose.ui.test.waitUntilNodeCount import androidx.compose.ui.unit.Density -/** - * A context through which composable blocks can be orchestrated within a [ComposeExtension]. - */ +/** A context through which composable blocks can be orchestrated within a [ComposeExtension]. */ public sealed interface ComposeContext : SemanticsNodeInteractionsProvider { // Internal note: The below method list is a copy of `ComposeContentTestRule`, // preventing the viral spread of its ExperimentalTestApi annotation // into the consumer's codebase and separating it from JUnit 4's TestRule public val density: Density public val mainClock: MainTestClock + public fun runOnUiThread(action: () -> T): T + public fun runOnIdle(action: () -> T): T + public fun waitForIdle() + public suspend fun awaitIdle() + public fun waitUntil(timeoutMillis: Long = 1_000L, condition: () -> Boolean) + public fun waitUntil( conditionDescription: String, timeoutMillis: Long = 1_000L, - condition: () -> Boolean + condition: () -> Boolean, ) public fun waitUntilNodeCount( matcher: SemanticsMatcher, count: Int, - timeoutMillis: Long = 1_000L + timeoutMillis: Long = 1_000L, ) public fun waitUntilAtLeastOneExists(matcher: SemanticsMatcher, timeoutMillis: Long = 1_000L) + public fun waitUntilExactlyOneExists(matcher: SemanticsMatcher, timeoutMillis: Long = 1_000L) + public fun waitUntilDoesNotExist(matcher: SemanticsMatcher, timeoutMillis: Long = 1_000L) + public fun registerIdlingResource(idlingResource: IdlingResource) + public fun unregisterIdlingResource(idlingResource: IdlingResource) + public fun setContent(composable: @Composable () -> Unit) } @OptIn(ExperimentalTestApi::class) -internal class ComposeContextImpl( - private val delegate: ComposeUiTest -) : ComposeContext, SemanticsNodeInteractionsProvider by delegate { +internal class ComposeContextImpl(private val delegate: ComposeUiTest) : + ComposeContext, SemanticsNodeInteractionsProvider by delegate { - override val density: Density get() = delegate.density + override val density: Density + get() = delegate.density - override val mainClock: MainTestClock get() = delegate.mainClock + override val mainClock: MainTestClock + get() = delegate.mainClock override fun runOnUiThread(action: () -> T): T = delegate.runOnUiThread(action) @@ -72,7 +82,7 @@ internal class ComposeContextImpl( override fun waitUntil( conditionDescription: String, timeoutMillis: Long, - condition: () -> Boolean + condition: () -> Boolean, ) { delegate.waitUntil(conditionDescription, timeoutMillis, condition) } @@ -97,12 +107,12 @@ internal class ComposeContextImpl( override fun onNode( matcher: SemanticsMatcher, - useUnmergedTree: Boolean + useUnmergedTree: Boolean, ): SemanticsNodeInteraction = delegate.onNode(matcher, useUnmergedTree) override fun onAllNodes( matcher: SemanticsMatcher, - useUnmergedTree: Boolean + useUnmergedTree: Boolean, ): SemanticsNodeInteractionCollection = delegate.onAllNodes(matcher, useUnmergedTree) override fun setContent(composable: @Composable () -> Unit) = delegate.setContent(composable) diff --git a/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/ComposeExtension.kt b/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/ComposeExtension.kt index a99e259d..abf277ee 100644 --- a/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/ComposeExtension.kt +++ b/instrumentation/compose/src/main/java/de/mannodermaus/junit5/compose/ComposeExtension.kt @@ -5,25 +5,25 @@ import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.Extension /** - * A JUnit 5 [Extension] that allows you to test and control [Composable]s and application using Compose. - * The functionality of testing Compose is provided by means of the [runComposeTest] method, - * which receives a [ComposeContext] from which the test can be orchestrated. The test will block - * until the app or composable is idle, to ensure the tests are deterministic. + * A JUnit 5 [Extension] that allows you to test and control [Composable]s and application using + * Compose. The functionality of testing Compose is provided by means of the [runComposeTest] + * method, which receives a [ComposeContext] from which the test can be orchestrated. The test will + * block until the app or composable is idle, to ensure the tests are deterministic. * - * This extension can be added to any JUnit 5 class using the [ExtendWith] annotation, - * or registered globally through a configuration file. Alternatively, you can instantiate the extension - * in a field within the test class using any of the [createComposeExtension] or + * This extension can be added to any JUnit 5 class using the [ExtendWith] annotation, or registered + * globally through a configuration file. Alternatively, you can instantiate the extension in a + * field within the test class using any of the [createComposeExtension] or * [createAndroidComposeExtension] factory methods. */ public interface ComposeExtension : Extension { /** - * Set up and drive the execution of a Compose test within the provided [block]. - * Depending on the time this is called, it will either queue up a preparatory action for the test - * (e.g. in @BeforeEach) - * The receive of this block is a [ComposeContext], through which you can access all sorts of - * utilities to drive the execution of the test, such as driving the clock or executing actions - * on the UI thread. The main purpose is provided through [ComposeContext.setContent], however: - * With this function, you can pass an arbitrary composable tree to the extension and evaluate it afterwards. + * Set up and drive the execution of a Compose test within the provided [block]. Depending on + * the time this is called, it will either queue up a preparatory action for the test (e.g. + * in @BeforeEach) The receive of this block is a [ComposeContext], through which you can access + * all sorts of utilities to drive the execution of the test, such as driving the clock or + * executing actions on the UI thread. The main purpose is provided through + * [ComposeContext.setContent], however: With this function, you can pass an arbitrary + * composable tree to the extension and evaluate it afterwards. */ public fun use(block: ComposeContext.() -> Unit) } diff --git a/instrumentation/compose/src/test/java/de/mannodermaus/junit5/compose/ComposeContextTests.kt b/instrumentation/compose/src/test/java/de/mannodermaus/junit5/compose/ComposeContextTests.kt index eed1072f..670dd7fb 100644 --- a/instrumentation/compose/src/test/java/de/mannodermaus/junit5/compose/ComposeContextTests.kt +++ b/instrumentation/compose/src/test/java/de/mannodermaus/junit5/compose/ComposeContextTests.kt @@ -2,10 +2,10 @@ package de.mannodermaus.junit5.compose import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.ComposeTestRule +import java.lang.reflect.Method import org.junit.jupiter.api.Assertions.fail import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource -import java.lang.reflect.Method class ComposeContextTests { companion object { diff --git a/instrumentation/core/build.gradle.kts b/instrumentation/core/build.gradle.kts index df4cfb17..bc39abe8 100644 --- a/instrumentation/core/build.gradle.kts +++ b/instrumentation/core/build.gradle.kts @@ -1,5 +1,3 @@ -import java.util.concurrent.atomic.AtomicBoolean - plugins { alias(libs.plugins.android.junit) alias(libs.plugins.android.library) diff --git a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/BaselineJUnit4Test.kt b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/BaselineJUnit4Test.kt index dfe1c9d0..22f38b97 100644 --- a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/BaselineJUnit4Test.kt +++ b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/BaselineJUnit4Test.kt @@ -4,14 +4,13 @@ import org.junit.Assert.assertEquals import org.junit.Test /** - * This JUnit 4 test class is here to validate - * that older device, which ignore JUnit 5 tests, - * still execute older ones. + * This JUnit 4 test class is here to validate that older device, which ignore JUnit 5 tests, still + * execute older ones. */ class BaselineJUnit4Test { - @Test - fun run() { - assertEquals(4, 2 + 2) - } + @Test + fun run() { + assertEquals(4, 2 + 2) + } } diff --git a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/KotlinInstrumentationTests.kt b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/KotlinInstrumentationTests.kt index 4f8125a5..8ca8c76d 100644 --- a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/KotlinInstrumentationTests.kt +++ b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/KotlinInstrumentationTests.kt @@ -18,50 +18,33 @@ import org.junit.jupiter.params.provider.ValueSource internal class KotlinInstrumentationTests { - @JvmField - @RegisterExtension - val scenarioExtension = ActivityScenarioExtension.launch() + @JvmField + @RegisterExtension + val scenarioExtension = ActivityScenarioExtension.launch() - @Test - fun testUsingGetScenario() { - val scenario = scenarioExtension.scenario - onView(withText("TestActivity")).check(matches(isDisplayed())) - scenario.onActivity { it.changeText("New Text") } - onView(withText("New Text")).check(matches(isDisplayed())) - } + @Test + fun testUsingGetScenario() { + val scenario = scenarioExtension.scenario + onView(withText("TestActivity")).check(matches(isDisplayed())) + scenario.onActivity { it.changeText("New Text") } + onView(withText("New Text")).check(matches(isDisplayed())) + } - @DisplayName("cool display name") - @Test - fun testWithDisplayName() { - } + @DisplayName("cool display name") @Test fun testWithDisplayName() {} - @Test - fun testUsingMethodParameter(scenario: ActivityScenario) { - onView(withText("TestActivity")).check(matches(isDisplayed())) - scenario.onActivity { it.changeText("New Text") } - onView(withText("New Text")).check(matches(isDisplayed())) - } + @Test + fun testUsingMethodParameter(scenario: ActivityScenario) { + onView(withText("TestActivity")).check(matches(isDisplayed())) + scenario.onActivity { it.changeText("New Text") } + onView(withText("New Text")).check(matches(isDisplayed())) + } - @ParameterizedTest - @ValueSource(ints = [1, 4, 6, 7]) - fun kotlinTestWithParameters(value: Int) { + @ParameterizedTest @ValueSource(ints = [1, 4, 6, 7]) fun kotlinTestWithParameters(value: Int) {} - } + @RepeatedTest(3) fun kotlinRepeatedTest(info: RepetitionInfo) {} - @RepeatedTest(3) - fun kotlinRepeatedTest(info: RepetitionInfo) { + @TestFactory + fun kotlinTestFactory() = listOf(dynamicTest("Dynamic 1") {}, dynamicTest("Dynamic 2") {}) - } - - @TestFactory - fun kotlinTestFactory() = listOf( - dynamicTest("Dynamic 1") {}, - dynamicTest("Dynamic 2") {} - ) - - @EnabledOnManufacturer(["Samsung"]) - @Test - fun onlyOnSamsung() { - - } + @EnabledOnManufacturer(["Samsung"]) @Test fun onlyOnSamsung() {} } diff --git a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/TaggedTests.kt b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/TaggedTests.kt index ea5a7508..00e308a8 100644 --- a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/TaggedTests.kt +++ b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/TaggedTests.kt @@ -5,9 +5,7 @@ import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test class TaggedTests { - @Test - fun includedTest() { - } + @Test fun includedTest() {} @Tag("nope") @Test diff --git a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/inheritance/KotlinInheritanceTests.kt b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/inheritance/KotlinInheritanceTests.kt index a0fd3ea7..5a26e131 100644 --- a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/inheritance/KotlinInheritanceTests.kt +++ b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/inheritance/KotlinInheritanceTests.kt @@ -31,5 +31,6 @@ class KotlinInterfaceTest : KotlinInterface { class KotlinMixedInterfaceTest : KotlinInterface, JavaInterface { override val kotlinValue: Int = 1337 + override fun getJavaValue(): Long = 1234L } diff --git a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/otherpackage/AnotherTest.kt b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/otherpackage/AnotherTest.kt index cee98af4..513a6bda 100644 --- a/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/otherpackage/AnotherTest.kt +++ b/instrumentation/core/src/androidTest/java/de/mannodermaus/junit5/otherpackage/AnotherTest.kt @@ -3,7 +3,5 @@ package de.mannodermaus.junit5.otherpackage import org.junit.jupiter.api.Test class AnotherTest { - @Test - fun anotherTest() { - } + @Test fun anotherTest() {} } diff --git a/instrumentation/core/src/debug/java/de/mannodermaus/junit5/TestActivity.kt b/instrumentation/core/src/debug/java/de/mannodermaus/junit5/TestActivity.kt index bf6ced5e..cdcff9d5 100644 --- a/instrumentation/core/src/debug/java/de/mannodermaus/junit5/TestActivity.kt +++ b/instrumentation/core/src/debug/java/de/mannodermaus/junit5/TestActivity.kt @@ -6,14 +6,14 @@ import android.widget.TextView internal class TestActivity : Activity() { - private val textView by lazy { findViewById(R.id.textView) } + private val textView by lazy { findViewById(R.id.textView) } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_test) - } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_test) + } - fun changeText(label: String) { - textView.text = label - } + fun changeText(label: String) { + textView.text = label + } } diff --git a/instrumentation/core/src/five/kotlin/de/mannodermaus/junit5/CoreConstants.kt b/instrumentation/core/src/five/kotlin/de/mannodermaus/junit5/CoreConstants.kt index b55eb448..3812b611 100644 --- a/instrumentation/core/src/five/kotlin/de/mannodermaus/junit5/CoreConstants.kt +++ b/instrumentation/core/src/five/kotlin/de/mannodermaus/junit5/CoreConstants.kt @@ -1,7 +1,7 @@ package de.mannodermaus.junit5 /** - * The minimum Android API level on which JUnit Framework tests may be executed. - * Trying to launch a test on an older device will simply mark it as 'skipped'. + * The minimum Android API level on which JUnit Framework tests may be executed. Trying to launch a + * test on an older device will simply mark it as 'skipped'. */ public const val JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION: Int = 26 diff --git a/instrumentation/core/src/five/kotlin/de/mannodermaus/junit5/internal/compat/ExtensionContextCompat.kt b/instrumentation/core/src/five/kotlin/de/mannodermaus/junit5/internal/compat/ExtensionContextCompat.kt index 98bd1096..0a2d9cdd 100644 --- a/instrumentation/core/src/five/kotlin/de/mannodermaus/junit5/internal/compat/ExtensionContextCompat.kt +++ b/instrumentation/core/src/five/kotlin/de/mannodermaus/junit5/internal/compat/ExtensionContextCompat.kt @@ -1,18 +1,18 @@ package de.mannodermaus.junit5.internal.compat -import org.junit.jupiter.api.extension.ExtensionContext import kotlin.reflect.KClass +import org.junit.jupiter.api.extension.ExtensionContext // JUnit 5 facade of ExtensionContext.Store APIs // that were deprecated/removed in subsequent versions of the framework. internal fun ExtensionContext.Store.computeIfAbsentCompat( key: K, - defaultCreator: (K) -> V + defaultCreator: (K) -> V, ): Any = getOrComputeIfAbsent(key, defaultCreator) internal fun ExtensionContext.Store.computeIfAbsentCompat( key: K, defaultCreator: (K) -> V, - requiredType: KClass + requiredType: KClass, ): V = getOrComputeIfAbsent(key, defaultCreator, requiredType.java) diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/ActivityScenarioExtension.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/ActivityScenarioExtension.kt index a4936c32..0912b31a 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/ActivityScenarioExtension.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/ActivityScenarioExtension.kt @@ -8,6 +8,8 @@ import androidx.test.core.app.ActivityScenario import de.mannodermaus.junit5.ActivityScenarioExtension.Companion.launch import de.mannodermaus.junit5.internal.LOG_TAG import de.mannodermaus.junit5.internal.compat.computeIfAbsentCompat +import java.lang.reflect.ParameterizedType +import java.util.concurrent.locks.ReentrantLock import org.junit.jupiter.api.extension.AfterEachCallback import org.junit.jupiter.api.extension.BeforeEachCallback import org.junit.jupiter.api.extension.ExtensionContext @@ -15,20 +17,17 @@ import org.junit.jupiter.api.extension.ParameterContext import org.junit.jupiter.api.extension.ParameterResolver import org.junit.jupiter.api.extension.RegisterExtension import org.junit.jupiter.api.parallel.ExecutionMode -import java.lang.reflect.ParameterizedType -import java.util.concurrent.locks.ReentrantLock /** - * JUnit 5 Extension for the [ActivityScenario] API, - * provided by the AndroidX test core library. + * JUnit 5 Extension for the [ActivityScenario] API, provided by the AndroidX test core library. * - * This extension is used in lieu of a JUnit 4 Rule to automatically - * launch/stop an [ActivityScenario] for each test case. + * This extension is used in lieu of a JUnit 4 Rule to automatically launch/stop an + * [ActivityScenario] for each test case. * - * To use this extension in your test class, add it as a non-private instance field - * to your test class, using one of the factory methods named [launch]. - * Then, annotate this field with JUnit Jupiter's [RegisterExtension] annotation. - * In Kotlin, also add [JvmField] or else the generated property won't be visible to the TestEngine! + * To use this extension in your test class, add it as a non-private instance field to your test + * class, using one of the factory methods named [launch]. Then, annotate this field with JUnit + * Jupiter's [RegisterExtension] annotation. In Kotlin, also add [JvmField] or else the generated + * property won't be visible to the TestEngine! * * ``` * // Java @@ -50,7 +49,6 @@ import java.util.concurrent.locks.ReentrantLock * In your test method, you can obtain a reference to the scenario in two ways: * * A) You obtain it from the extension directly through its accessor method: - * * ``` * // Java * class MyActivityTests { @@ -81,7 +79,6 @@ import java.util.concurrent.locks.ReentrantLock * ``` * * B) You add a parameter of type [ActivityScenario], with the activity class as its generic type: - * * ``` * // Java * class MyActivityTests { @@ -108,41 +105,44 @@ import java.util.concurrent.locks.ReentrantLock * } * } * ``` - * */ @RequiresApi(26) public class ActivityScenarioExtension -private constructor(private val scenarioSupplier: () -> ActivityScenario) : BeforeEachCallback, - AfterEachCallback, ParameterResolver { +private constructor(private val scenarioSupplier: () -> ActivityScenario) : + BeforeEachCallback, AfterEachCallback, ParameterResolver { public companion object { private const val WARNING_KEY = "de.mannodermaus.junit5.LogConcurrentExecutionWarning" private const val LOCK_KEY = "de.mannodermaus.junit5.SharedResourceLock" - private val NAMESPACE = - ExtensionContext.Namespace.create(ActivityScenarioExtension::class) + private val NAMESPACE = ExtensionContext.Namespace.create(ActivityScenarioExtension::class) /** - * Launches an activity of a given class and constructs an [ActivityScenario] for it. - * A default launch intent without specific extras is used to launch the activity. + * Launches an activity of a given class and constructs an [ActivityScenario] for it. A + * default launch intent without specific extras is used to launch the activity. */ @JvmStatic public fun launch(activityClass: Class): ActivityScenarioExtension = - ActivityScenarioExtension { ActivityScenario.launch(activityClass) } + ActivityScenarioExtension { + ActivityScenario.launch(activityClass) + } /** - * Launches an activity of a given class and constructs an [ActivityScenario] for it. - * The given intent is used to launch the activity. + * Launches an activity of a given class and constructs an [ActivityScenario] for it. The + * given intent is used to launch the activity. */ @JvmStatic - public fun launch(startActivityIntent: Intent): ActivityScenarioExtension = - ActivityScenarioExtension { ActivityScenario.launch(startActivityIntent) } + public fun launch( + startActivityIntent: Intent + ): ActivityScenarioExtension = ActivityScenarioExtension { + ActivityScenario.launch(startActivityIntent) + } /* Kotlin-specific convenience variations */ /** - * Launches an activity of a given class and constructs an [ActivityScenario] for it. - * A default launch intent without specific extras is used to launch the activity. + * Launches an activity of a given class and constructs an [ActivityScenario] for it. A + * default launch intent without specific extras is used to launch the activity. */ public inline fun launch(): ActivityScenarioExtension = launch(A::class.java) @@ -154,6 +154,7 @@ private constructor(private val scenarioSupplier: () -> ActivityScenario) : B /** * Returns the current [ActivityScenario] of the activity class. + * * @throws NullPointerException If this method is called while no test is running */ public val scenario: ActivityScenario @@ -179,17 +180,16 @@ private constructor(private val scenarioSupplier: () -> ActivityScenario) : B override fun supportsParameter( parameterContext: ParameterContext, - extensionContext: ExtensionContext + extensionContext: ExtensionContext, ): Boolean { // The extension can resolve ActivityScenario parameters that use the correct activity type. val paramType = parameterContext.parameter.parameterizedType - return paramType is ParameterizedType - && paramType.rawType == ActivityScenario::class.java + return paramType is ParameterizedType && paramType.rawType == ActivityScenario::class.java } override fun resolveParameter( parameterContext: ParameterContext, - extensionContext: ExtensionContext + extensionContext: ExtensionContext, ): Any = scenario /* Private */ @@ -208,11 +208,12 @@ private constructor(private val scenarioSupplier: () -> ActivityScenario) : B // Create a global lock for restricting test execution to one-by-one; // this is necessary to ensure that only one ActivityScenario is ever active at a time, // preventing violations of Android's instrumentation and Espresso - val lock = store.computeIfAbsentCompat( - key = LOCK_KEY, - defaultCreator = { ReentrantLock() }, - requiredType = ReentrantLock::class, - ) + val lock = + store.computeIfAbsentCompat( + key = LOCK_KEY, + defaultCreator = { ReentrantLock() }, + requiredType = ReentrantLock::class, + ) if (state) { lock.lock() @@ -224,16 +225,15 @@ private constructor(private val scenarioSupplier: () -> ActivityScenario) : B private fun logConcurrentExecutionWarningOnce(store: ExtensionContext.Store) { store.computeIfAbsentCompat(WARNING_KEY) { setOf( - " [WARNING!] UI tests using ActivityScenarioExtension should not be executed in CONCURRENT mode.", - " We will try to disable parallelism for Espresso tests, but this may be error-prone", - " (also, your execution times will look off). If you encounter issues, please consider", - " annotating your Espresso test classes to use the SAME_THREAD mode via the @Execution annotation!", - " --------------------------------------------------------------------", - " For more information, feel free to consult the JUnit 5 User Guide at:", - " https://junit.org/junit5/docs/current/user-guide/#writing-tests-parallel-execution-synchronization", - ).forEach { line -> - Log.e(LOG_TAG, line) - } + " [WARNING!] UI tests using ActivityScenarioExtension should not be executed in CONCURRENT mode.", + " We will try to disable parallelism for Espresso tests, but this may be error-prone", + " (also, your execution times will look off). If you encounter issues, please consider", + " annotating your Espresso test classes to use the SAME_THREAD mode via the @Execution annotation!", + " --------------------------------------------------------------------", + " For more information, feel free to consult the JUnit 5 User Guide at:", + " https://junit.org/junit5/docs/current/user-guide/#writing-tests-parallel-execution-synchronization", + ) + .forEach { line -> Log.e(LOG_TAG, line) } } } } diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/DeprecatedCoreConstants.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/DeprecatedCoreConstants.kt index 0efc4a31..1f1bc528 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/DeprecatedCoreConstants.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/DeprecatedCoreConstants.kt @@ -4,6 +4,6 @@ package de.mannodermaus.junit5 @Deprecated( message = "Renamed to JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION", - replaceWith = ReplaceWith("JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION") + replaceWith = ReplaceWith("JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION"), ) public const val JUNIT5_MINIMUM_SDK_VERSION: Int = JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValue.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValue.kt index 61c410d4..faa07a8a 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValue.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValue.kt @@ -6,7 +6,4 @@ import org.junit.jupiter.api.extension.ExtendWith @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @ExtendWith(DisabledIfBuildConfigValueCondition::class) -public annotation class DisabledIfBuildConfigValue( - val named: String, - val matches: String -) +public annotation class DisabledIfBuildConfigValue(val named: String, val matches: String) diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledOnManufacturer.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledOnManufacturer.kt index 06d24683..257acc10 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledOnManufacturer.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledOnManufacturer.kt @@ -8,5 +8,5 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(DisabledOnManufacturerCondition::class) public annotation class DisabledOnManufacturer( val value: Array, - val ignoreCase: Boolean = true + val ignoreCase: Boolean = true, ) diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersion.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersion.kt index 0434575a..44b58203 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersion.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersion.kt @@ -11,5 +11,5 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(DisabledOnSdkVersionCondition::class) public annotation class DisabledOnSdkVersion( @IntRange(from = JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION.toLong()) val from: Int = NOT_SET, - @IntRange(from = JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION.toLong()) val until: Int = NOT_SET + @IntRange(from = JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION.toLong()) val until: Int = NOT_SET, ) diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValue.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValue.kt index 03822d13..6ccb01ac 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValue.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValue.kt @@ -6,7 +6,4 @@ import org.junit.jupiter.api.extension.ExtendWith @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @ExtendWith(EnabledIfBuildConfigValueCondition::class) -public annotation class EnabledIfBuildConfigValue( - val named: String, - val matches: String -) +public annotation class EnabledIfBuildConfigValue(val named: String, val matches: String) diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledOnManufacturer.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledOnManufacturer.kt index 80487978..994f59ca 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledOnManufacturer.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledOnManufacturer.kt @@ -8,5 +8,5 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(EnabledOnManufacturerCondition::class) public annotation class EnabledOnManufacturer( val value: Array, - val ignoreCase: Boolean = true + val ignoreCase: Boolean = true, ) diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersion.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersion.kt index 09878c9c..82b64afa 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersion.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersion.kt @@ -11,5 +11,5 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(EnabledOnSdkVersionCondition::class) public annotation class EnabledOnSdkVersion( @IntRange(from = JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION.toLong()) val from: Int = NOT_SET, - @IntRange(from = JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION.toLong()) val until: Int = NOT_SET + @IntRange(from = JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION.toLong()) val until: Int = NOT_SET, ) diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledIfBuildConfigValueCondition.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledIfBuildConfigValueCondition.kt index 12dd30c3..6943128c 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledIfBuildConfigValueCondition.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledIfBuildConfigValueCondition.kt @@ -1,8 +1,8 @@ package de.mannodermaus.junit5.internal import androidx.annotation.RequiresApi -import de.mannodermaus.junit5.internal.utils.BuildConfigValueUtils import de.mannodermaus.junit5.condition.DisabledIfBuildConfigValue +import de.mannodermaus.junit5.internal.utils.BuildConfigValueUtils import org.junit.jupiter.api.extension.ConditionEvaluationResult import org.junit.jupiter.api.extension.ConditionEvaluationResult.disabled import org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled @@ -14,8 +14,7 @@ import org.junit.platform.commons.util.Preconditions internal class DisabledIfBuildConfigValueCondition : ExecutionCondition { companion object { - private val ENABLED_BY_DEFAULT = - enabled("@DisabledIfBuildConfigValue is not present") + private val ENABLED_BY_DEFAULT = enabled("@DisabledIfBuildConfigValue is not present") } @RequiresApi(24) @@ -27,16 +26,25 @@ internal class DisabledIfBuildConfigValueCondition : ExecutionCondition { val name = annotation.named.trim() val regexString = annotation.matches - Preconditions.notBlank(name) { "The 'named' attribute must not be blank in $annotation" } - Preconditions.notBlank(regexString) { "The 'matches' attribute must not be blank in $annotation" } + Preconditions.notBlank(name) { + "The 'named' attribute must not be blank in $annotation" + } + Preconditions.notBlank(regexString) { + "The 'matches' attribute must not be blank in $annotation" + } - val actual = runCatching { BuildConfigValueUtils.getAsString(name) }.getOrNull() - ?: return enabled("BuildConfig key [$name] does not exist") + val actual = + runCatching { BuildConfigValueUtils.getAsString(name) }.getOrNull() + ?: return enabled("BuildConfig key [$name] does not exist") return if (actual.matches(regexString.toRegex())) { - disabled("BuildConfig key [$name] with value [$actual] matches regular expression [$regexString]") + disabled( + "BuildConfig key [$name] with value [$actual] matches regular expression [$regexString]" + ) } else { - enabled("BuildConfig key [$name] with value [$actual] does not match regular expression [$regexString]") + enabled( + "BuildConfig key [$name] with value [$actual] does not match regular expression [$regexString]" + ) } } diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledOnManufacturerCondition.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledOnManufacturerCondition.kt index dd7a1ffb..118e6f49 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledOnManufacturerCondition.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledOnManufacturerCondition.kt @@ -1,7 +1,7 @@ package de.mannodermaus.junit5.internal -import androidx.annotation.RequiresApi import android.os.Build +import androidx.annotation.RequiresApi import de.mannodermaus.junit5.condition.DisabledOnManufacturer import de.mannodermaus.junit5.internal.EnabledOnManufacturerCondition.Companion.disabled import de.mannodermaus.junit5.internal.EnabledOnManufacturerCondition.Companion.enabled @@ -29,7 +29,7 @@ internal class DisabledOnManufacturerCondition : ExecutionCondition { Preconditions.condition( patterns.isNotEmpty(), - "You must declare at least one Manufacturer in @DisabledOnManufacturer" + "You must declare at least one Manufacturer in @DisabledOnManufacturer", ) return if (patterns.any { Build.MANUFACTURER.equals(it, ignoreCase = ignoreCase) }) { diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledOnSdkVersionCondition.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledOnSdkVersionCondition.kt index 649a0093..eb013fc0 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledOnSdkVersionCondition.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/DisabledOnSdkVersionCondition.kt @@ -1,7 +1,7 @@ package de.mannodermaus.junit5.internal -import androidx.annotation.RequiresApi import android.os.Build +import androidx.annotation.RequiresApi import de.mannodermaus.junit5.condition.DisabledOnSdkVersion import de.mannodermaus.junit5.internal.EnabledOnSdkVersionCondition.Companion.disabled import de.mannodermaus.junit5.internal.EnabledOnSdkVersionCondition.Companion.enabled @@ -30,11 +30,12 @@ internal class DisabledOnSdkVersionCondition : ExecutionCondition { val hasUpperBound = untilApi != NOT_SET Preconditions.condition( hasLowerBound || hasUpperBound, - "At least one value must be provided in @DisabledOnSdkVersion" + "At least one value must be provided in @DisabledOnSdkVersion", ) // Constrain the current API Level based on the presence of "fromApi" & "untilApi": - // If either one is not set at all, that part of the conditional becomes true automatically + // If either one is not set at all, that part of the conditional becomes true + // automatically val lowerCheck = !hasLowerBound || Build.VERSION.SDK_INT >= fromApi val upperCheck = !hasUpperBound || Build.VERSION.SDK_INT <= untilApi return if (lowerCheck && upperCheck) { diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledIfBuildConfigValueCondition.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledIfBuildConfigValueCondition.kt index 07e15f35..02ed4505 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledIfBuildConfigValueCondition.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledIfBuildConfigValueCondition.kt @@ -1,8 +1,8 @@ package de.mannodermaus.junit5.internal import androidx.annotation.RequiresApi -import de.mannodermaus.junit5.internal.utils.BuildConfigValueUtils import de.mannodermaus.junit5.condition.EnabledIfBuildConfigValue +import de.mannodermaus.junit5.internal.utils.BuildConfigValueUtils import org.junit.jupiter.api.extension.ConditionEvaluationResult import org.junit.jupiter.api.extension.ConditionEvaluationResult.disabled import org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled @@ -14,8 +14,7 @@ import org.junit.platform.commons.util.Preconditions internal class EnabledIfBuildConfigValueCondition : ExecutionCondition { companion object { - private val ENABLED_BY_DEFAULT = - enabled("@EnabledIfBuildConfigValue is not present") + private val ENABLED_BY_DEFAULT = enabled("@EnabledIfBuildConfigValue is not present") } @RequiresApi(24) @@ -27,16 +26,25 @@ internal class EnabledIfBuildConfigValueCondition : ExecutionCondition { val name = annotation.named.trim() val regexString = annotation.matches - Preconditions.notBlank(name) { "The 'named' attribute must not be blank in $annotation" } - Preconditions.notBlank(regexString) { "The 'matches' attribute must not be blank in $annotation" } + Preconditions.notBlank(name) { + "The 'named' attribute must not be blank in $annotation" + } + Preconditions.notBlank(regexString) { + "The 'matches' attribute must not be blank in $annotation" + } - val actual = runCatching { BuildConfigValueUtils.getAsString(name) }.getOrNull() - ?: return disabled("BuildConfig key [$name] does not exist") + val actual = + runCatching { BuildConfigValueUtils.getAsString(name) }.getOrNull() + ?: return disabled("BuildConfig key [$name] does not exist") return if (actual.matches(regexString.toRegex())) { - enabled("BuildConfig key [$name] with value [$actual] matches regular expression [$regexString]") + enabled( + "BuildConfig key [$name] with value [$actual] matches regular expression [$regexString]" + ) } else { - disabled("BuildConfig key [$name] with value [$actual] does not match regular expression [$regexString]") + disabled( + "BuildConfig key [$name] with value [$actual] does not match regular expression [$regexString]" + ) } } diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledOnManufacturerCondition.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledOnManufacturerCondition.kt index 5ab019bb..75e8bab0 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledOnManufacturerCondition.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledOnManufacturerCondition.kt @@ -1,7 +1,7 @@ package de.mannodermaus.junit5.internal -import androidx.annotation.RequiresApi import android.os.Build +import androidx.annotation.RequiresApi import de.mannodermaus.junit5.condition.EnabledOnManufacturer import org.junit.jupiter.api.extension.ConditionEvaluationResult import org.junit.jupiter.api.extension.ExecutionCondition @@ -16,11 +16,15 @@ internal class EnabledOnManufacturerCondition : ExecutionCondition { ConditionEvaluationResult.enabled("@EnabledOnManufacturer is not present") fun enabled(): ConditionEvaluationResult { - return ConditionEvaluationResult.enabled("Enabled on Manufacturer: " + Build.MANUFACTURER) + return ConditionEvaluationResult.enabled( + "Enabled on Manufacturer: " + Build.MANUFACTURER + ) } fun disabled(): ConditionEvaluationResult { - return ConditionEvaluationResult.disabled("Disabled on Manufacturer: " + Build.MANUFACTURER) + return ConditionEvaluationResult.disabled( + "Disabled on Manufacturer: " + Build.MANUFACTURER + ) } } @@ -35,7 +39,7 @@ internal class EnabledOnManufacturerCondition : ExecutionCondition { Preconditions.condition( patterns.isNotEmpty(), - "You must declare at least one Manufacturer in @EnabledOnManufacturer" + "You must declare at least one Manufacturer in @EnabledOnManufacturer", ) return if (patterns.any { Build.MANUFACTURER.equals(it, ignoreCase = ignoreCase) }) { diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledOnSdkVersionCondition.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledOnSdkVersionCondition.kt index 6d0a6839..dc3823a2 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledOnSdkVersionCondition.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/EnabledOnSdkVersionCondition.kt @@ -1,7 +1,7 @@ package de.mannodermaus.junit5.internal -import androidx.annotation.RequiresApi import android.os.Build +import androidx.annotation.RequiresApi import de.mannodermaus.junit5.condition.EnabledOnSdkVersion import org.junit.jupiter.api.extension.ConditionEvaluationResult import org.junit.jupiter.api.extension.ExecutionCondition @@ -36,11 +36,12 @@ internal class EnabledOnSdkVersionCondition : ExecutionCondition { val hasUpperBound = untilApi != NOT_SET Preconditions.condition( hasLowerBound || hasUpperBound, - "At least one value must be provided in @EnabledOnSdkVersion" + "At least one value must be provided in @EnabledOnSdkVersion", ) // Constrain the current API Level based on the presence of "fromApi" & "untilApi": - // If either one is not set at all, that part of the conditional becomes true automatically + // If either one is not set at all, that part of the conditional becomes true + // automatically val lowerCheck = !hasLowerBound || Build.VERSION.SDK_INT >= fromApi val upperCheck = !hasUpperBound || Build.VERSION.SDK_INT <= untilApi return if (lowerCheck && upperCheck) { diff --git a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/utils/BuildConfigValueUtils.kt b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/utils/BuildConfigValueUtils.kt index 4a3a9fbc..e2f5e638 100644 --- a/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/utils/BuildConfigValueUtils.kt +++ b/instrumentation/core/src/main/java/de/mannodermaus/junit5/internal/utils/BuildConfigValueUtils.kt @@ -19,11 +19,12 @@ internal object BuildConfigValueUtils { fun getValue(key: String): String? { return try { - fieldCache.getOrPut(key) { - buildConfigClass.getField(key).also { - it.isAccessible = true + fieldCache + .getOrPut(key) { + buildConfigClass.getField(key).also { it.isAccessible = true } } - }.get(null)?.toString() + .get(null) + ?.toString() } catch (ignored: Throwable) { throw IllegalAccessException("Cannot access BuildConfig field '$key'") } @@ -40,8 +41,9 @@ internal object BuildConfigValueUtils { } /** - * Reflectively look up a BuildConfig field's value. - * This caches previous lookups to maximize performance. + * Reflectively look up a BuildConfig field's value. This caches previous lookups to maximize + * performance. + * * @param key Key of the entry to obtain * @return The value of this entry, if any */ @@ -54,4 +56,4 @@ internal object BuildConfigValueUtils { throw IllegalAccessException("Cannot access BuildConfig field'$key'") } } -} \ No newline at end of file +} diff --git a/instrumentation/core/src/six/kotlin/de/mannodermaus/junit5/CoreConstants.kt b/instrumentation/core/src/six/kotlin/de/mannodermaus/junit5/CoreConstants.kt index bf6f6e8c..27dd1ed0 100644 --- a/instrumentation/core/src/six/kotlin/de/mannodermaus/junit5/CoreConstants.kt +++ b/instrumentation/core/src/six/kotlin/de/mannodermaus/junit5/CoreConstants.kt @@ -1,7 +1,7 @@ package de.mannodermaus.junit5 /** - * The minimum Android API level on which JUnit Framework tests may be executed. - * Trying to launch a test on an older device will simply mark it as 'skipped'. + * The minimum Android API level on which JUnit Framework tests may be executed. Trying to launch a + * test on an older device will simply mark it as 'skipped'. */ public const val JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION: Int = 35 diff --git a/instrumentation/core/src/six/kotlin/de/mannodermaus/junit5/internal/compat/ExtensionContextCompat.kt b/instrumentation/core/src/six/kotlin/de/mannodermaus/junit5/internal/compat/ExtensionContextCompat.kt index 2c1c9983..af5144ad 100644 --- a/instrumentation/core/src/six/kotlin/de/mannodermaus/junit5/internal/compat/ExtensionContextCompat.kt +++ b/instrumentation/core/src/six/kotlin/de/mannodermaus/junit5/internal/compat/ExtensionContextCompat.kt @@ -1,18 +1,18 @@ package de.mannodermaus.junit5.internal.compat -import org.junit.jupiter.api.extension.ExtensionContext import kotlin.reflect.KClass +import org.junit.jupiter.api.extension.ExtensionContext // JUnit 6 facade of ExtensionContext.Store APIs // that didn't exist in previous versions of the framework. internal fun ExtensionContext.Store.computeIfAbsentCompat( key: K, - defaultCreator: (K) -> V + defaultCreator: (K) -> V, ): Any = computeIfAbsent(key, defaultCreator) internal fun ExtensionContext.Store.computeIfAbsentCompat( key: K, defaultCreator: (K) -> V, - requiredType: KClass + requiredType: KClass, ): V = computeIfAbsent(key, defaultCreator, requiredType.java) 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 cabe47ee..e59cea27 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,6 +1,8 @@ package de.mannodermaus.junit5.condition import com.google.common.truth.Truth.assertThat +import java.lang.reflect.AnnotatedElement +import java.util.* import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.TestInfo @@ -10,50 +12,47 @@ 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.* abstract class AbstractExecutionConditionTests { - private val context = mock() - private var result: ConditionEvaluationResult? = null + private val context = mock() + private var result: ConditionEvaluationResult? = null - /* Lifecycle */ + /* Lifecycle */ - @BeforeEach - fun beforeEach(testInfo: TestInfo) { - whenever(context.element).thenReturn(method(testInfo)) - } + @BeforeEach + fun beforeEach(testInfo: TestInfo) { + whenever(context.element).thenReturn(method(testInfo)) + } - /* Abstract */ + /* Abstract */ - abstract fun getTestClass(): Class<*> + abstract fun getTestClass(): Class<*> - abstract fun getExecutionCondition(): ExecutionCondition + abstract fun getExecutionCondition(): ExecutionCondition - /* Protected */ + /* Protected */ - protected fun evaluateCondition() { - this.result = getExecutionCondition().evaluateExecutionCondition(context) - } + protected fun evaluateCondition() { + this.result = getExecutionCondition().evaluateExecutionCondition(context) + } - protected fun assertEnabled() { - assertTrue(!result!!.isDisabled, "Should be enabled") - } + protected fun assertEnabled() { + assertTrue(!result!!.isDisabled, "Should be enabled") + } - protected fun assertDisabled() { - assertTrue(result!!.isDisabled, "Should be disabled") - } + protected fun assertDisabled() { + assertTrue(result!!.isDisabled, "Should be disabled") + } - protected fun assertReasonEquals(text: String) { - assertThat(result!!.reason).hasValue(text) - } + protected fun assertReasonEquals(text: String) { + assertThat(result!!.reason).hasValue(text) + } - /* Private */ + /* Private */ - private fun method(testInfo: TestInfo) = - method(getTestClass(), testInfo.testMethod.get().name) + private fun method(testInfo: TestInfo) = method(getTestClass(), testInfo.testMethod.get().name) - private fun method(clazz: Class<*>, methodName: String): Optional = - Optional.of(ReflectionUtils.findMethod(clazz, methodName).get()) + private fun method(clazz: Class<*>, methodName: String): Optional = + Optional.of(ReflectionUtils.findMethod(clazz, methodName).get()) } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValueConditionTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValueConditionTests.kt index 9b1bf077..73d7c006 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValueConditionTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValueConditionTests.kt @@ -13,78 +13,71 @@ import org.junit.platform.commons.PreconditionViolationException /** * Unit tests for [DisabledIfBuildConfigValueCondition]. * - * This works together with [DisabledIfBuildConfigValueIntegrationTests]: The test methods - * in both classes MUST be named identical. + * This works together with [DisabledIfBuildConfigValueIntegrationTests]: The test methods in both + * classes MUST be named identical. */ @ResourceLock(RESOURCE_LOCK_INSTRUMENTATION) class DisabledIfBuildConfigValueConditionTests : AbstractExecutionConditionTests() { - override fun getExecutionCondition(): ExecutionCondition = - DisabledIfBuildConfigValueCondition() + override fun getExecutionCondition(): ExecutionCondition = DisabledIfBuildConfigValueCondition() - override fun getTestClass(): Class<*> = DisabledIfBuildConfigValueIntegrationTests::class.java + override fun getTestClass(): Class<*> = DisabledIfBuildConfigValueIntegrationTests::class.java - /** - * @see [DisabledIfBuildConfigValueIntegrationTests.invalidBecauseNameIsEmpty] - */ - @Test - fun invalidBecauseNameIsEmpty() { - withMockedInstrumentation { - val expected = assertThrows { - evaluateCondition() - } + /** @see [DisabledIfBuildConfigValueIntegrationTests.invalidBecauseNameIsEmpty] */ + @Test + fun invalidBecauseNameIsEmpty() { + withMockedInstrumentation { + val expected = assertThrows { evaluateCondition() } - assertThat(expected).hasMessageThat().contains("The 'named' attribute must not be blank in") + assertThat(expected) + .hasMessageThat() + .contains("The 'named' attribute must not be blank in") + } } - } - /** - * @see [DisabledIfBuildConfigValueIntegrationTests.invalidBecauseRegexIsEmpty] - */ - @Test - fun invalidBecauseRegexIsEmpty() { - withMockedInstrumentation { - val expected = assertThrows { - evaluateCondition() - } + /** @see [DisabledIfBuildConfigValueIntegrationTests.invalidBecauseRegexIsEmpty] */ + @Test + fun invalidBecauseRegexIsEmpty() { + withMockedInstrumentation { + val expected = assertThrows { evaluateCondition() } - assertThat(expected).hasMessageThat().contains("The 'matches' attribute must not be blank in") + assertThat(expected) + .hasMessageThat() + .contains("The 'matches' attribute must not be blank in") + } } - } - /** - * @see [DisabledIfBuildConfigValueIntegrationTests.disabledBecauseValueMatchesRegex] - */ - @Test - fun disabledBecauseValueMatchesRegex() { - withMockedInstrumentation { - evaluateCondition() - assertDisabled() - assertReasonEquals("BuildConfig key [DEBUG] with value [true] matches regular expression [\\w{4}]") + /** @see [DisabledIfBuildConfigValueIntegrationTests.disabledBecauseValueMatchesRegex] */ + @Test + fun disabledBecauseValueMatchesRegex() { + withMockedInstrumentation { + evaluateCondition() + assertDisabled() + assertReasonEquals( + "BuildConfig key [DEBUG] with value [true] matches regular expression [\\w{4}]" + ) + } } - } - /** - * @see [DisabledIfBuildConfigValueIntegrationTests.enabledBecauseValueDoesNotMatchRegex] - */ - @Test - fun enabledBecauseValueDoesNotMatchRegex() { - withMockedInstrumentation { - evaluateCondition() - assertEnabled() - assertReasonEquals("BuildConfig key [VERSION_NAME] with value [1.0] does not match regular expression [0.1.234]") + /** @see [DisabledIfBuildConfigValueIntegrationTests.enabledBecauseValueDoesNotMatchRegex] */ + @Test + fun enabledBecauseValueDoesNotMatchRegex() { + withMockedInstrumentation { + evaluateCondition() + assertEnabled() + assertReasonEquals( + "BuildConfig key [VERSION_NAME] with value [1.0] does not match regular expression [0.1.234]" + ) + } } - } - /** - * @see [DisabledIfBuildConfigValueIntegrationTests.enabledBecauseKeyDoesNotExist] - */ - @Test - fun enabledBecauseKeyDoesNotExist() { - withMockedInstrumentation { - evaluateCondition() - assertEnabled() - assertReasonEquals("BuildConfig key [NOT_EXISTENT_KEY] does not exist") + /** @see [DisabledIfBuildConfigValueIntegrationTests.enabledBecauseKeyDoesNotExist] */ + @Test + fun enabledBecauseKeyDoesNotExist() { + withMockedInstrumentation { + evaluateCondition() + assertEnabled() + assertReasonEquals("BuildConfig key [NOT_EXISTENT_KEY] does not exist") + } } - } } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValueIntegrationTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValueIntegrationTests.kt index 2d2807f1..988afcdc 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValueIntegrationTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledIfBuildConfigValueIntegrationTests.kt @@ -4,39 +4,34 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test /** - * Companion class for [DisabledIfBuildConfigValueConditionTests]. - * The tests in here are intentionally disabled; the partner class will - * drive them through reflection in order to assert the behavior of the condition + * Companion class for [DisabledIfBuildConfigValueConditionTests]. The tests in here are + * intentionally disabled; the partner class will drive them through reflection in order to assert + * the behavior of the condition */ class DisabledIfBuildConfigValueIntegrationTests { - @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") - @DisabledIfBuildConfigValue(named = "", matches = ".*") - @Test - fun invalidBecauseNameIsEmpty() { - } + @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") + @DisabledIfBuildConfigValue(named = "", matches = ".*") + @Test + fun invalidBecauseNameIsEmpty() {} - @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") - @DisabledIfBuildConfigValue(named = "DEBUG", matches = "") - @Test - fun invalidBecauseRegexIsEmpty() { - } + @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") + @DisabledIfBuildConfigValue(named = "DEBUG", matches = "") + @Test + fun invalidBecauseRegexIsEmpty() {} - @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") - @DisabledIfBuildConfigValue(named = "DEBUG", matches = "\\w{4}") - @Test - fun disabledBecauseValueMatchesRegex() { - } + @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") + @DisabledIfBuildConfigValue(named = "DEBUG", matches = "\\w{4}") + @Test + fun disabledBecauseValueMatchesRegex() {} - @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") - @DisabledIfBuildConfigValue(named = "VERSION_NAME", matches = "0.1.234") - @Test - fun enabledBecauseValueDoesNotMatchRegex() { - } + @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") + @DisabledIfBuildConfigValue(named = "VERSION_NAME", matches = "0.1.234") + @Test + fun enabledBecauseValueDoesNotMatchRegex() {} - @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") - @DisabledIfBuildConfigValue(named = "NOT_EXISTENT_KEY", matches = "whatever") - @Test - fun enabledBecauseKeyDoesNotExist() { - } + @Disabled("Used by DisabledIfBuildConfigValueConditionTests only") + @DisabledIfBuildConfigValue(named = "NOT_EXISTENT_KEY", matches = "whatever") + @Test + fun enabledBecauseKeyDoesNotExist() {} } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnManufacturerConditionTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnManufacturerConditionTests.kt index 20b1eed5..09f4c3d5 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnManufacturerConditionTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnManufacturerConditionTests.kt @@ -11,85 +11,74 @@ import org.junit.platform.commons.PreconditionViolationException /** * Unit tests for [DisabledOnManufacturerCondition]. * - * This works together with [DisabledOnManufacturerIntegrationTests]: The test methods - * in both classes MUST be named identical. + * This works together with [DisabledOnManufacturerIntegrationTests]: The test methods in both + * classes MUST be named identical. */ class DisabledOnManufacturerConditionTests : AbstractExecutionConditionTests() { - override fun getExecutionCondition(): ExecutionCondition = - DisabledOnManufacturerCondition() + override fun getExecutionCondition(): ExecutionCondition = DisabledOnManufacturerCondition() - override fun getTestClass(): Class<*> = DisabledOnManufacturerIntegrationTests::class.java + override fun getTestClass(): Class<*> = DisabledOnManufacturerIntegrationTests::class.java - /** - * @see [DisabledOnManufacturerIntegrationTests.invalidBecauseArrayIsEmpty] - */ - @Test - fun invalidBecauseArrayIsEmpty() { - val expected = assertThrows { - evaluateCondition() - } + /** @see [DisabledOnManufacturerIntegrationTests.invalidBecauseArrayIsEmpty] */ + @Test + fun invalidBecauseArrayIsEmpty() { + val expected = assertThrows { evaluateCondition() } - assertThat(expected).hasMessageThat().contains("You must declare at least one Manufacturer in @DisabledOnManufacturer") - } + assertThat(expected) + .hasMessageThat() + .contains("You must declare at least one Manufacturer in @DisabledOnManufacturer") + } - /** - * @see [DisabledOnManufacturerIntegrationTests.disabledBecauseValueMatchesExactly] - */ - @Test - fun disabledBecauseValueMatchesExactly() { - withManufacturer("Samsung") { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on Manufacturer: Samsung") + /** @see [DisabledOnManufacturerIntegrationTests.disabledBecauseValueMatchesExactly] */ + @Test + fun disabledBecauseValueMatchesExactly() { + withManufacturer("Samsung") { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on Manufacturer: Samsung") + } } - } - /** - * @see [DisabledOnManufacturerIntegrationTests.disabledBecauseValueIsAmongTheValues] - */ - @Test - fun disabledBecauseValueIsAmongTheValues() { - withManufacturer("Huawei") { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on Manufacturer: Huawei") + /** @see [DisabledOnManufacturerIntegrationTests.disabledBecauseValueIsAmongTheValues] */ + @Test + fun disabledBecauseValueIsAmongTheValues() { + withManufacturer("Huawei") { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on Manufacturer: Huawei") + } } - } - /** - * @see [DisabledOnManufacturerIntegrationTests.disabledBecauseValueMatchesWithOfIgnoreCase] - */ - @Test - fun disabledBecauseValueMatchesWithOfIgnoreCase() { - withManufacturer("Samsung") { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on Manufacturer: Samsung") + /** @see [DisabledOnManufacturerIntegrationTests.disabledBecauseValueMatchesWithOfIgnoreCase] */ + @Test + fun disabledBecauseValueMatchesWithOfIgnoreCase() { + withManufacturer("Samsung") { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on Manufacturer: Samsung") + } } - } - /** - * @see [DisabledOnManufacturerIntegrationTests.enabledBecauseValueDoesntMatchDueToIgnoreCase] - */ - @Test - fun enabledBecauseValueDoesntMatchDueToIgnoreCase() { - withManufacturer("Samsung") { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on Manufacturer: Samsung") + /** + * @see [DisabledOnManufacturerIntegrationTests.enabledBecauseValueDoesntMatchDueToIgnoreCase] + */ + @Test + fun enabledBecauseValueDoesntMatchDueToIgnoreCase() { + withManufacturer("Samsung") { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on Manufacturer: Samsung") + } } - } - /** - * @see [DisabledOnManufacturerIntegrationTests.enabledBecauseValueDoesntMatchAnyValue] - */ - @Test - fun enabledBecauseValueDoesntMatchAnyValue() { - withManufacturer("Google") { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on Manufacturer: Google") + /** @see [DisabledOnManufacturerIntegrationTests.enabledBecauseValueDoesntMatchAnyValue] */ + @Test + fun enabledBecauseValueDoesntMatchAnyValue() { + withManufacturer("Google") { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on Manufacturer: Google") + } } - } } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnManufacturerIntegrationTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnManufacturerIntegrationTests.kt index 45dd1cd1..65aab7af 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnManufacturerIntegrationTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnManufacturerIntegrationTests.kt @@ -4,45 +4,39 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test /** - * Companion class for [DisabledOnManufacturerConditionTests]. - * The tests in here are intentionally disabled; the partner class will - * drive them through reflection in order to assert the behavior of the condition + * Companion class for [DisabledOnManufacturerConditionTests]. The tests in here are intentionally + * disabled; the partner class will drive them through reflection in order to assert the behavior of + * the condition */ class DisabledOnManufacturerIntegrationTests { - @Disabled("Used by DisabledOnManufacturerConditionTests only") - @DisabledOnManufacturer([]) - @Test - fun invalidBecauseArrayIsEmpty() { - } - - @Disabled("Used by DisabledOnManufacturerConditionTests only") - @DisabledOnManufacturer(["Samsung"]) - @Test - fun disabledBecauseValueMatchesExactly() { - } - - @Disabled("Used by DisabledOnManufacturerConditionTests only") - @DisabledOnManufacturer(["Samsung", "Huawei"]) - @Test - fun disabledBecauseValueIsAmongTheValues() { - } - - @Disabled("Used by DisabledOnManufacturerConditionTests only") - @DisabledOnManufacturer(["sAmSuNg"]) - @Test - fun disabledBecauseValueMatchesWithOfIgnoreCase() { - } - - @Disabled("Used by DisabledOnManufacturerConditionTests only") - @DisabledOnManufacturer(["sAmSuNg"], ignoreCase = false) - @Test - fun enabledBecauseValueDoesntMatchDueToIgnoreCase() { - } - - @Disabled("Used by DisabledOnManufacturerConditionTests only") - @DisabledOnManufacturer(["Samsung", "Huawei"]) - @Test - fun enabledBecauseValueDoesntMatchAnyValue() { - } + @Disabled("Used by DisabledOnManufacturerConditionTests only") + @DisabledOnManufacturer([]) + @Test + fun invalidBecauseArrayIsEmpty() {} + + @Disabled("Used by DisabledOnManufacturerConditionTests only") + @DisabledOnManufacturer(["Samsung"]) + @Test + fun disabledBecauseValueMatchesExactly() {} + + @Disabled("Used by DisabledOnManufacturerConditionTests only") + @DisabledOnManufacturer(["Samsung", "Huawei"]) + @Test + fun disabledBecauseValueIsAmongTheValues() {} + + @Disabled("Used by DisabledOnManufacturerConditionTests only") + @DisabledOnManufacturer(["sAmSuNg"]) + @Test + fun disabledBecauseValueMatchesWithOfIgnoreCase() {} + + @Disabled("Used by DisabledOnManufacturerConditionTests only") + @DisabledOnManufacturer(["sAmSuNg"], ignoreCase = false) + @Test + fun enabledBecauseValueDoesntMatchDueToIgnoreCase() {} + + @Disabled("Used by DisabledOnManufacturerConditionTests only") + @DisabledOnManufacturer(["Samsung", "Huawei"]) + @Test + fun enabledBecauseValueDoesntMatchAnyValue() {} } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersionConditionTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersionConditionTests.kt index 3daa5bf6..b9a7c775 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersionConditionTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersionConditionTests.kt @@ -11,97 +11,82 @@ import org.junit.platform.commons.PreconditionViolationException /** * Unit tests for [DisabledOnSdkVersionCondition]. * - * This works together with [DisabledOnSdkVersionIntegrationTests]: The test methods - * in both classes MUST be named identical. + * This works together with [DisabledOnSdkVersionIntegrationTests]: The test methods in both classes + * MUST be named identical. */ class DisabledOnSdkVersionConditionTests : AbstractExecutionConditionTests() { - override fun getExecutionCondition(): ExecutionCondition = - DisabledOnSdkVersionCondition() + override fun getExecutionCondition(): ExecutionCondition = DisabledOnSdkVersionCondition() - override fun getTestClass(): Class<*> = DisabledOnSdkVersionIntegrationTests::class.java + override fun getTestClass(): Class<*> = DisabledOnSdkVersionIntegrationTests::class.java - /** - * @see [DisabledOnSdkVersionIntegrationTests.invalidBecauseNoValueGiven] - */ - @Test - fun invalidBecauseNoValueGiven() { - val expected = assertThrows { - evaluateCondition() - } + /** @see [DisabledOnSdkVersionIntegrationTests.invalidBecauseNoValueGiven] */ + @Test + fun invalidBecauseNoValueGiven() { + val expected = assertThrows { evaluateCondition() } - assertThat(expected).hasMessageThat().contains("At least one value must be provided in @DisabledOnSdkVersion") - } + assertThat(expected) + .hasMessageThat() + .contains("At least one value must be provided in @DisabledOnSdkVersion") + } - /** - * @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseMinApiIsMatched] - */ - @Test - fun disabledBecauseMinApiIsMatched() { - withApiLevel(26) { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on API 26") + /** @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseMinApiIsMatched] */ + @Test + fun disabledBecauseMinApiIsMatched() { + withApiLevel(26) { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on API 26") + } } - } - /** - * @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseMaxApiIsMatched] - */ - @Test - fun disabledBecauseMaxApiIsMatched() { - withApiLevel(24) { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on API 24") + /** @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseMaxApiIsMatched] */ + @Test + fun disabledBecauseMaxApiIsMatched() { + withApiLevel(24) { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on API 24") + } } - } - /** - * @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseApiIsInValidRange] - */ - @Test - fun disabledBecauseApiIsInValidRange() { - withApiLevel(26) { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on API 26") + /** @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseApiIsInValidRange] */ + @Test + fun disabledBecauseApiIsInValidRange() { + withApiLevel(26) { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on API 26") + } } - } - /** - * @see [DisabledOnSdkVersionIntegrationTests.enabledBecauseMinApiLowEnough] - */ - @Test - fun enabledBecauseMinApiLowEnough() { - withApiLevel(26) { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on API 26") + /** @see [DisabledOnSdkVersionIntegrationTests.enabledBecauseMinApiLowEnough] */ + @Test + fun enabledBecauseMinApiLowEnough() { + withApiLevel(26) { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on API 26") + } } - } - /** - * @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseMaxApiHighEnough] - */ - @Test - fun disabledBecauseMaxApiHighEnough() { - withApiLevel(29) { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on API 29") + /** @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseMaxApiHighEnough] */ + @Test + fun disabledBecauseMaxApiHighEnough() { + withApiLevel(29) { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on API 29") + } } - } - /** - * @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseApiIsInsideValidRange] - */ - @Test - fun disabledBecauseApiIsInsideValidRange() { - withApiLevel(28) { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on API 28") + /** @see [DisabledOnSdkVersionIntegrationTests.disabledBecauseApiIsInsideValidRange] */ + @Test + fun disabledBecauseApiIsInsideValidRange() { + withApiLevel(28) { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on API 28") + } } - } } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersionIntegrationTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersionIntegrationTests.kt index 6cef4f62..9c9a76e1 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersionIntegrationTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/DisabledOnSdkVersionIntegrationTests.kt @@ -4,51 +4,44 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test /** - * Companion class for [DisabledOnSdkVersionConditionTests]. - * The tests in here are intentionally disabled; the partner class will - * drive them through reflection in order to assert the behavior of the condition + * Companion class for [DisabledOnSdkVersionConditionTests]. The tests in here are intentionally + * disabled; the partner class will drive them through reflection in order to assert the behavior of + * the condition */ class DisabledOnSdkVersionIntegrationTests { - @Disabled("Used by DisabledOnSdkVersionConditionTests only") - @DisabledOnSdkVersion - @Test - fun invalidBecauseNoValueGiven() { - } - - @Disabled("Used by DisabledOnSdkVersionConditionTests only") - @DisabledOnSdkVersion(from = 24) - @Test - fun disabledBecauseMinApiIsMatched() { - } - - @Disabled("Used by DisabledOnSdkVersionConditionTests only") - @DisabledOnSdkVersion(until = 26) - @Test - fun disabledBecauseMaxApiIsMatched() { - } - - @Disabled("Used by DisabledOnSdkVersionConditionTests only") - @DisabledOnSdkVersion(from = 24, until = 29) - @Test - fun disabledBecauseApiIsInValidRange() { - } - - @Disabled("Used by DisabledOnSdkVersionConditionTests only") - @DisabledOnSdkVersion(from = 27) - @Test - fun enabledBecauseMinApiLowEnough() { - } - - @Disabled("Used by DisabledOnSdkVersionConditionTests only") - @DisabledOnSdkVersion(until = 27) - @Test - fun disabledBecauseMaxApiHighEnough() { - } - - @Disabled("Used by DisabledOnSdkVersionConditionTests only") - @DisabledOnSdkVersion(from = 27, until = 29) - @Test - fun disabledBecauseApiIsInsideValidRange() { - } + @Disabled("Used by DisabledOnSdkVersionConditionTests only") + @DisabledOnSdkVersion + @Test + fun invalidBecauseNoValueGiven() {} + + @Disabled("Used by DisabledOnSdkVersionConditionTests only") + @DisabledOnSdkVersion(from = 24) + @Test + fun disabledBecauseMinApiIsMatched() {} + + @Disabled("Used by DisabledOnSdkVersionConditionTests only") + @DisabledOnSdkVersion(until = 26) + @Test + fun disabledBecauseMaxApiIsMatched() {} + + @Disabled("Used by DisabledOnSdkVersionConditionTests only") + @DisabledOnSdkVersion(from = 24, until = 29) + @Test + fun disabledBecauseApiIsInValidRange() {} + + @Disabled("Used by DisabledOnSdkVersionConditionTests only") + @DisabledOnSdkVersion(from = 27) + @Test + fun enabledBecauseMinApiLowEnough() {} + + @Disabled("Used by DisabledOnSdkVersionConditionTests only") + @DisabledOnSdkVersion(until = 27) + @Test + fun disabledBecauseMaxApiHighEnough() {} + + @Disabled("Used by DisabledOnSdkVersionConditionTests only") + @DisabledOnSdkVersion(from = 27, until = 29) + @Test + fun disabledBecauseApiIsInsideValidRange() {} } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValueConditionTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValueConditionTests.kt index a772928d..85538f48 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValueConditionTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValueConditionTests.kt @@ -13,78 +13,71 @@ import org.junit.platform.commons.PreconditionViolationException /** * Unit tests for [EnabledIfBuildConfigValueCondition]. * - * This works together with [EnabledIfBuildConfigValueIntegrationTests]: The test methods - * in both classes MUST be named identical. + * This works together with [EnabledIfBuildConfigValueIntegrationTests]: The test methods in both + * classes MUST be named identical. */ @ResourceLock(RESOURCE_LOCK_INSTRUMENTATION) class EnabledIfBuildConfigValueConditionTests : AbstractExecutionConditionTests() { - override fun getExecutionCondition(): ExecutionCondition = - EnabledIfBuildConfigValueCondition() + override fun getExecutionCondition(): ExecutionCondition = EnabledIfBuildConfigValueCondition() - override fun getTestClass(): Class<*> = EnabledIfBuildConfigValueIntegrationTests::class.java + override fun getTestClass(): Class<*> = EnabledIfBuildConfigValueIntegrationTests::class.java - /** - * @see [EnabledIfBuildConfigValueIntegrationTests.invalidBecauseNameIsEmpty] - */ - @Test - fun invalidBecauseNameIsEmpty() { - withMockedInstrumentation { - val expected = assertThrows { - evaluateCondition() - } + /** @see [EnabledIfBuildConfigValueIntegrationTests.invalidBecauseNameIsEmpty] */ + @Test + fun invalidBecauseNameIsEmpty() { + withMockedInstrumentation { + val expected = assertThrows { evaluateCondition() } - assertThat(expected).hasMessageThat().contains("The 'named' attribute must not be blank in") + assertThat(expected) + .hasMessageThat() + .contains("The 'named' attribute must not be blank in") + } } - } - /** - * @see [EnabledIfBuildConfigValueIntegrationTests.invalidBecauseRegexIsEmpty] - */ - @Test - fun invalidBecauseRegexIsEmpty() { - withMockedInstrumentation { - val expected = assertThrows { - evaluateCondition() - } + /** @see [EnabledIfBuildConfigValueIntegrationTests.invalidBecauseRegexIsEmpty] */ + @Test + fun invalidBecauseRegexIsEmpty() { + withMockedInstrumentation { + val expected = assertThrows { evaluateCondition() } - assertThat(expected).hasMessageThat().contains("The 'matches' attribute must not be blank in") + assertThat(expected) + .hasMessageThat() + .contains("The 'matches' attribute must not be blank in") + } } - } - /** - * @see [EnabledIfBuildConfigValueIntegrationTests.enabledBecauseValueMatchesRegex] - */ - @Test - fun enabledBecauseValueMatchesRegex() { - withMockedInstrumentation { - evaluateCondition() - assertEnabled() - assertReasonEquals("BuildConfig key [DEBUG] with value [true] matches regular expression [\\w{4}]") + /** @see [EnabledIfBuildConfigValueIntegrationTests.enabledBecauseValueMatchesRegex] */ + @Test + fun enabledBecauseValueMatchesRegex() { + withMockedInstrumentation { + evaluateCondition() + assertEnabled() + assertReasonEquals( + "BuildConfig key [DEBUG] with value [true] matches regular expression [\\w{4}]" + ) + } } - } - /** - * @see [EnabledIfBuildConfigValueIntegrationTests.disabledBecauseValueDoesNotMatchRegex] - */ - @Test - fun disabledBecauseValueDoesNotMatchRegex() { - withMockedInstrumentation { - evaluateCondition() - assertDisabled() - assertReasonEquals("BuildConfig key [VERSION_NAME] with value [1.0] does not match regular expression [0.1.234]") + /** @see [EnabledIfBuildConfigValueIntegrationTests.disabledBecauseValueDoesNotMatchRegex] */ + @Test + fun disabledBecauseValueDoesNotMatchRegex() { + withMockedInstrumentation { + evaluateCondition() + assertDisabled() + assertReasonEquals( + "BuildConfig key [VERSION_NAME] with value [1.0] does not match regular expression [0.1.234]" + ) + } } - } - /** - * @see [EnabledIfBuildConfigValueIntegrationTests.disabledBecauseKeyDoesNotExist] - */ - @Test - fun disabledBecauseKeyDoesNotExist() { - withMockedInstrumentation { - evaluateCondition() - assertDisabled() - assertReasonEquals("BuildConfig key [NOT_EXISTENT_KEY] does not exist") + /** @see [EnabledIfBuildConfigValueIntegrationTests.disabledBecauseKeyDoesNotExist] */ + @Test + fun disabledBecauseKeyDoesNotExist() { + withMockedInstrumentation { + evaluateCondition() + assertDisabled() + assertReasonEquals("BuildConfig key [NOT_EXISTENT_KEY] does not exist") + } } - } } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValueIntegrationTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValueIntegrationTests.kt index fc7a798e..324c42ee 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValueIntegrationTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledIfBuildConfigValueIntegrationTests.kt @@ -4,39 +4,34 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test /** - * Companion class for [EnabledIfBuildConfigValueConditionTests]. - * The tests in here are intentionally disabled; the partner class will - * drive them through reflection in order to assert the behavior of the condition + * Companion class for [EnabledIfBuildConfigValueConditionTests]. The tests in here are + * intentionally disabled; the partner class will drive them through reflection in order to assert + * the behavior of the condition */ class EnabledIfBuildConfigValueIntegrationTests { - @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") - @EnabledIfBuildConfigValue(named = "", matches = ".*") - @Test - fun invalidBecauseNameIsEmpty() { - } + @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") + @EnabledIfBuildConfigValue(named = "", matches = ".*") + @Test + fun invalidBecauseNameIsEmpty() {} - @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") - @EnabledIfBuildConfigValue(named = "DEBUG", matches = "") - @Test - fun invalidBecauseRegexIsEmpty() { - } + @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") + @EnabledIfBuildConfigValue(named = "DEBUG", matches = "") + @Test + fun invalidBecauseRegexIsEmpty() {} - @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") - @EnabledIfBuildConfigValue(named = "DEBUG", matches = "\\w{4}") - @Test - fun enabledBecauseValueMatchesRegex() { - } + @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") + @EnabledIfBuildConfigValue(named = "DEBUG", matches = "\\w{4}") + @Test + fun enabledBecauseValueMatchesRegex() {} - @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") - @EnabledIfBuildConfigValue(named = "VERSION_NAME", matches = "0.1.234") - @Test - fun disabledBecauseValueDoesNotMatchRegex() { - } + @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") + @EnabledIfBuildConfigValue(named = "VERSION_NAME", matches = "0.1.234") + @Test + fun disabledBecauseValueDoesNotMatchRegex() {} - @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") - @EnabledIfBuildConfigValue(named = "NOT_EXISTENT_KEY", matches = "whatever") - @Test - fun disabledBecauseKeyDoesNotExist() { - } + @Disabled("Used by EnabledIfBuildConfigValueConditionTests only") + @EnabledIfBuildConfigValue(named = "NOT_EXISTENT_KEY", matches = "whatever") + @Test + fun disabledBecauseKeyDoesNotExist() {} } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnManufacturerConditionTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnManufacturerConditionTests.kt index dc931911..4c4f9c96 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnManufacturerConditionTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnManufacturerConditionTests.kt @@ -11,85 +11,74 @@ import org.junit.platform.commons.PreconditionViolationException /** * Unit tests for [EnabledOnManufacturerCondition]. * - * This works together with [EnabledOnManufacturerIntegrationTests]: The test methods - * in both classes MUST be named identical. + * This works together with [EnabledOnManufacturerIntegrationTests]: The test methods in both + * classes MUST be named identical. */ class EnabledOnManufacturerConditionTests : AbstractExecutionConditionTests() { - override fun getExecutionCondition(): ExecutionCondition = - EnabledOnManufacturerCondition() + override fun getExecutionCondition(): ExecutionCondition = EnabledOnManufacturerCondition() - override fun getTestClass(): Class<*> = EnabledOnManufacturerIntegrationTests::class.java + override fun getTestClass(): Class<*> = EnabledOnManufacturerIntegrationTests::class.java - /** - * @see [EnabledOnManufacturerIntegrationTests.invalidBecauseArrayIsEmpty] - */ - @Test - fun invalidBecauseArrayIsEmpty() { - val expected = assertThrows { - evaluateCondition() - } + /** @see [EnabledOnManufacturerIntegrationTests.invalidBecauseArrayIsEmpty] */ + @Test + fun invalidBecauseArrayIsEmpty() { + val expected = assertThrows { evaluateCondition() } - assertThat(expected).hasMessageThat().contains("You must declare at least one Manufacturer in @EnabledOnManufacturer") - } + assertThat(expected) + .hasMessageThat() + .contains("You must declare at least one Manufacturer in @EnabledOnManufacturer") + } - /** - * @see [EnabledOnManufacturerIntegrationTests.enabledBecauseValueMatchesExactly] - */ - @Test - fun enabledBecauseValueMatchesExactly() { - withManufacturer("Samsung") { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on Manufacturer: Samsung") + /** @see [EnabledOnManufacturerIntegrationTests.enabledBecauseValueMatchesExactly] */ + @Test + fun enabledBecauseValueMatchesExactly() { + withManufacturer("Samsung") { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on Manufacturer: Samsung") + } } - } - /** - * @see [EnabledOnManufacturerIntegrationTests.enabledBecauseValueIsAmongTheValues] - */ - @Test - fun enabledBecauseValueIsAmongTheValues() { - withManufacturer("Huawei") { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on Manufacturer: Huawei") + /** @see [EnabledOnManufacturerIntegrationTests.enabledBecauseValueIsAmongTheValues] */ + @Test + fun enabledBecauseValueIsAmongTheValues() { + withManufacturer("Huawei") { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on Manufacturer: Huawei") + } } - } - /** - * @see [EnabledOnManufacturerIntegrationTests.enabledBecauseValueMatchesWithOfIgnoreCase] - */ - @Test - fun enabledBecauseValueMatchesWithOfIgnoreCase() { - withManufacturer("Samsung") { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on Manufacturer: Samsung") + /** @see [EnabledOnManufacturerIntegrationTests.enabledBecauseValueMatchesWithOfIgnoreCase] */ + @Test + fun enabledBecauseValueMatchesWithOfIgnoreCase() { + withManufacturer("Samsung") { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on Manufacturer: Samsung") + } } - } - /** - * @see [EnabledOnManufacturerIntegrationTests.disabledBecauseValueDoesntMatchDueToIgnoreCase] - */ - @Test - fun disabledBecauseValueDoesntMatchDueToIgnoreCase() { - withManufacturer("Samsung") { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on Manufacturer: Samsung") + /** + * @see [EnabledOnManufacturerIntegrationTests.disabledBecauseValueDoesntMatchDueToIgnoreCase] + */ + @Test + fun disabledBecauseValueDoesntMatchDueToIgnoreCase() { + withManufacturer("Samsung") { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on Manufacturer: Samsung") + } } - } - /** - * @see [EnabledOnManufacturerIntegrationTests.disabledBecauseValueDoesntMatchAnyValue] - */ - @Test - fun disabledBecauseValueDoesntMatchAnyValue() { - withManufacturer("Google") { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on Manufacturer: Google") + /** @see [EnabledOnManufacturerIntegrationTests.disabledBecauseValueDoesntMatchAnyValue] */ + @Test + fun disabledBecauseValueDoesntMatchAnyValue() { + withManufacturer("Google") { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on Manufacturer: Google") + } } - } } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnManufacturerIntegrationTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnManufacturerIntegrationTests.kt index 146fa01a..4d1e0ab4 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnManufacturerIntegrationTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnManufacturerIntegrationTests.kt @@ -4,45 +4,39 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test /** - * Companion class for [EnabledOnManufacturerConditionTests]. - * The tests in here are intentionally disabled; the partner class will - * drive them through reflection in order to assert the behavior of the condition + * Companion class for [EnabledOnManufacturerConditionTests]. The tests in here are intentionally + * disabled; the partner class will drive them through reflection in order to assert the behavior of + * the condition */ class EnabledOnManufacturerIntegrationTests { - @Disabled("Used by EnabledOnManufacturerConditionTests only") - @EnabledOnManufacturer([]) - @Test - fun invalidBecauseArrayIsEmpty() { - } - - @Disabled("Used by EnabledOnManufacturerConditionTests only") - @EnabledOnManufacturer(["Samsung"]) - @Test - fun enabledBecauseValueMatchesExactly() { - } - - @Disabled("Used by EnabledOnManufacturerConditionTests only") - @EnabledOnManufacturer(["Samsung", "Huawei"]) - @Test - fun enabledBecauseValueIsAmongTheValues() { - } - - @Disabled("Used by EnabledOnManufacturerConditionTests only") - @EnabledOnManufacturer(["sAmSuNg"]) - @Test - fun enabledBecauseValueMatchesWithOfIgnoreCase() { - } - - @Disabled("Used by EnabledOnManufacturerConditionTests only") - @EnabledOnManufacturer(["sAmSuNg"], ignoreCase = false) - @Test - fun disabledBecauseValueDoesntMatchDueToIgnoreCase() { - } - - @Disabled("Used by EnabledOnManufacturerConditionTests only") - @EnabledOnManufacturer(["Samsung", "Huawei"]) - @Test - fun disabledBecauseValueDoesntMatchAnyValue() { - } + @Disabled("Used by EnabledOnManufacturerConditionTests only") + @EnabledOnManufacturer([]) + @Test + fun invalidBecauseArrayIsEmpty() {} + + @Disabled("Used by EnabledOnManufacturerConditionTests only") + @EnabledOnManufacturer(["Samsung"]) + @Test + fun enabledBecauseValueMatchesExactly() {} + + @Disabled("Used by EnabledOnManufacturerConditionTests only") + @EnabledOnManufacturer(["Samsung", "Huawei"]) + @Test + fun enabledBecauseValueIsAmongTheValues() {} + + @Disabled("Used by EnabledOnManufacturerConditionTests only") + @EnabledOnManufacturer(["sAmSuNg"]) + @Test + fun enabledBecauseValueMatchesWithOfIgnoreCase() {} + + @Disabled("Used by EnabledOnManufacturerConditionTests only") + @EnabledOnManufacturer(["sAmSuNg"], ignoreCase = false) + @Test + fun disabledBecauseValueDoesntMatchDueToIgnoreCase() {} + + @Disabled("Used by EnabledOnManufacturerConditionTests only") + @EnabledOnManufacturer(["Samsung", "Huawei"]) + @Test + fun disabledBecauseValueDoesntMatchAnyValue() {} } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersionConditionTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersionConditionTests.kt index ea72c6b1..1dded892 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersionConditionTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersionConditionTests.kt @@ -11,96 +11,82 @@ import org.junit.platform.commons.PreconditionViolationException /** * Unit tests for [EnabledOnSdkVersionCondition]. * - * This works together with [EnabledOnSdkVersionIntegrationTests]: The test methods - * in both classes MUST be named identical. + * This works together with [EnabledOnSdkVersionIntegrationTests]: The test methods in both classes + * MUST be named identical. */ class EnabledOnSdkVersionConditionTests : AbstractExecutionConditionTests() { - override fun getExecutionCondition(): ExecutionCondition = EnabledOnSdkVersionCondition() + override fun getExecutionCondition(): ExecutionCondition = EnabledOnSdkVersionCondition() - override fun getTestClass(): Class<*> = EnabledOnSdkVersionIntegrationTests::class.java + override fun getTestClass(): Class<*> = EnabledOnSdkVersionIntegrationTests::class.java - /** - * @see [EnabledOnSdkVersionIntegrationTests.invalidBecauseNoValueGiven] - */ - @Test - fun invalidBecauseNoValueGiven() { - val expected = assertThrows { - evaluateCondition() - } + /** @see [EnabledOnSdkVersionIntegrationTests.invalidBecauseNoValueGiven] */ + @Test + fun invalidBecauseNoValueGiven() { + val expected = assertThrows { evaluateCondition() } - assertThat(expected).hasMessageThat().contains("At least one value must be provided in @EnabledOnSdkVersion") - } + assertThat(expected) + .hasMessageThat() + .contains("At least one value must be provided in @EnabledOnSdkVersion") + } - /** - * @see [EnabledOnSdkVersionIntegrationTests.enabledBecauseMinApiIsMatched] - */ - @Test - fun enabledBecauseMinApiIsMatched() { - withApiLevel(26) { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on API 26") + /** @see [EnabledOnSdkVersionIntegrationTests.enabledBecauseMinApiIsMatched] */ + @Test + fun enabledBecauseMinApiIsMatched() { + withApiLevel(26) { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on API 26") + } } - } - /** - * @see [EnabledOnSdkVersionIntegrationTests.enabledBecauseMaxApiIsMatched] - */ - @Test - fun enabledBecauseMaxApiIsMatched() { - withApiLevel(24) { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on API 24") + /** @see [EnabledOnSdkVersionIntegrationTests.enabledBecauseMaxApiIsMatched] */ + @Test + fun enabledBecauseMaxApiIsMatched() { + withApiLevel(24) { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on API 24") + } } - } - /** - * @see [EnabledOnSdkVersionIntegrationTests.enabledBecauseApiIsInValidRange] - */ - @Test - fun enabledBecauseApiIsInValidRange() { - withApiLevel(26) { - evaluateCondition() - assertEnabled() - assertReasonEquals("Enabled on API 26") + /** @see [EnabledOnSdkVersionIntegrationTests.enabledBecauseApiIsInValidRange] */ + @Test + fun enabledBecauseApiIsInValidRange() { + withApiLevel(26) { + evaluateCondition() + assertEnabled() + assertReasonEquals("Enabled on API 26") + } } - } - /** - * @see [EnabledOnSdkVersionIntegrationTests.disabledBecauseMinApiTooLow] - */ - @Test - fun disabledBecauseMinApiTooLow() { - withApiLevel(26) { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on API 26") + /** @see [EnabledOnSdkVersionIntegrationTests.disabledBecauseMinApiTooLow] */ + @Test + fun disabledBecauseMinApiTooLow() { + withApiLevel(26) { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on API 26") + } } - } - /** - * @see [EnabledOnSdkVersionIntegrationTests.disabledBecauseMaxApiTooHigh] - */ - @Test - fun disabledBecauseMaxApiTooHigh() { - withApiLevel(29) { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on API 29") + /** @see [EnabledOnSdkVersionIntegrationTests.disabledBecauseMaxApiTooHigh] */ + @Test + fun disabledBecauseMaxApiTooHigh() { + withApiLevel(29) { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on API 29") + } } - } - /** - * @see [EnabledOnSdkVersionIntegrationTests.disabledBecauseApiIsOutsideValidRange] - */ - @Test - fun disabledBecauseApiIsOutsideValidRange() { - withApiLevel(26) { - evaluateCondition() - assertDisabled() - assertReasonEquals("Disabled on API 26") + /** @see [EnabledOnSdkVersionIntegrationTests.disabledBecauseApiIsOutsideValidRange] */ + @Test + fun disabledBecauseApiIsOutsideValidRange() { + withApiLevel(26) { + evaluateCondition() + assertDisabled() + assertReasonEquals("Disabled on API 26") + } } - } } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersionIntegrationTests.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersionIntegrationTests.kt index 64fce9c2..e4a77eff 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersionIntegrationTests.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/condition/EnabledOnSdkVersionIntegrationTests.kt @@ -4,51 +4,44 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test /** - * Companion class for [EnabledOnSdkVersionConditionTests]. - * The tests in here are intentionally disabled; the partner class will - * drive them through reflection in order to assert the behavior of the condition + * Companion class for [EnabledOnSdkVersionConditionTests]. The tests in here are intentionally + * disabled; the partner class will drive them through reflection in order to assert the behavior of + * the condition */ class EnabledOnSdkVersionIntegrationTests { - @Disabled("Used by EnabledOnSdkVersionConditionTests only") - @EnabledOnSdkVersion - @Test - fun invalidBecauseNoValueGiven() { - } - - @Disabled("Used by EnabledOnSdkVersionConditionTests only") - @EnabledOnSdkVersion(from = 24) - @Test - fun enabledBecauseMinApiIsMatched() { - } - - @Disabled("Used by EnabledOnSdkVersionConditionTests only") - @EnabledOnSdkVersion(until = 26) - @Test - fun enabledBecauseMaxApiIsMatched() { - } - - @Disabled("Used by EnabledOnSdkVersionConditionTests only") - @EnabledOnSdkVersion(from = 24, until = 29) - @Test - fun enabledBecauseApiIsInValidRange() { - } - - @Disabled("Used by EnabledOnSdkVersionConditionTests only") - @EnabledOnSdkVersion(from = 27) - @Test - fun disabledBecauseMinApiTooLow() { - } - - @Disabled("Used by EnabledOnSdkVersionConditionTests only") - @EnabledOnSdkVersion(until = 27) - @Test - fun disabledBecauseMaxApiTooHigh() { - } - - @Disabled("Used by EnabledOnSdkVersionConditionTests only") - @EnabledOnSdkVersion(from = 27, until = 29) - @Test - fun disabledBecauseApiIsOutsideValidRange() { - } + @Disabled("Used by EnabledOnSdkVersionConditionTests only") + @EnabledOnSdkVersion + @Test + fun invalidBecauseNoValueGiven() {} + + @Disabled("Used by EnabledOnSdkVersionConditionTests only") + @EnabledOnSdkVersion(from = 24) + @Test + fun enabledBecauseMinApiIsMatched() {} + + @Disabled("Used by EnabledOnSdkVersionConditionTests only") + @EnabledOnSdkVersion(until = 26) + @Test + fun enabledBecauseMaxApiIsMatched() {} + + @Disabled("Used by EnabledOnSdkVersionConditionTests only") + @EnabledOnSdkVersion(from = 24, until = 29) + @Test + fun enabledBecauseApiIsInValidRange() {} + + @Disabled("Used by EnabledOnSdkVersionConditionTests only") + @EnabledOnSdkVersion(from = 27) + @Test + fun disabledBecauseMinApiTooLow() {} + + @Disabled("Used by EnabledOnSdkVersionConditionTests only") + @EnabledOnSdkVersion(until = 27) + @Test + fun disabledBecauseMaxApiTooHigh() {} + + @Disabled("Used by EnabledOnSdkVersionConditionTests only") + @EnabledOnSdkVersion(from = 27, until = 29) + @Test + fun disabledBecauseApiIsOutsideValidRange() {} } diff --git a/instrumentation/core/src/test/java/de/mannodermaus/junit5/util/ResourceLocks.kt b/instrumentation/core/src/test/java/de/mannodermaus/junit5/util/ResourceLocks.kt index b23ba7c6..29c39b31 100644 --- a/instrumentation/core/src/test/java/de/mannodermaus/junit5/util/ResourceLocks.kt +++ b/instrumentation/core/src/test/java/de/mannodermaus/junit5/util/ResourceLocks.kt @@ -1,6 +1,4 @@ package de.mannodermaus.junit5.util -/** - * JUnit Jupiter resource locks, restricting parallelism of the test suite. - */ +/** JUnit Jupiter resource locks, restricting parallelism of the test suite. */ const val RESOURCE_LOCK_INSTRUMENTATION = "instrumentation" diff --git a/instrumentation/extensions/build.gradle.kts b/instrumentation/extensions/build.gradle.kts index 78f5642f..cd16206f 100644 --- a/instrumentation/extensions/build.gradle.kts +++ b/instrumentation/extensions/build.gradle.kts @@ -7,9 +7,7 @@ plugins { android { namespace = "de.mannodermaus.junit5.extensions" - defaultConfig { - minSdk = Android.testRunnerMinSdkVersion - } + defaultConfig { minSdk = Android.testRunnerMinSdkVersion } } dependencies { 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 ef65f627..e6b45937 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 @@ -2,8 +2,6 @@ package de.mannodermaus.junit5.extensions import android.Manifest import android.annotation.SuppressLint -import android.os.Build -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 @@ -12,16 +10,16 @@ import org.junit.jupiter.api.extension.BeforeEachCallback import org.junit.jupiter.api.extension.ExtensionContext /** - * The [GrantPermissionExtension] allows granting of runtime permissions before a test. - * Use this extension when a test requires a runtime permission to do its work. + * The [GrantPermissionExtension] allows granting of runtime permissions before a test. Use this + * extension when a test requires a runtime permission to do its work. * * This is a port of JUnit 4's GrantPermissionRule for JUnit 5. * - *

When applied to a test class it attempts to grant all requested runtime permissions. - * The requested permissions will then be granted on the device and will take immediate effect. - * Once a permission is granted it will apply for all tests running in the current Instrumentation. - * There is no way of revoking a permission after it was granted. - * Attempting to do so will crash the Instrumentation process. + *

When applied to a test class it attempts to grant all requested runtime permissions. The + * requested permissions will then be granted on the device and will take immediate effect. Once a + * permission is granted it will apply for all tests running in the current 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 @@ -40,9 +38,7 @@ internal constructor(private val permissionGranter: PermissionGranter) : BeforeE public fun grant(vararg permissions: String): GrantPermissionExtension { val granter = loadSingleService(PermissionGranter::class.java, ::PermissionRequester) - return GrantPermissionExtension(granter).also { - it.grantPermissions(permissions) - } + return GrantPermissionExtension(granter).also { it.grantPermissions(permissions) } } private fun satisfyPermissionDependencies(permissions: Array): Set { diff --git a/instrumentation/extensions/src/test/kotlin/de/mannodermaus/junit5/extensions/GrantPermissionExtensionTests.kt b/instrumentation/extensions/src/test/kotlin/de/mannodermaus/junit5/extensions/GrantPermissionExtensionTests.kt index 5b28b015..40958fe5 100644 --- a/instrumentation/extensions/src/test/kotlin/de/mannodermaus/junit5/extensions/GrantPermissionExtensionTests.kt +++ b/instrumentation/extensions/src/test/kotlin/de/mannodermaus/junit5/extensions/GrantPermissionExtensionTests.kt @@ -5,13 +5,13 @@ import android.os.Build import androidx.test.internal.platform.content.PermissionGranter import com.google.common.truth.Truth.assertThat import de.mannodermaus.junit5.testutil.AndroidBuildUtils.withApiLevel +import java.lang.reflect.Modifier import org.junit.jupiter.api.DynamicTest import org.junit.jupiter.api.DynamicTest.dynamicTest import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestFactory import org.junit.jupiter.api.extension.ExtensionContext import org.mockito.Mockito.mock -import java.lang.reflect.Modifier class GrantPermissionExtensionTests { @@ -21,8 +21,7 @@ class GrantPermissionExtensionTests { fun `single permission`() { runExtension(Manifest.permission.CAMERA) - assertThat(granter.grantedPermissions) - .containsExactly(Manifest.permission.CAMERA) + assertThat(granter.grantedPermissions).containsExactly(Manifest.permission.CAMERA) } @Test @@ -36,7 +35,8 @@ class GrantPermissionExtensionTests { .containsExactly( Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, - ).inOrder() + ) + .inOrder() } @TestFactory @@ -53,7 +53,8 @@ class GrantPermissionExtensionTests { .containsExactly( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - ).inOrder() + ) + .inOrder() } } } @@ -65,7 +66,9 @@ class GrantPermissionExtensionTests { // Look inside Build.VERSION_CODES and locate // the static int field with the highest value, // except for the 'CUR_DEVELOPMENT' test field - return Build.VERSION_CODES::class.java.declaredFields + return Build.VERSION_CODES::class + .java + .declaredFields .filter { Modifier.isStatic(it.modifiers) } .filter { it.type == Int::class.java } .filter { it.name != "CUR_DEVELOPMENT" } diff --git a/instrumentation/runner/build.gradle.kts b/instrumentation/runner/build.gradle.kts index 3f7f3aa7..cc6ffbd5 100644 --- a/instrumentation/runner/build.gradle.kts +++ b/instrumentation/runner/build.gradle.kts @@ -7,9 +7,7 @@ plugins { android { namespace = "de.mannodermaus.junit5.runner" - defaultConfig { - minSdk = Android.testRunnerMinSdkVersion - } + defaultConfig { minSdk = Android.testRunnerMinSdkVersion } } configurations.all { diff --git a/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/RunnerConstants.kt b/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/RunnerConstants.kt index 4cbe229f..2fd986ba 100644 --- a/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/RunnerConstants.kt +++ b/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/RunnerConstants.kt @@ -1,7 +1,7 @@ package de.mannodermaus.junit5.internal /** - * The minimum Android API level on which JUnit Framework tests may be executed. - * Trying to launch a test on an older device will simply mark it as 'skipped'. + * The minimum Android API level on which JUnit Framework tests may be executed. Trying to launch a + * test on an older device will simply mark it as 'skipped'. */ internal const val JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION: Int = 26 diff --git a/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyConfigurationParameters.kt b/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyConfigurationParameters.kt index e4a3b731..6b4b1362 100644 --- a/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyConfigurationParameters.kt +++ b/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyConfigurationParameters.kt @@ -1,19 +1,20 @@ package de.mannodermaus.junit5.internal.discovery import androidx.annotation.RequiresApi -import org.junit.platform.engine.ConfigurationParameters import java.util.Optional +import org.junit.platform.engine.ConfigurationParameters /** - * JUnit 5 version of the [ConfigurationParameters] interface, - * including the deprecated APIs that were removed in subsequent versions of the framework. + * JUnit 5 version of the [ConfigurationParameters] interface, including the deprecated APIs that + * were removed in subsequent versions of the framework. */ @RequiresApi(26) internal object EmptyConfigurationParameters : ConfigurationParameters { override fun get(key: String) = Optional.empty() + override fun getBoolean(key: String) = Optional.empty() + override fun keySet() = emptySet() - @Deprecated("Deprecated in Java", ReplaceWith("keySet().size")) - override fun size() = 0 + @Deprecated("Deprecated in Java", ReplaceWith("keySet().size")) override fun size() = 0 } diff --git a/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/runners/TestPlanAdapter.kt b/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/runners/TestPlanAdapter.kt index d56eeee1..6c42afa8 100644 --- a/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/runners/TestPlanAdapter.kt +++ b/instrumentation/runner/src/five/kotlin/de/mannodermaus/junit5/internal/runners/TestPlanAdapter.kt @@ -4,16 +4,15 @@ import org.junit.platform.launcher.TestIdentifier import org.junit.platform.launcher.TestPlan /** - * JUnit 5 version of the [TestPlanAdapter], - * including the deprecated APIs that were removed in subsequent versions of the framework. + * JUnit 5 version of the [TestPlanAdapter], including the deprecated APIs that were removed in + * subsequent versions of the framework. */ -internal open class TestPlanAdapter( - val delegate: TestPlan -) : TestPlan( - /* containsTests = */ delegate.containsTests(), - /* configurationParameters = */ delegate.configurationParameters, - /* outputDirectoryCreator = */ delegate.outputDirectoryCreator -) { +internal open class TestPlanAdapter(val delegate: TestPlan) : + TestPlan( + /* containsTests = */ delegate.containsTests(), + /* configurationParameters = */ delegate.configurationParameters, + /* outputDirectoryCreator = */ delegate.outputDirectoryCreator, + ) { @Deprecated("Deprecated in Java") @Suppress("DEPRECATION") override fun getChildren(parentId: String): Set { diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilder.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilder.kt index d5834aec..243c5e42 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilder.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilder.kt @@ -9,15 +9,13 @@ import org.junit.runner.Runner import org.junit.runners.model.RunnerBuilder /** - * Custom RunnerBuilder hooked into the main Test Instrumentation Runner - * provided by the Android Test Support Library, which allows to run - * the JUnit Platform for instrumented tests. With this, - * the default JUnit 4-based Runner for Android instrumented tests is, - * in a way, tricked into detecting JUnit Jupiter tests as well. - * - * The RunnerBuilder is added to the instrumentation runner - * through a custom "testInstrumentationRunnerArgument" in the build.gradle script: + * Custom RunnerBuilder hooked into the main Test Instrumentation Runner provided by the Android + * Test Support Library, which allows to run the JUnit Platform for instrumented tests. With this, + * the default JUnit 4-based Runner for Android instrumented tests is, in a way, tricked into + * detecting JUnit Jupiter tests as well. * + * The RunnerBuilder is added to the instrumentation runner through a custom + * "testInstrumentationRunnerArgument" in the build.gradle script: *

  *   android {
  *     defaultConfig {
@@ -27,8 +25,8 @@ import org.junit.runners.model.RunnerBuilder
  *   }
  * 
* - * (Suppressing unused, since this is hooked into the - * project configuration via a Test Instrumentation Runner Argument.) + * (Suppressing unused, since this is hooked into the project configuration via a Test + * Instrumentation Runner Argument.) */ public open class AndroidJUnitFrameworkBuilder internal constructor() : RunnerBuilder() { private val junitFrameworkAvailable by lazy { @@ -73,9 +71,9 @@ public open class AndroidJUnitFrameworkBuilder internal constructor() : RunnerBu Log.e(LOG_TAG, "JUnitPlatform not found on runtime classpath") throw IllegalStateException( "junit-platform-runner not found on runtime classpath of instrumentation tests; " + - "please review your androidTest dependencies or raise an issue.", e + "please review your androidTest dependencies or raise an issue.", + e, ) - } catch (e: Throwable) { Log.e(LOG_TAG, "Error constructing runner", e) throw e @@ -84,18 +82,13 @@ public open class AndroidJUnitFrameworkBuilder internal constructor() : RunnerBu /* Private */ - private val ignorablePackages = setOf( - "java.", - "javax.", - "androidx.", - "com.android.", - "kotlin.", - "kotlinx.", - ) + private val ignorablePackages = + setOf("java.", "javax.", "androidx.", "com.android.", "kotlin.", "kotlinx.") - private val Class<*>.isInIgnorablePackage: Boolean get() { - return ignorablePackages.any { name.startsWith(it) } - } + private val Class<*>.isInIgnorablePackage: Boolean + get() { + return ignorablePackages.any { name.startsWith(it) } + } private fun JUnitFrameworkRunnerParams.registerEnvironmentVariables() { environmentVariables.forEach { (key, value) -> @@ -119,15 +112,13 @@ public open class AndroidJUnitFrameworkBuilder internal constructor() : RunnerBu } /** - * Custom RunnerBuilder hooked into the main Test Instrumentation Runner - * provided by the Android Test Support Library, which allows to run - * the JUnit Platform for instrumented tests. With this, - * the default JUnit 4-based Runner for Android instrumented tests is, - * in a way, tricked into detecting JUnit Jupiter tests as well. - * - * The RunnerBuilder is added to the instrumentation runner - * through a custom "testInstrumentationRunnerArgument" in the build.gradle script: + * Custom RunnerBuilder hooked into the main Test Instrumentation Runner provided by the Android + * Test Support Library, which allows to run the JUnit Platform for instrumented tests. With this, + * the default JUnit 4-based Runner for Android instrumented tests is, in a way, tricked into + * detecting JUnit Jupiter tests as well. * + * The RunnerBuilder is added to the instrumentation runner through a custom + * "testInstrumentationRunnerArgument" in the build.gradle script: *
  *   android {
  *     defaultConfig {
@@ -137,11 +128,11 @@ public open class AndroidJUnitFrameworkBuilder internal constructor() : RunnerBu
  *   }
  * 
* - * (Suppressing unused, since this is hooked into the - * project configuration via a Test Instrumentation Runner Argument.) + * (Suppressing unused, since this is hooked into the project configuration via a Test + * Instrumentation Runner Argument.) */ @Deprecated( message = "Renamed to AndroidJUnitFrameworkBuilder", - replaceWith = ReplaceWith("AndroidJUnitFrameworkBuilder") + replaceWith = ReplaceWith("AndroidJUnitFrameworkBuilder"), ) public class AndroidJUnit5Builder : AndroidJUnitFrameworkBuilder() diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/LibcoreAccess.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/LibcoreAccess.kt index 63e89657..6f718ac1 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/LibcoreAccess.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/LibcoreAccess.kt @@ -7,12 +7,13 @@ internal object LibcoreAccess { private class Wrapper { private val libcoreClass = Class.forName("libcore.io.Libcore") private val libcoreOsObject = libcoreClass.getField("os").get(null) - private val setEnvMethod = libcoreOsObject.javaClass.getMethod( - "setenv", - String::class.java, - String::class.java, - Boolean::class.java - ) + private val setEnvMethod = + libcoreOsObject.javaClass.getMethod( + "setenv", + String::class.java, + String::class.java, + Boolean::class.java, + ) fun setenv(key: String, value: String, overwrite: Boolean) { setEnvMethod.invoke(libcoreOsObject, key, value, overwrite) @@ -29,11 +30,12 @@ internal object LibcoreAccess { } /** - * Invokes the method "libcore.io.Libcore.os.setenv(String, String)" with the provided key/value pair. - * This effectively adds a custom environment variable to the running process, - * allowing instrumentation tests to honor JUnit 5's @EnabledIfEnvironmentVariable and @DisabledIfEnvironmentVariable annotations. + * Invokes the method "libcore.io.Libcore.os.setenv(String, String)" with the provided key/value + * pair. This effectively adds a custom environment variable to the running process, allowing + * instrumentation tests to honor JUnit 5's @EnabledIfEnvironmentVariable + * and @DisabledIfEnvironmentVariable annotations. * - * @param key Key of the variable + * @param key Key of the variable * @param value Value of the variable * @throws IllegalAccessException If Libcore is not available */ diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyTestPlan.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyTestPlan.kt index f3d44c2d..0ef81ada 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyTestPlan.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyTestPlan.kt @@ -1,26 +1,30 @@ package de.mannodermaus.junit5.internal.discovery import androidx.annotation.RequiresApi +import java.io.File import org.junit.platform.engine.OutputDirectoryCreator import org.junit.platform.engine.TestDescriptor import org.junit.platform.launcher.TestPlan -import java.io.File /** - * A JUnit TestPlan that does absolutely nothing. - * Used by [de.mannodermaus.junit5.internal.runners.AndroidJUnitFramework] whenever a class - * is not loadable through the JUnit Platform and should be discarded. + * A JUnit TestPlan that does absolutely nothing. Used by + * [de.mannodermaus.junit5.internal.runners.AndroidJUnitFramework] whenever a class is not loadable + * through the JUnit Platform and should be discarded. */ @RequiresApi(26) -internal object EmptyTestPlan : TestPlan( - /* containsTests = */ false, - /* configurationParameters = */ EmptyConfigurationParameters, - /* outputDirectoryCreator = */ emptyOutputDirectoryCreator -) +internal object EmptyTestPlan : + TestPlan( + /* containsTests = */ false, + /* configurationParameters = */ EmptyConfigurationParameters, + /* outputDirectoryCreator = */ emptyOutputDirectoryCreator, + ) @RequiresApi(26) -private val emptyOutputDirectoryCreator = object : OutputDirectoryCreator { - private val path = File.createTempFile("empty-output", ".nop").toPath() - override fun getRootDirectory() = path - override fun createOutputDirectory(testDescriptor: TestDescriptor) = path -} +private val emptyOutputDirectoryCreator = + object : OutputDirectoryCreator { + private val path = File.createTempFile("empty-output", ".nop").toPath() + + override fun getRootDirectory() = path + + override fun createOutputDirectory(testDescriptor: TestDescriptor) = path + } diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/GeneratedFilters.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/GeneratedFilters.kt index 2104f9b7..cacebdc7 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/GeneratedFilters.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/GeneratedFilters.kt @@ -9,9 +9,8 @@ import org.junit.platform.launcher.TagFilter private const val INSTRUMENTATION_FILTER_RES_FILE_NAME = "de_mannodermaus_junit5_filters" /** - * Holder object for the filters of a test plan. - * It converts the contents of a resource file into JUnit Platform [Filter] objects - * for the [AndroidJUnitFramework] runner. + * Holder object for the filters of a test plan. It converts the contents of a resource file into + * JUnit Platform [Filter] objects for the [AndroidJUnitFramework] runner. */ internal object GeneratedFilters { @@ -21,21 +20,23 @@ internal object GeneratedFilters { // Look up the resource file written by the Gradle plugin // and open it. // (See Constants.kt inside the plugin's repository for the value used here) - val identifier = context.resources.getIdentifier( - INSTRUMENTATION_FILTER_RES_FILE_NAME, - "raw", - context.packageName - ) - val inputStream = if (identifier != 0) { - try { - context.resources.openRawResource(identifier) - } catch (_: Resources.NotFoundException) { - // Ignore + val identifier = + context.resources.getIdentifier( + INSTRUMENTATION_FILTER_RES_FILE_NAME, + "raw", + context.packageName, + ) + val inputStream = + if (identifier != 0) { + try { + context.resources.openRawResource(identifier) + } catch (_: Resources.NotFoundException) { + // Ignore + null + } + } else { null } - } else { - null - } if (inputStream == null) { // File doesn't exist, or couldn't be located; return diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/ParsedSelectors.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/ParsedSelectors.kt index 3afbe5f3..61999c78 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/ParsedSelectors.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/ParsedSelectors.kt @@ -6,10 +6,9 @@ import org.junit.platform.engine.DiscoverySelector import org.junit.platform.engine.discovery.DiscoverySelectors /** - * Holder object for the selectors of a test plan. - * It converts the arguments handed to the Runner by the - * Android instrumentation into JUnit Platform [DiscoverySelector] objects - * for the [AndroidJUnitFramework] runner. + * Holder object for the selectors of a test plan. It converts the arguments handed to the Runner by + * the Android instrumentation into JUnit Platform [DiscoverySelector] objects for the + * [AndroidJUnitFramework] runner. */ internal object ParsedSelectors { fun fromBundle(testClass: Class<*>, arguments: Bundle): List { @@ -23,29 +22,31 @@ internal object ParsedSelectors { // Separate the provided argument into methods, if any are given // (Format: class=com.package1.FirstTest#method1,com.package1.SecondTest#method2). // For each component in this string that applies to the test class at hand, - // consider it a method filter if the name is appended to the component, using a pound sign (#). - // Finally, if at least one of these method filters can be found, construct JUnit selectors from it - classArg.split(",") - .forEach { component -> - if (!component.startsWith(testClassName)) { - // Not the desired class - return@forEach - } - - // Try extracting an appended method name - var methodName = component.replace(testClassName, "") - if (!methodName.startsWith("#")) { - return@forEach - } - methodName = methodName.substring(1) - - // Find all methods with the given name - val eligibleMethods = methods + // consider it a method filter if the name is appended to the component, using a pound + // sign (#). + // Finally, if at least one of these method filters can be found, construct JUnit + // selectors from it + classArg.split(",").forEach { component -> + if (!component.startsWith(testClassName)) { + // Not the desired class + return@forEach + } + + // Try extracting an appended method name + var methodName = component.replace(testClassName, "") + if (!methodName.startsWith("#")) { + return@forEach + } + methodName = methodName.substring(1) + + // Find all methods with the given name + val eligibleMethods = + methods .filter { it.name == methodName } .map { method -> DiscoverySelectors.selectMethod(testClass, method) } - selectors += eligibleMethods - } + selectors += eligibleMethods + } if (selectors.isNotEmpty()) { // Restrictions to specific methods apply diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/PropertiesParser.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/PropertiesParser.kt index e69ab49c..fdfd9436 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/PropertiesParser.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/PropertiesParser.kt @@ -2,7 +2,8 @@ package de.mannodermaus.junit5.internal.discovery internal object PropertiesParser { fun fromString(string: String) = - string.split(",") + string + .split(",") .map { keyValuePair -> keyValuePair.split("=") } .filter { keyValueList -> keyValueList.size == 2 } .associate { it[0] to it[1] } diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/ShardingFilter.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/ShardingFilter.kt index 87ddefc3..38d87d5f 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/ShardingFilter.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/discovery/ShardingFilter.kt @@ -2,23 +2,21 @@ package de.mannodermaus.junit5.internal.discovery import android.os.Bundle import de.mannodermaus.junit5.internal.extensions.isDynamicTest +import kotlin.math.abs import org.junit.platform.engine.FilterResult import org.junit.platform.engine.TestDescriptor import org.junit.platform.launcher.PostDiscoveryFilter import org.junit.platform.launcher.TestIdentifier -import kotlin.math.abs /** * JUnit 5 implementation of the default instrumentation's - * `androidx.test.internal.runner.TestRequestBuilder$ShardingFilter`, - * ported to the new API to support dynamic test templates, too. + * `androidx.test.internal.runner.TestRequestBuilder$ShardingFilter`, ported to the new API to + * support dynamic test templates, too. * * Based on a draft by KyoungJoo Jeon (@jkj8790). */ -internal class ShardingFilter( - private val numShards: Int, - private val shardIndex: Int, -) : PostDiscoveryFilter { +internal class ShardingFilter(private val numShards: Int, private val shardIndex: Int) : + PostDiscoveryFilter { companion object { private const val ARG_NUM_SHARDS = "numShards" diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinder.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinder.kt index 8109c8ef..6eeb934f 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinder.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinder.kt @@ -2,18 +2,18 @@ package de.mannodermaus.junit5.internal.dummy import android.util.Log import de.mannodermaus.junit5.internal.LOG_TAG +import java.lang.reflect.Method +import java.lang.reflect.Modifier import org.junit.jupiter.api.RepeatedTest import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestFactory import org.junit.jupiter.api.TestTemplate import org.junit.jupiter.params.ParameterizedTest -import java.lang.reflect.Method -import java.lang.reflect.Modifier /** - * Algorithm to find all methods annotated with a JUnit Jupiter annotation - * for devices running below the API level requirement of the JUnit Framework. - * As they rely on Java 8 stuff, we're unable to rely on JUnit Platform's own reflection utilities. + * Algorithm to find all methods annotated with a JUnit Jupiter annotation for devices running below + * the API level requirement of the JUnit Framework. As they rely on Java 8 stuff, we're unable to + * rely on JUnit Platform's own reflection utilities. */ internal object JupiterTestMethodFinder { // Carefully access the Jupiter annotations, since it's possible that they aren't on @@ -57,7 +57,7 @@ internal object JupiterTestMethodFinder { Log.w( LOG_TAG, "Encountered ${t.javaClass.simpleName} while finding Jupiter test methods for ${this@doFind.name}", - t + t, ) } } diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/extensions/TestIdentifierExt.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/extensions/TestIdentifierExt.kt index c54aeb90..7ea7600d 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/extensions/TestIdentifierExt.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/extensions/TestIdentifierExt.kt @@ -3,13 +3,14 @@ package de.mannodermaus.junit5.internal.extensions import de.mannodermaus.junit5.internal.formatters.TestNameFormatter import org.junit.platform.launcher.TestIdentifier -private val DYNAMIC_TEST_PREFIXES = listOf( - "[test-template-invocation", - "[dynamic-test", - "[dynamic-container", - "[test-factory", - "[test-template" -) +private val DYNAMIC_TEST_PREFIXES = + listOf( + "[test-template-invocation", + "[dynamic-test", + "[dynamic-container", + "[test-factory", + "[test-template", + ) private val TestIdentifier.shortId: String get() { @@ -22,8 +23,8 @@ private val TestIdentifier.shortId: String } /** - * Check if the given TestIdentifier describes a "test template invocation", - * i.e. a dynamic test generated at runtime. + * Check if the given TestIdentifier describes a "test template invocation", i.e. a dynamic test + * generated at runtime. */ internal val TestIdentifier.isDynamicTest: Boolean get() { @@ -32,10 +33,8 @@ internal val TestIdentifier.isDynamicTest: Boolean } /** - * Returns a formatted version of this identifier's name, - * which is compatible with the quirks and limitations - * of the Android Instrumentation, esp. when the [legacyFormat] - * flag is enabled. + * Returns a formatted version of this identifier's name, which is compatible with the quirks and + * limitations of the Android Instrumentation, esp. when the [legacyFormat] flag is enabled. */ internal fun TestIdentifier.format(legacyFormat: Boolean = false): String = TestNameFormatter.format(this, legacyFormat) diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/formatters/TestNameFormatter.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/formatters/TestNameFormatter.kt index 40acf8e9..018d60f2 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/formatters/TestNameFormatter.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/formatters/TestNameFormatter.kt @@ -3,22 +3,24 @@ package de.mannodermaus.junit5.internal.formatters import org.junit.platform.launcher.TestIdentifier /** - * A class for naming Jupiter test methods in a compatible manner, - * taking into account several limitations imposed by the - * Android instrumentation (e.g. on isolated test runs). + * A class for naming Jupiter test methods in a compatible manner, taking into account several + * limitations imposed by the Android instrumentation (e.g. on isolated test runs). */ internal object TestNameFormatter { fun format(identifier: TestIdentifier, legacyFormat: Boolean = false): String { // When requesting the legacy format of the formatter, // construct a technical version of its name for backwards compatibility - // with the JUnit 4-based instrumentation of Android by stripping the brackets of parameterized tests completely. + // with the JUnit 4-based instrumentation of Android by stripping the brackets of + // parameterized tests completely. // If this didn't happen, running them from the IDE will cause "No tests found" errors. - // See AndroidX's TestRequestBuilder$MethodFilter for where this is cross-referenced in the instrumentation! + // See AndroidX's TestRequestBuilder$MethodFilter for where this is cross-referenced in the + // instrumentation! // // History: // - #199 & #207 (the original unearthing of this behavior) // - #317 (making an exception for dynamic tests) - // - #339 (retain indices of parameterized methods to avoid premature filtering by JUnit 4's test discovery) + // - #339 (retain indices of parameterized methods to avoid premature filtering by JUnit 4's + // test discovery) if (legacyFormat) { val reportName = identifier.legacyReportingName val paramStartIndex = reportName.indexOf('(') diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFramework.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFramework.kt index be6aef8e..f82f8e26 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFramework.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFramework.kt @@ -11,9 +11,8 @@ import org.junit.runner.Runner import org.junit.runner.notification.RunNotifier /** - * JUnit Runner implementation using the JUnit Platform as its backbone. - * Serves as an intermediate solution to writing JUnit 5-based instrumentation tests - * until official support arrives for this. + * JUnit Runner implementation using the JUnit Platform as its backbone. Serves as an intermediate + * solution to writing JUnit 5-based instrumentation tests until official support arrives for this. */ @RequiresApi(26) @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) @@ -46,25 +45,27 @@ internal class AndroidJUnitFramework( if (isUsingOrchestrator && params.isParallelExecutionEnabled) { throw RuntimeException( """ - Running tests with the Android Test Orchestrator does not work with parallel tests, - since some information must be retained across parallel test execution, - and the isolated nature of the Android Test Orchestrator thwarts these efforts. - Please disable either setting and try again. - """.trimIndent(), + Running tests with the Android Test Orchestrator does not work with parallel tests, + since some information must be retained across parallel test execution, + and the isolated nature of the Android Test Orchestrator thwarts these efforts. + Please disable either setting and try again. + """ + .trimIndent() ) } - val testPlan = try { - launcher.discover(request) - } catch (e: JUnitException) { - // Each class in scope is given to the runner, - // but some may fail to be loaded by the class loader - // (e.g. when they are tailored to JVM work and reference sun.* classes - // or anything else not present in the Android runtime). - // Log those to console, but discard them from being considered at all - e.printStackTrace() - EmptyTestPlan - } + val testPlan = + try { + launcher.discover(request) + } catch (e: JUnitException) { + // Each class in scope is given to the runner, + // but some may fail to be loaded by the class loader + // (e.g. when they are tailored to JVM work and reference sun.* classes + // or anything else not present in the Android runtime). + // Log those to console, but discard them from being considered at all + e.printStackTrace() + EmptyTestPlan + } return AndroidJUnitPlatformTestTree( testPlan = testPlan, diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformRunnerListener.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformRunnerListener.kt index 038bee42..0295effb 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformRunnerListener.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformRunnerListener.kt @@ -13,13 +13,11 @@ import org.junit.runner.Description import org.junit.runner.notification.Failure import org.junit.runner.notification.RunNotifier -/** - * Required, public extension to allow access to package-private RunnerListener class - */ +/** Required, public extension to allow access to package-private RunnerListener class */ @SuppressLint("NewApi") internal class AndroidJUnitPlatformRunnerListener( private val testTree: AndroidJUnitPlatformTestTree, - private val notifier: RunNotifier + private val notifier: RunNotifier, ) : TestExecutionListener { override fun reportingEntryPublished(testIdentifier: TestIdentifier, entry: ReportEntry) { @@ -45,12 +43,13 @@ internal class AndroidJUnitPlatformRunnerListener( when { testIdentifier.isTest -> fireTestIgnored(testIdentifier, reason) testIdentifier.isDynamicTest -> fireTestIgnored(testIdentifier, reason) - testIdentifier.isContainer -> testTree.getChildren(testIdentifier).forEach { childIdentifier -> - // Only report leaf tests as skipped - if (childIdentifier.isTest || childIdentifier.isDynamicTest) { - fireTestIgnored(childIdentifier, reason) + testIdentifier.isContainer -> + testTree.getChildren(testIdentifier).forEach { childIdentifier -> + // Only report leaf tests as skipped + if (childIdentifier.isTest || childIdentifier.isDynamicTest) { + fireTestIgnored(childIdentifier, reason) + } } - } } } @@ -62,7 +61,7 @@ internal class AndroidJUnitPlatformRunnerListener( override fun executionFinished( testIdentifier: TestIdentifier, - testExecutionResult: TestExecutionResult + testExecutionResult: TestExecutionResult, ) { val description = testTree.getDescription(testIdentifier) val status = testExecutionResult.status @@ -84,6 +83,6 @@ internal class AndroidJUnitPlatformRunnerListener( private fun toFailure( testExecutionResult: TestExecutionResult, - description: Description + description: Description, ): Failure = Failure(description, testExecutionResult.throwable.orElse(null)) -} \ No newline at end of file +} 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 9b7c703e..14a7dfae 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 @@ -5,6 +5,8 @@ package de.mannodermaus.junit5.internal.runners import android.annotation.SuppressLint import de.mannodermaus.junit5.internal.extensions.format import de.mannodermaus.junit5.internal.extensions.isDynamicTest +import java.util.Optional +import java.util.function.Predicate import org.junit.platform.commons.util.AnnotationUtils import org.junit.platform.engine.UniqueId import org.junit.platform.engine.support.descriptor.ClassSource @@ -13,13 +15,11 @@ import org.junit.platform.launcher.TestIdentifier import org.junit.platform.launcher.TestPlan import org.junit.platform.suite.api.SuiteDisplayName import org.junit.runner.Description -import java.util.Optional -import java.util.function.Predicate /** - * Required, public extension to allow access to package-private TestTree class. - * Furthermore, manipulate the test tree in a way that will fold dynamic tests - * into the test report, without having the Android instrumentation mess up their naming. + * Required, public extension to allow access to package-private TestTree class. Furthermore, + * manipulate the test tree in a way that will fold dynamic tests into the test report, without + * having the Android instrumentation mess up their naming. */ @SuppressLint("NewApi") internal class AndroidJUnitPlatformTestTree( @@ -37,39 +37,41 @@ internal class AndroidJUnitPlatformTestTree( // Order matters here, since all dynamic tests are also containers, // but not all containers are dynamic tests - fun getTestName(identifier: TestIdentifier): String = when { - identifier.isDynamicTest -> if (needLegacyFormat) { - // In isolated method runs, there is no need to compose - // dynamic test names from multiple pieces, as the - // Android Instrumentation only looks at the raw method name - // anyway and all information about parameter types is lost - identifier.format(true) - } else { - // Collect all dynamic tests' IDs from this identifier, - // all the way up to the first non-dynamic test. - // Collect the name of all these into a list, then finally - // compose the final name from this list. Note that, because we - // move upwards the test plan, the elements must be reversed - // before the final name can be composed. - val nameComponents = mutableListOf() - var currentNode: TestIdentifier? = identifier - while (currentNode != null && currentNode.isDynamicTest) { - nameComponents.add(currentNode.format(false)) - currentNode = modifiedTestPlan.getRealParent(currentNode).orElse(null) - } - nameComponents.reverse() - - // Android's Unified Test Platform (AGP 7.0+) is using literal test names - // to create files when capturing Logcat output during execution. - // Ergo, make sure that only legal characters are being used in the test names - // (ref. https://github.com/mannodermaus/android-junit5/issues/263) - nameComponents.joinToString(" - ") - } + fun getTestName(identifier: TestIdentifier): String = + when { + identifier.isDynamicTest -> + if (needLegacyFormat) { + // In isolated method runs, there is no need to compose + // dynamic test names from multiple pieces, as the + // Android Instrumentation only looks at the raw method name + // anyway and all information about parameter types is lost + identifier.format(true) + } else { + // Collect all dynamic tests' IDs from this identifier, + // all the way up to the first non-dynamic test. + // Collect the name of all these into a list, then finally + // compose the final name from this list. Note that, because we + // move upwards the test plan, the elements must be reversed + // before the final name can be composed. + val nameComponents = mutableListOf() + var currentNode: TestIdentifier? = identifier + while (currentNode != null && currentNode.isDynamicTest) { + nameComponents.add(currentNode.format(false)) + currentNode = modifiedTestPlan.getRealParent(currentNode).orElse(null) + } + nameComponents.reverse() + + // Android's Unified Test Platform (AGP 7.0+) is using literal test names + // to create files when capturing Logcat output during execution. + // Ergo, make sure that only legal characters are being used in the test names + // (ref. https://github.com/mannodermaus/android-junit5/issues/263) + nameComponents.joinToString(" - ") + } - identifier.isContainer -> getTechnicalName(identifier) + identifier.isContainer -> getTechnicalName(identifier) - else -> identifier.format(needLegacyFormat) - } + else -> identifier.format(needLegacyFormat) + } // Do not expose our custom TestPlan, because JUnit Platform wouldn't like that very much. // Only internally, use the wrapped version @@ -94,11 +96,7 @@ internal class AndroidJUnitPlatformTestTree( private fun buildDescriptionTree(suiteDescription: Description, testPlan: TestPlan) { testPlan.roots.forEach { identifier -> - buildDescription( - identifier, - suiteDescription, - testPlan - ) + buildDescription(identifier, suiteDescription, testPlan) } } @@ -110,18 +108,18 @@ internal class AndroidJUnitPlatformTestTree( private fun buildDescription( identifier: TestIdentifier, parent: Description, - testPlan: TestPlan + testPlan: TestPlan, ) { - val newDescription = createJUnit4Description(identifier, testPlan).also { - descriptions[identifier] = it - } + val newDescription = + createJUnit4Description(identifier, testPlan).also { descriptions[identifier] = it } - val newParent = if (identifier.isTest || identifier.isDynamicTest) { - parent.addChild(newDescription) - newDescription - } else { - parent - } + val newParent = + if (identifier.isTest || identifier.isDynamicTest) { + parent.addChild(newDescription) + newDescription + } else { + parent + } testPlan.getChildren(identifier).forEach { child -> buildDescription(child, newParent, testPlan) @@ -130,15 +128,14 @@ internal class AndroidJUnitPlatformTestTree( private fun createJUnit4Description( identifier: TestIdentifier, - testPlan: TestPlan + testPlan: TestPlan, ): Description { val name = nameExtractor(identifier) - return if (identifier.isTest || identifier.isDynamicTest) { Description.createTestDescription( - /* className = */ - testPlan.getParent(identifier) + /* className = */ testPlan + .getParent(identifier) .map(nameExtractor) .orElse(""), /* name = */ name, @@ -158,7 +155,6 @@ internal class AndroidJUnitPlatformTestTree( if (source is ClassSource) { return source.javaClass.name - } else if (source is MethodSource) { val methodParameterTypes = source.methodParameterTypes.orEmpty() return if (methodParameterTypes.isBlank()) { @@ -177,14 +173,13 @@ internal class AndroidJUnitPlatformTestTree( return modifiedTestPlan.getDescendants(testIdentifier) } - /** - * Custom drop-in TestPlan for Android purposes. - */ + /** Custom drop-in TestPlan for Android purposes. */ private class ModifiedTestPlan(delegate: TestPlan) : TestPlanAdapter(delegate) { fun getRealParent(child: TestIdentifier): Optional { // Because the overridden "getParent()" from the superclass is modified, - // expose this additional method to access the actual parent identifier of the given child. + // expose this additional method to access the actual parent identifier of the given + // child. // This is needed when composing the display name of a dynamic test. return delegate.getParent(child) } @@ -201,7 +196,9 @@ internal class AndroidJUnitPlatformTestTree( } } - private fun findEligibleParentOfDynamicTest(child: TestIdentifier): Optional { + private fun findEligibleParentOfDynamicTest( + child: TestIdentifier + ): Optional { var node = delegate.getParent(child) while (node.isPresent && node.get().isDynamicTest) { node = node.flatMap(delegate::getParent) @@ -248,4 +245,4 @@ internal class AndroidJUnitPlatformTestTree( return delegate.containsTests() } } -} \ No newline at end of file +} diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnitFramework.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnitFramework.kt index c1261dee..db7a3706 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnitFramework.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/DummyJUnitFramework.kt @@ -5,14 +5,14 @@ import android.util.Log import de.mannodermaus.junit5.internal.JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION import de.mannodermaus.junit5.internal.LOG_TAG import de.mannodermaus.junit5.internal.dummy.JupiterTestMethodFinder +import java.lang.reflect.Method import org.junit.runner.Description import org.junit.runner.Runner import org.junit.runner.notification.RunNotifier -import java.lang.reflect.Method /** - * Fake Runner that marks all JUnit Framework methods as ignored, - * used for old devices without the required Java capabilities. + * Fake Runner that marks all JUnit Framework methods as ignored, used for old devices without the + * required Java capabilities. */ internal class DummyJUnitFramework(private val testClass: Class<*>) : Runner() { @@ -22,9 +22,9 @@ internal class DummyJUnitFramework(private val testClass: Class<*>) : Runner() { Log.w( LOG_TAG, "JUnit Framework is not supported on this device: " + - "API level ${Build.VERSION.SDK_INT} is less than " + - "${JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION}, the minimum requirement. " + - "All Jupiter tests for ${testClass.name} will be disabled." + "API level ${Build.VERSION.SDK_INT} is less than " + + "${JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION}, the minimum requirement. " + + "All Jupiter tests for ${testClass.name} will be disabled.", ) for (testMethod in testMethods) { diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerFactory.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerFactory.kt index 2dd7067f..779b0458 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerFactory.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerFactory.kt @@ -7,19 +7,20 @@ import org.junit.runner.Runner /** * Since we can't reference [AndroidJUnitFramework] directly, use this factory for instantiation. * - * On devices with sufficient API levels, delegate to the real implementation to drive - * the execution of JUnit Framework tests. Below this threshold, they wouldn't work, however; - * for this case, delegate to a dummy runner which will highlight these tests as ignored. + * On devices with sufficient API levels, delegate to the real implementation to drive the execution + * of JUnit Framework tests. Below this threshold, they wouldn't work, however; for this case, + * delegate to a dummy runner which will highlight these tests as ignored. */ internal fun tryCreateJUnitFrameworkRunner( klass: Class<*>, - paramsSupplier: () -> JUnitFrameworkRunnerParams + paramsSupplier: () -> JUnitFrameworkRunnerParams, ): Runner? { - val runner = if (Build.VERSION.SDK_INT >= JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION) { - AndroidJUnitFramework(klass, paramsSupplier) - } else { - DummyJUnitFramework(klass) - } + val runner = + if (Build.VERSION.SDK_INT >= JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION) { + AndroidJUnitFramework(klass, paramsSupplier) + } else { + DummyJUnitFramework(klass) + } // It's still possible for the runner to not be relevant to the test run, // which is related to how further filters are applied (e.g. via @Tag). @@ -29,5 +30,4 @@ internal fun tryCreateJUnitFrameworkRunner( return runner.takeIf(Runner::hasExecutableTests) } -private fun Runner.hasExecutableTests() = - this.description.children.isNotEmpty() +private fun Runner.hasExecutableTests() = this.description.children.isNotEmpty() diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerParams.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerParams.kt index 0d9cfb7d..693634a9 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerParams.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/JUnitFrameworkRunnerParams.kt @@ -16,7 +16,7 @@ internal data class JUnitFrameworkRunnerParams( private val filters: List> = emptyList(), val environmentVariables: Map = emptyMap(), val systemProperties: Map = emptyMap(), - private val configurationParameters: Map = emptyMap() + private val configurationParameters: Map = emptyMap(), ) { fun createSelectors(testClass: Class<*>): List { return ParsedSelectors.fromBundle(testClass, arguments) @@ -42,25 +42,30 @@ internal data class JUnitFrameworkRunnerParams( val arguments = InstrumentationRegistry.getArguments() // Parse environment variables & pass them to the JVM - val environmentVariables = arguments.getString(ARG_ENVIRONMENT_VARIABLES) - ?.run { PropertiesParser.fromString(this) } - ?: emptyMap() + val environmentVariables = + arguments.getString(ARG_ENVIRONMENT_VARIABLES)?.run { + PropertiesParser.fromString(this) + } ?: emptyMap() // Parse system properties & pass them to the JVM - val systemProperties = arguments.getString(ARG_SYSTEM_PROPERTIES) - ?.run { PropertiesParser.fromString(this) } - ?: emptyMap() + val systemProperties = + arguments.getString(ARG_SYSTEM_PROPERTIES)?.run { + PropertiesParser.fromString(this) + } ?: emptyMap() // Parse configuration parameters - val configurationParameters = arguments.getString(ARG_CONFIGURATION_PARAMETERS) - ?.run { PropertiesParser.fromString(this) } - ?: emptyMap() + val configurationParameters = + arguments.getString(ARG_CONFIGURATION_PARAMETERS)?.run { + PropertiesParser.fromString(this) + } ?: emptyMap() - // The user may apply test filters to their instrumentation tests through the Gradle plugin's DSL, + // The user may apply test filters to their instrumentation tests through the Gradle + // plugin's DSL, // which aren't subject to the filtering imposed through adb. // A special resource file may be looked up at runtime, containing // the filters to apply by the AndroidJUnit5 runner. - val filters = GeneratedFilters.fromContext(instrumentation.context) + + val filters = + GeneratedFilters.fromContext(instrumentation.context) + listOfNotNull(ShardingFilter.fromArguments(arguments)) return JUnitFrameworkRunnerParams( @@ -68,7 +73,7 @@ internal data class JUnitFrameworkRunnerParams( filters, environmentVariables, systemProperties, - configurationParameters + configurationParameters, ) } } diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/notification/FilteredRunListener.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/notification/FilteredRunListener.kt index 3288c74a..6cf4ab4e 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/notification/FilteredRunListener.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/notification/FilteredRunListener.kt @@ -5,9 +5,9 @@ import org.junit.runner.notification.Failure import org.junit.runner.notification.RunListener /** - * A wrapper implementation around JUnit's [RunListener] class - * which only works selectively. In other words, this implementation only delegates - * to its parameter for test descriptors that pass the given [filter]. + * A wrapper implementation around JUnit's [RunListener] class which only works selectively. In + * other words, this implementation only delegates to its parameter for test descriptors that pass + * the given [filter]. */ internal class FilteredRunListener( private val delegate: RunListener, diff --git a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/notification/ParallelRunNotifier.kt b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/notification/ParallelRunNotifier.kt index 4229a76c..b0292a09 100644 --- a/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/notification/ParallelRunNotifier.kt +++ b/instrumentation/runner/src/main/kotlin/de/mannodermaus/junit5/internal/runners/notification/ParallelRunNotifier.kt @@ -8,26 +8,25 @@ import android.util.Log import androidx.test.internal.runner.listener.InstrumentationResultPrinter import de.mannodermaus.junit5.internal.LOG_TAG import de.mannodermaus.junit5.internal.runners.notification.ParallelRunNotifier.EventThread.Event -import org.junit.runner.Description -import org.junit.runner.notification.Failure -import org.junit.runner.notification.RunListener -import org.junit.runner.notification.RunNotifier import java.util.concurrent.Executors import java.util.concurrent.LinkedBlockingDeque import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.TimeUnit +import org.junit.runner.Description +import org.junit.runner.notification.Failure +import org.junit.runner.notification.RunListener +import org.junit.runner.notification.RunNotifier /** - * Wrapping implementation of JUnit 4's run notifier for parallel test execution - * (i.e. when "junit.jupiter.execution.parallel.enabled" is active during the run). - * It unpacks the singular 'instrumentation result printer' assigned by AndroidX - * and reroutes its notification mechanism. This allows parallel tests to still execute in parallel, - * but also allows their results to be reported back in the strictly sequential order required by the instrumentation. + * Wrapping implementation of JUnit 4's run notifier for parallel test execution (i.e. when + * "junit.jupiter.execution.parallel.enabled" is active during the run). It unpacks the singular + * 'instrumentation result printer' assigned by AndroidX and reroutes its notification mechanism. + * This allows parallel tests to still execute in parallel, but also allows their results to be + * reported back in the strictly sequential order required by the instrumentation. */ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotifier() { private companion object { - @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - private val doneLock = Object() + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") private val doneLock = Object() private val nopPrinter = InstrumentationResultPrinter() private val nopTestState = TestState("", Bundle(), 0) @@ -52,7 +51,8 @@ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotif private val states = mutableMapOf() // Even though parallelism is the name of the game under the hood for this RunNotifier, - // the nature of the Android Instrumentation is very much bound to synchronous execution internally. + // the nature of the Android Instrumentation is very much bound to synchronous execution + // internally. // Therefore, a single-threaded executor must be used to project the multithreaded notifications // from JUnit 5 onto this legacy thread model, resulting in some funky test reporting // but allowing the awesome performance benefits of parallel test execution! @@ -70,10 +70,9 @@ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotif delegate.fireTestSuiteStarted(description) // Start asynchronous processing pipeline - eventThread = EventThread( - onProcessEvent = ::onProcessEvent, - onDone = ::onDone, - ).also(EventThread::start) + eventThread = + EventThread(onProcessEvent = ::onProcessEvent, onDone = ::onDone) + .also(EventThread::start) } override fun fireTestStarted(description: Description) { @@ -112,54 +111,55 @@ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotif /* Private */ - private fun onProcessEvent(event: Event) = executor.submit { - val description = event.description - - when (event) { - is Event.Started -> { - delegate.fireTestStarted(description) - printer.testStarted(description) + private fun onProcessEvent(event: Event) = + executor.submit { + val description = event.description - // Persist the current printer state for this test - // (for later, when this test's finish event comes in) - states[description.uniqueIdentifier] = printer.captureTestState() - } - - is Event.Ignored -> { - delegate.fireTestIgnored(description) - printer.testIgnored(description) - } + when (event) { + is Event.Started -> { + delegate.fireTestStarted(description) + printer.testStarted(description) - is Event.Finished -> { - // Restore the printer state to the current test case, - // then fire the relevant lifecycle methods of the delegate notifier - printer.restoreTestState(description) - - // For failed test cases, always invoke the failure methods first, - // but invoke the 'finished' method pair for all cases - when { - event.testFailure != null -> { - delegate.fireTestFailure(event.testFailure) - printer.testFailure(event.testFailure) - delegate.fireTestFinished(description) - printer.testFinished(description) - } + // Persist the current printer state for this test + // (for later, when this test's finish event comes in) + states[description.uniqueIdentifier] = printer.captureTestState() + } - event.assumptionFailure != null -> { - delegate.fireTestAssumptionFailed(event.assumptionFailure) - printer.testAssumptionFailure(event.assumptionFailure) - delegate.fireTestFinished(description) - printer.testFinished(description) - } + is Event.Ignored -> { + delegate.fireTestIgnored(description) + printer.testIgnored(description) + } - else -> { - delegate.fireTestFinished(description) - printer.testFinished(description) + is Event.Finished -> { + // Restore the printer state to the current test case, + // then fire the relevant lifecycle methods of the delegate notifier + printer.restoreTestState(description) + + // For failed test cases, always invoke the failure methods first, + // but invoke the 'finished' method pair for all cases + when { + event.testFailure != null -> { + delegate.fireTestFailure(event.testFailure) + printer.testFailure(event.testFailure) + delegate.fireTestFinished(description) + printer.testFinished(description) + } + + event.assumptionFailure != null -> { + delegate.fireTestAssumptionFailed(event.assumptionFailure) + printer.testAssumptionFailure(event.assumptionFailure) + delegate.fireTestFinished(description) + printer.testFinished(description) + } + + else -> { + delegate.fireTestFinished(description) + printer.testFinished(description) + } } } } } - } private fun onDone(description: Description?) { synchronized(doneLock) { @@ -191,8 +191,7 @@ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotif } private val Description.uniqueIdentifier - get() = - "$className-$displayName" + get() = "$className-$displayName" private class EventThread( private val onProcessEvent: (Event) -> Unit, @@ -202,6 +201,7 @@ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotif val description: Description data class Started(override val description: Description) : Event + data class Finished( override val description: Description, val testFailure: Failure? = null, @@ -285,21 +285,29 @@ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotif @Suppress("UNCHECKED_CAST") private class Reflection { - private fun Class.field(name: String) = this.getDeclaredField(name).also { it.isAccessible = true } + private fun Class.field(name: String) = + this.getDeclaredField(name).also { it.isAccessible = true } - private val synchronizedRunListenerClass = Class.forName("org.junit.runner.notification.SynchronizedRunListener") - private val synchronizedListenerDelegateField = synchronizedRunListenerClass.field("listener") + private val synchronizedRunListenerClass = + Class.forName("org.junit.runner.notification.SynchronizedRunListener") + private val synchronizedListenerDelegateField = + synchronizedRunListenerClass.field("listener") private val runNotifierListenersField = RunNotifier::class.java.field("listeners") - private val resultPrinterTestResultField = InstrumentationResultPrinter::class.java.field("testResult") - private val resultPrinterTestResultCodeField = InstrumentationResultPrinter::class.java.field("testResultCode") - private val resultPrinterTestClassField = InstrumentationResultPrinter::class.java.field("testClass") + private val resultPrinterTestResultField = + InstrumentationResultPrinter::class.java.field("testResult") + private val resultPrinterTestResultCodeField = + InstrumentationResultPrinter::class.java.field("testResultCode") + private val resultPrinterTestClassField = + InstrumentationResultPrinter::class.java.field("testClass") private var cached: InstrumentationResultPrinter? = null fun initialize(notifier: RunNotifier): InstrumentationResultPrinter? { try { // The printer needs to be retrieved only once per test run - cached?.let { return it } + cached?.let { + return it + } // The Android system registers a global listener // for communicating status events back to the instrumentation. @@ -311,9 +319,10 @@ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotif // The Android instrumentation may wrap the printer inside another JUnit listener, // so make sure to search for the result inside its toString() representation // (rather than through an 'it is X' check) - val candidate = listeners?.firstOrNull { - InstrumentationResultPrinter::class.java.name in it.toString() - } + val candidate = + listeners?.firstOrNull { + InstrumentationResultPrinter::class.java.name in it.toString() + } if (candidate != null) { // Replace the original listener with a wrapped version of itself, @@ -326,11 +335,13 @@ internal class ParallelRunNotifier(private val delegate: RunNotifier) : RunNotif // The Android instrumentation may wrap the printer inside another JUnit listener, // so make sure to search for the result inside its toString() representation // (rather than through an 'it is X' check) - val result = if (synchronizedRunListenerClass.isInstance(candidate)) { - synchronizedListenerDelegateField.get(candidate) as? InstrumentationResultPrinter - } else { - candidate as? InstrumentationResultPrinter - } + val result = + if (synchronizedRunListenerClass.isInstance(candidate)) { + synchronizedListenerDelegateField.get(candidate) + as? InstrumentationResultPrinter + } else { + candidate as? InstrumentationResultPrinter + } cached = result return result diff --git a/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/RunnerConstants.kt b/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/RunnerConstants.kt index 8ef01d5c..b6a86743 100644 --- a/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/RunnerConstants.kt +++ b/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/RunnerConstants.kt @@ -1,7 +1,7 @@ package de.mannodermaus.junit5.internal /** - * The minimum Android API level on which JUnit Framework tests may be executed. - * Trying to launch a test on an older device will simply mark it as 'skipped'. + * The minimum Android API level on which JUnit Framework tests may be executed. Trying to launch a + * test on an older device will simply mark it as 'skipped'. */ internal const val JUNIT_FRAMEWORK_MINIMUM_SDK_VERSION: Int = 35 diff --git a/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyConfigurationParameters.kt b/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyConfigurationParameters.kt index db7dbf3b..407fc5e8 100644 --- a/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyConfigurationParameters.kt +++ b/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/discovery/EmptyConfigurationParameters.kt @@ -1,15 +1,15 @@ package de.mannodermaus.junit5.internal.discovery import androidx.annotation.RequiresApi -import org.junit.platform.engine.ConfigurationParameters import java.util.Optional +import org.junit.platform.engine.ConfigurationParameters -/** - * JUnit 6 version of the [ConfigurationParameters] interface. - */ +/** JUnit 6 version of the [ConfigurationParameters] interface. */ @RequiresApi(26) internal object EmptyConfigurationParameters : ConfigurationParameters { override fun get(key: String) = Optional.empty() + override fun getBoolean(key: String) = Optional.empty() + override fun keySet() = emptySet() } diff --git a/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/runners/TestPlanAdapter.kt b/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/runners/TestPlanAdapter.kt index 837778a8..842c24bc 100644 --- a/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/runners/TestPlanAdapter.kt +++ b/instrumentation/runner/src/six/kotlin/de/mannodermaus/junit5/internal/runners/TestPlanAdapter.kt @@ -2,13 +2,10 @@ package de.mannodermaus.junit5.internal.runners import org.junit.platform.launcher.TestPlan -/** - * JUnit 6 version of the [TestPlanAdapter]. - */ -internal open class TestPlanAdapter( - val delegate: TestPlan -) : TestPlan( - /* containsTests = */ delegate.containsTests(), - /* configurationParameters = */ delegate.configurationParameters, - /* outputDirectoryCreator = */ delegate.outputDirectoryCreator -) +/** JUnit 6 version of the [TestPlanAdapter]. */ +internal open class TestPlanAdapter(val delegate: TestPlan) : + TestPlan( + /* containsTests = */ delegate.containsTests(), + /* configurationParameters = */ delegate.configurationParameters, + /* outputDirectoryCreator = */ delegate.outputDirectoryCreator, + ) diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilderTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilderTests.kt index 6fc73aa0..46a4d583 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilderTests.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/AndroidJUnitFrameworkBuilderTests.kt @@ -14,35 +14,38 @@ class AndroidJUnitFrameworkBuilderTests { private val builder = AndroidJUnitFrameworkBuilder() @TestFactory - fun `no runner is created if class only contains top-level test methods`() = runTest( - expectSuccess = false, - // In Kotlin, a 'Kt'-suffixed class of top-level functions cannot be referenced - // via the ::class syntax, so construct a reference to the class directly - Class.forName(javaClass.packageName + ".TestClassesKt") - ) + fun `no runner is created if class only contains top-level test methods`() = + runTest( + expectSuccess = false, + // In Kotlin, a 'Kt'-suffixed class of top-level functions cannot be referenced + // via the ::class syntax, so construct a reference to the class directly + Class.forName(javaClass.packageName + ".TestClassesKt"), + ) @TestFactory - fun `runner is created correctly for classes with valid jupiter test methods`() = runTest( - expectSuccess = true, - HasTest::class.java, - HasRepeatedTest::class.java, - HasTestFactory::class.java, - HasTestTemplate::class.java, - HasParameterizedTest::class.java, - HasInnerClassWithTest::class.java, - HasTaggedTest::class.java, - HasInheritedTestsFromClass::class.java, - HasInheritedTestsFromInterface::class.java, - HasMultipleInheritancesAndOverrides::class.java, - ) + fun `runner is created correctly for classes with valid jupiter test methods`() = + runTest( + expectSuccess = true, + HasTest::class.java, + HasRepeatedTest::class.java, + HasTestFactory::class.java, + HasTestTemplate::class.java, + HasParameterizedTest::class.java, + HasInnerClassWithTest::class.java, + HasTaggedTest::class.java, + HasInheritedTestsFromClass::class.java, + HasInheritedTestsFromInterface::class.java, + HasMultipleInheritancesAndOverrides::class.java, + ) @TestFactory - fun `no runner is created if class has no jupiter test methods`() = runTest( - expectSuccess = false, - DoesntHaveTestMethods::class.java, - HasJUnit4Tests::class.java, - kotlin.time.Duration::class.java, - ) + fun `no runner is created if class has no jupiter test methods`() = + runTest( + expectSuccess = false, + DoesntHaveTestMethods::class.java, + HasJUnit4Tests::class.java, + kotlin.time.Duration::class.java, + ) /* Private */ @@ -52,20 +55,21 @@ class AndroidJUnitFrameworkBuilderTests { return classes.map { cls -> dynamicContainer( /* displayName = */ cls.name, - /* dynamicNodes = */ setOf(Build.VERSION_CODES.M, Build.VERSION_CODES.TIRAMISU).map { apiLevel -> - dynamicTest("API Level $apiLevel") { - withMockedInstrumentation { - withApiLevel(apiLevel) { - val runner = builder.runnerForClass(cls) - if (expectSuccess) { - assertThat(runner).isNotNull() - } else { - assertThat(runner).isNull() + /* dynamicNodes = */ setOf(Build.VERSION_CODES.M, Build.VERSION_CODES.TIRAMISU) + .map { apiLevel -> + dynamicTest("API Level $apiLevel") { + withMockedInstrumentation { + withApiLevel(apiLevel) { + val runner = builder.runnerForClass(cls) + if (expectSuccess) { + assertThat(runner).isNotNull() + } else { + assertThat(runner).isNull() + } } } } - } - } + }, ) } } diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/TestClasses.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/TestClasses.kt index 3e75ab2d..d3cff471 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/TestClasses.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/TestClasses.kt @@ -1,118 +1,93 @@ package de.mannodermaus.junit5 +import java.util.stream.Stream import org.junit.jupiter.api.* import org.junit.jupiter.api.DynamicTest.dynamicTest import org.junit.jupiter.api.extension.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource import org.junit.jupiter.params.provider.ValueSource -import java.util.stream.Stream class DoesntHaveTestMethods class HasTest { - @Test - fun method() { - } + @Test fun method() {} } class HasRepeatedTest { - @RepeatedTest(5) - fun method(info: RepetitionInfo) { - } + @RepeatedTest(5) fun method(info: RepetitionInfo) {} } class HasTestFactory { - @TestFactory - fun method() = listOf( - dynamicTest("a") {}, - dynamicTest("b") {} - ) + @TestFactory fun method() = listOf(dynamicTest("a") {}, dynamicTest("b") {}) } class HasTestTemplate { - @TestTemplate - @ExtendWith(ExampleInvocationContextProvider::class) - fun method(param: String) { - } - - class ExampleInvocationContextProvider : TestTemplateInvocationContextProvider { - override fun provideTestTemplateInvocationContexts(context: ExtensionContext): Stream = - listOf("param1", "param2") - .map(this::context) - .stream() - - override fun supportsTestTemplate(context: ExtensionContext) = true - - private fun context(param: String): TestTemplateInvocationContext = - object : TestTemplateInvocationContext { - override fun getDisplayName(invocationIndex: Int): String = param - - override fun getAdditionalExtensions() = listOf( - object : ParameterResolver { - override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext) = - parameterContext.parameter.type == String::class.java - - override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext) = - param - } - ) - } - } + @TestTemplate @ExtendWith(ExampleInvocationContextProvider::class) fun method(param: String) {} + + class ExampleInvocationContextProvider : TestTemplateInvocationContextProvider { + override fun provideTestTemplateInvocationContexts( + context: ExtensionContext + ): Stream = + listOf("param1", "param2").map(this::context).stream() + + override fun supportsTestTemplate(context: ExtensionContext) = true + + private fun context(param: String): TestTemplateInvocationContext = + object : TestTemplateInvocationContext { + override fun getDisplayName(invocationIndex: Int): String = param + + override fun getAdditionalExtensions() = + listOf( + object : ParameterResolver { + override fun supportsParameter( + parameterContext: ParameterContext, + extensionContext: ExtensionContext, + ) = parameterContext.parameter.type == String::class.java + + override fun resolveParameter( + parameterContext: ParameterContext, + extensionContext: ExtensionContext, + ) = param + } + ) + } + } } class HasParameterizedTest { - @ParameterizedTest - @CsvSource("a", "b") - fun method(param: String) { - } + @ParameterizedTest @CsvSource("a", "b") fun method(param: String) {} } class HasInnerClassWithTest { - @Nested - inner class InnerClass { - @Test - fun method() { + @Nested + inner class InnerClass { + @Test fun method() {} } - } } class HasTaggedTest { - @Tag("slow") - @Test - fun method() { - - } + @Tag("slow") @Test fun method() {} } abstract class AbstractTestClass { - @Test - open fun abstractTest() { - } + @Test open fun abstractTest() {} } interface AbstractTestInterface { - @Test - fun interfaceTest() { - } + @Test fun interfaceTest() {} } class HasInheritedTestsFromClass : AbstractTestClass() { - @Test - fun method() { - } + @Test fun method() {} } class HasInheritedTestsFromInterface : AbstractTestInterface class HasMultipleInheritancesAndOverrides : AbstractTestClass(), AbstractTestInterface { - @Test - override fun abstractTest() { - } + @Test override fun abstractTest() {} - @Test - fun someOtherTest() { - } + @Test fun someOtherTest() {} } // These tests should not be acknowledged, @@ -120,19 +95,15 @@ class HasMultipleInheritancesAndOverrides : AbstractTestClass(), AbstractTestInt // are unsupported by JUnit 5 class HasJUnit4Tests { - @org.junit.Test - fun method() {} + @org.junit.Test fun method() {} } -@RepeatedTest(2) -fun topLevelRepeatedTest(unused: RepetitionInfo) {} +@RepeatedTest(2) fun topLevelRepeatedTest(unused: RepetitionInfo) {} @ValueSource(strings = ["a", "b"]) @ParameterizedTest fun topLevelParameterizedTest(unused: String) {} -@TestTemplate -fun topLevelTestTemplate() {} +@TestTemplate fun topLevelTestTemplate() {} -@TestFactory -fun topLevelTestFactory(): Stream = Stream.empty() +@TestFactory fun topLevelTestFactory(): Stream = Stream.empty() diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/TestHelpers.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/TestHelpers.kt index 26be67cb..0abd7ee9 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/TestHelpers.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/TestHelpers.kt @@ -1,30 +1,31 @@ package de.mannodermaus.junit5 +import kotlin.reflect.KClass import org.junit.platform.engine.discovery.DiscoverySelectors import org.junit.platform.launcher.Launcher import org.junit.platform.launcher.TestPlan import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder import org.junit.platform.launcher.core.LauncherFactory -import kotlin.reflect.KClass /** - * A quick one-liner for executing a Jupiter discover-and-execute pass - * from inside of a Jupiter test. Useful for testing runner code - * that needs to work with the innards of the [TestPlan], such as - * individual test identifiers and such. + * A quick one-liner for executing a Jupiter discover-and-execute pass from inside of a Jupiter + * test. Useful for testing runner code that needs to work with the innards of the [TestPlan], such + * as individual test identifiers and such. */ fun discoverTests( cls: KClass<*>, launcher: Launcher = LauncherFactory.create(), executeAsWell: Boolean = true, ): TestPlan { - return launcher.discover( - LauncherDiscoveryRequestBuilder.request() - .selectors(DiscoverySelectors.selectClass(cls.java)) - .build() - ).also { plan -> - if (executeAsWell) { - launcher.execute(plan) + return launcher + .discover( + LauncherDiscoveryRequestBuilder.request() + .selectors(DiscoverySelectors.selectClass(cls.java)) + .build() + ) + .also { plan -> + if (executeAsWell) { + launcher.execute(plan) + } } - } } diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/discovery/PropertiesParserTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/discovery/PropertiesParserTests.kt index 2c2970af..6aadba25 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/discovery/PropertiesParserTests.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/discovery/PropertiesParserTests.kt @@ -5,39 +5,31 @@ import org.junit.jupiter.api.Test class PropertiesParserTests { - @Test - fun `test valid string, containing one entry`() { - val string = "KEY1=true" - val variables = PropertiesParser.fromString(string) - assertThat(variables).containsExactly( - "KEY1", "true" - ) - } + @Test + fun `test valid string, containing one entry`() { + val string = "KEY1=true" + val variables = PropertiesParser.fromString(string) + assertThat(variables).containsExactly("KEY1", "true") + } - @Test - fun `test valid string, containing multiple entries`() { - val string = "KEY1=true,KEY2=123,KEY3=lol" - val variables = PropertiesParser.fromString(string) - assertThat(variables).containsExactly( - "KEY1", "true", - "KEY2", "123", - "KEY3", "lol" - ) - } + @Test + fun `test valid string, containing multiple entries`() { + val string = "KEY1=true,KEY2=123,KEY3=lol" + val variables = PropertiesParser.fromString(string) + assertThat(variables).containsExactly("KEY1", "true", "KEY2", "123", "KEY3", "lol") + } - @Test - fun `test invalid string, filter out those entries`() { - val string = "KEY1=true,INVALID1,INVALID2=lol=lolol,1234567" - val variables = PropertiesParser.fromString(string) - assertThat(variables).containsExactly( - "KEY1", "true" - ) - } + @Test + fun `test invalid string, filter out those entries`() { + val string = "KEY1=true,INVALID1,INVALID2=lol=lolol,1234567" + val variables = PropertiesParser.fromString(string) + assertThat(variables).containsExactly("KEY1", "true") + } - @Test - fun `test invalid string, return empty map`() { - val string = "" - val variables = PropertiesParser.fromString(string) - assertThat(variables).isEmpty() - } + @Test + fun `test invalid string, return empty map`() { + val string = "" + val variables = PropertiesParser.fromString(string) + assertThat(variables).isEmpty() + } } diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt index b3d684e1..439b19dd 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/dummy/JupiterTestMethodFinderTests.kt @@ -31,19 +31,20 @@ import org.junit.runner.notification.RunNotifier class JupiterTestMethodFinderTests { // Each element is a Pair of 'test class' and 'number of expected tests' - private val classes = listOf( - DoesntHaveTestMethods::class.java to 0, - HasTaggedTest::class.java to 1, - HasTest::class.java to 1, - HasRepeatedTest::class.java to 5, - HasTestFactory::class.java to 2, - HasTestTemplate::class.java to 2, - HasParameterizedTest::class.java to 2, - HasInnerClassWithTest::class.java to 1, - HasInheritedTestsFromClass::class.java to 2, - HasInheritedTestsFromInterface::class.java to 1, - HasMultipleInheritancesAndOverrides::class.java to 3, - ) + private val classes = + listOf( + DoesntHaveTestMethods::class.java to 0, + HasTaggedTest::class.java to 1, + HasTest::class.java to 1, + HasRepeatedTest::class.java to 5, + HasTestFactory::class.java to 2, + HasTestTemplate::class.java to 2, + HasParameterizedTest::class.java to 2, + HasInnerClassWithTest::class.java to 1, + HasInheritedTestsFromClass::class.java to 2, + HasInheritedTestsFromInterface::class.java to 1, + HasMultipleInheritancesAndOverrides::class.java to 3, + ) private val allFinders = setOf(JupiterTestMethodFinder) @@ -59,7 +60,9 @@ class JupiterTestMethodFinderTests { assertThat(methods).isNotEmpty() val result = runJUnit5(cls) - assertWithMessage("Executed ${result.count()} instead of $testCount tests on class '${cls.simpleName}': '${result.methodNames()}'") + assertWithMessage( + "Executed ${result.count()} instead of $testCount tests on class '${cls.simpleName}': '${result.methodNames()}'" + ) .that(result.count()) .isEqualTo(testCount) } @@ -69,12 +72,12 @@ class JupiterTestMethodFinderTests { @Test fun `check that tag filter works`() { - val result = runJUnit5( - cls = HasTaggedTest::class.java, - filter = TagFilter.excludeTags("slow"), - ) + val result = + runJUnit5(cls = HasTaggedTest::class.java, filter = TagFilter.excludeTags("slow")) - assertWithMessage("Executed ${result.count()} instead of 0 tests: '${result.methodNames()}'") + assertWithMessage( + "Executed ${result.count()} instead of 0 tests: '${result.methodNames()}'" + ) .that(result.count()) .isEqualTo(0) } @@ -83,17 +86,11 @@ class JupiterTestMethodFinderTests { private fun testForEachFinder(block: (JupiterTestMethodFinder) -> List) = allFinders.map { finder -> - dynamicContainer( - "using ${finder.javaClass.simpleName}", - block(finder), - ) + dynamicContainer("using ${finder.javaClass.simpleName}", block(finder)) } @CheckResult - private fun runJUnit5( - cls: Class<*>, - filter: Filter<*>? = null, - ): CountingRunListener { + private fun runJUnit5(cls: Class<*>, filter: Filter<*>? = null): CountingRunListener { // Verify number of executed test cases as well val notifier = RunNotifier() val listener = CountingRunListener() diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/formatters/TestNameFormatterTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/formatters/TestNameFormatterTests.kt index 4ccdc08f..4beb2bc3 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/formatters/TestNameFormatterTests.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/formatters/TestNameFormatterTests.kt @@ -8,73 +8,76 @@ import de.mannodermaus.junit5.HasTestFactory import de.mannodermaus.junit5.HasTestTemplate import de.mannodermaus.junit5.discoverTests import de.mannodermaus.junit5.internal.extensions.format +import kotlin.reflect.KClass import org.junit.jupiter.api.Test -import org.junit.platform.engine.discovery.DiscoverySelectors import org.junit.platform.launcher.TestIdentifier import org.junit.platform.launcher.TestPlan -import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder -import org.junit.platform.launcher.core.LauncherFactory -import kotlin.reflect.KClass class TestNameFormatterTests { @Test - fun `normal junit5 test`() = runTestWith(HasTest::class) { identifier -> - assertThat(identifier.format(false)).isEqualTo("method") - assertThat(identifier.format(true)).isEqualTo("method") - } + fun `normal junit5 test`() = + runTestWith(HasTest::class) { identifier -> + assertThat(identifier.format(false)).isEqualTo("method") + assertThat(identifier.format(true)).isEqualTo("method") + } @Test - fun `repeated test`() = runTestWith(HasRepeatedTest::class) { identifier -> - assertThat(identifier.format(false)).isEqualTo("method[RepetitionInfo]") - assertThat(identifier.format(true)).isEqualTo("method") - - // Inspect individual executions, too - assertChildren(identifier, expectedCount = 5) { index, child -> - val number = index + 1 - assertThat(child.format(false)).isEqualTo("repetition $number of 5") - assertThat(child.format(true)).isEqualTo("method[$number]") + fun `repeated test`() = + runTestWith(HasRepeatedTest::class) { identifier -> + assertThat(identifier.format(false)).isEqualTo("method[RepetitionInfo]") + assertThat(identifier.format(true)).isEqualTo("method") + + // Inspect individual executions, too + assertChildren(identifier, expectedCount = 5) { index, child -> + val number = index + 1 + assertThat(child.format(false)).isEqualTo("repetition $number of 5") + assertThat(child.format(true)).isEqualTo("method[$number]") + } } - } @Test - fun `test factory`() = runTestWith(HasTestFactory::class) { identifier -> - assertThat(identifier.format(false)).isEqualTo("method") - assertThat(identifier.format(true)).isEqualTo("method") - - // Inspect individual executions, too - assertChildren(identifier, expectedCount = 2) { index, child -> - val number = index + 1 - assertThat(child.format(false)).isEqualTo(if (index == 0) "a" else "b") - assertThat(child.format(true)).isEqualTo("method[$number]") + fun `test factory`() = + runTestWith(HasTestFactory::class) { identifier -> + assertThat(identifier.format(false)).isEqualTo("method") + assertThat(identifier.format(true)).isEqualTo("method") + + // Inspect individual executions, too + assertChildren(identifier, expectedCount = 2) { index, child -> + val number = index + 1 + assertThat(child.format(false)).isEqualTo(if (index == 0) "a" else "b") + assertThat(child.format(true)).isEqualTo("method[$number]") + } } - } @Test - fun `test template`() = runTestWith(HasTestTemplate::class) { identifier -> - assertThat(identifier.format(false)).isEqualTo("method[String]") - assertThat(identifier.format(true)).isEqualTo("method") - - // Inspect individual executions, too - assertChildren(identifier, expectedCount = 2) { index, child -> - val number = index + 1 - assertThat(child.format(false)).isEqualTo("param$number") - assertThat(child.format(true)).isEqualTo("method[$number]") + fun `test template`() = + runTestWith(HasTestTemplate::class) { identifier -> + assertThat(identifier.format(false)).isEqualTo("method[String]") + assertThat(identifier.format(true)).isEqualTo("method") + + // Inspect individual executions, too + assertChildren(identifier, expectedCount = 2) { index, child -> + val number = index + 1 + assertThat(child.format(false)).isEqualTo("param$number") + assertThat(child.format(true)).isEqualTo("method[$number]") + } } - } @Test - fun `parameterized test`() = runTestWith(HasParameterizedTest::class) { identifier -> - assertThat(identifier.format(false)).isEqualTo("method[String]") - assertThat(identifier.format(true)).isEqualTo("method") - - // Inspect individual executions, too - assertChildren(identifier, expectedCount = 2) { index, child -> - val number = index + 1 - assertThat(child.format(false)).isEqualTo("[$number] " + if (index == 0) "a" else "b") - assertThat(child.format(true)).isEqualTo("method[$number]") + fun `parameterized test`() = + runTestWith(HasParameterizedTest::class) { identifier -> + assertThat(identifier.format(false)).isEqualTo("method[String]") + assertThat(identifier.format(true)).isEqualTo("method") + + // Inspect individual executions, too + assertChildren(identifier, expectedCount = 2) { index, child -> + val number = index + 1 + assertThat(child.format(false)) + .isEqualTo("[$number] " + if (index == 0) "a" else "b") + assertThat(child.format(true)).isEqualTo("method[$number]") + } } - } /* Private */ @@ -98,7 +101,7 @@ class TestNameFormatterTests { private fun TestPlan.assertChildren( of: TestIdentifier, expectedCount: Int, - block: (Int, TestIdentifier) -> Unit + block: (Int, TestIdentifier) -> Unit, ) { with(getChildren(of)) { assertThat(size).isEqualTo(expectedCount) diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFrameworkTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFrameworkTests.kt index 6f571535..f9387287 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFrameworkTests.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitFrameworkTests.kt @@ -4,6 +4,7 @@ import android.os.Bundle import com.google.common.truth.Truth.assertThat import de.mannodermaus.junit5.testutil.AndroidBuildUtils.withMockedInstrumentation import de.mannodermaus.junit5.testutil.CollectingRunListener +import java.util.concurrent.atomic.AtomicReference import org.junit.jupiter.api.DynamicContainer import org.junit.jupiter.api.DynamicContainer.dynamicContainer import org.junit.jupiter.api.DynamicTest.dynamicTest @@ -15,7 +16,6 @@ import org.junit.jupiter.params.provider.ValueSource import org.junit.runner.RunWith import org.junit.runner.notification.RunNotifier import org.robolectric.RobolectricTestRunner -import java.util.concurrent.atomic.AtomicReference @RunWith(RobolectricTestRunner::class) class AndroidJUnitFrameworkTests { @@ -25,16 +25,17 @@ class AndroidJUnitFrameworkTests { val results = runTests() val successNames = results.runTestNames - assertThat(successNames).containsExactly( - "normal test", - "testFactory - container - test 1", - "testFactory - container - test 2", - "repeatedTest - repetition 1 of 3", - "repeatedTest - repetition 2 of 3", - "repeatedTest - repetition 3 of 3", - "parameterizedTest(String) - [1] hello", - "parameterizedTest(String) - [2] world", - ) + assertThat(successNames) + .containsExactly( + "normal test", + "testFactory - container - test 1", + "testFactory - container - test 2", + "repeatedTest - repetition 1 of 3", + "repeatedTest - repetition 2 of 3", + "repeatedTest - repetition 3 of 3", + "parameterizedTest(String) - [1] hello", + "parameterizedTest(String) - [2] world", + ) } @org.junit.Test @@ -48,13 +49,15 @@ class AndroidJUnitFrameworkTests { val allResults = mutableListOf() for (i in 0..4) { - val results = runTests( - shardingConfig = if (i < 4) { - ShardingConfig(num = 4, index = i) - } else { - null - } - ) + val results = + runTests( + shardingConfig = + if (i < 4) { + ShardingConfig(num = 4, index = i) + } else { + null + } + ) if (i == 4) { // Last execution should execute all tests together @@ -67,9 +70,7 @@ class AndroidJUnitFrameworkTests { } } - allResults.forEach { results -> - assertThat(results.runCount).isLessThan(totalTests) - } + allResults.forEach { results -> assertThat(results.runCount).isLessThan(totalTests) } } /* Private */ @@ -90,12 +91,13 @@ class AndroidJUnitFrameworkTests { return resultRef.get() } - private fun buildArgs(shardingConfig: ShardingConfig?) = Bundle().apply { - if (shardingConfig != null) { - putString("numShards", shardingConfig.num.toString()) - putString("shardIndex", shardingConfig.index.toString()) + private fun buildArgs(shardingConfig: ShardingConfig?) = + Bundle().apply { + if (shardingConfig != null) { + putString("numShards", shardingConfig.num.toString()) + putString("shardIndex", shardingConfig.index.toString()) + } } - } // JUnit Vintage Engine reports an empty event and must be excluded. // Because of this, only count tests with an attached method name @@ -104,32 +106,21 @@ class AndroidJUnitFrameworkTests { private val CollectingRunListener.Results.runCount get() = runTestNames.size - } /* Data */ @Suppress("ClassName") internal class Sample_NormalTests { - @Test - fun `normal test`() { - } + @Test fun `normal test`() {} @TestFactory - fun testFactory(): DynamicContainer = dynamicContainer( - "container", - listOf( - dynamicTest("test 1") {}, - dynamicTest("test 2") {}, - ) - ) - - @RepeatedTest(3) - fun repeatedTest() { - } + fun testFactory(): DynamicContainer = + dynamicContainer("container", listOf(dynamicTest("test 1") {}, dynamicTest("test 2") {})) + + @RepeatedTest(3) fun repeatedTest() {} @ValueSource(strings = ["hello", "world"]) @ParameterizedTest - fun parameterizedTest(param: String) { - } -} \ No newline at end of file + fun parameterizedTest(param: String) {} +} diff --git a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformTestTreeTests.kt b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformTestTreeTests.kt index 2fc30771..6e6fe366 100644 --- a/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformTestTreeTests.kt +++ b/instrumentation/runner/src/test/kotlin/de/mannodermaus/junit5/internal/runners/AndroidJUnitPlatformTestTreeTests.kt @@ -7,18 +7,15 @@ import de.mannodermaus.junit5.HasTest import de.mannodermaus.junit5.HasTestFactory import de.mannodermaus.junit5.HasTestTemplate import de.mannodermaus.junit5.discoverTests +import kotlin.reflect.KClass import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource import org.junit.platform.launcher.TestExecutionListener import org.junit.platform.launcher.TestIdentifier import org.junit.platform.launcher.core.LauncherFactory -import kotlin.reflect.KClass class AndroidJUnitPlatformTestTreeTests { - @CsvSource( - "false, method", - "true, method", - ) + @CsvSource("false, method", "true, method") @ParameterizedTest fun test(isolated: Boolean, expected: String) = runTestWith(HasTest::class, isolated) { identifier -> @@ -26,10 +23,7 @@ class AndroidJUnitPlatformTestTreeTests { assertThat(description.methodName).isEqualTo(expected) } - @CsvSource( - "false, method[RepetitionInfo] - repetition %d of 5", - "true, method[%d]", - ) + @CsvSource("false, method[RepetitionInfo] - repetition %d of 5", "true, method[%d]") @ParameterizedTest fun `repeated test`(isolated: Boolean, expected: String) = runTestWith(HasRepeatedTest::class, isolated) { identifier -> @@ -40,10 +34,7 @@ class AndroidJUnitPlatformTestTreeTests { } } - @CsvSource( - "false, method - %s", - "true, method[%d]", - ) + @CsvSource("false, method - %s", "true, method[%d]") @ParameterizedTest fun `test factory`(isolated: Boolean, expected: String) = runTestWith(HasTestFactory::class, isolated) { identifier -> @@ -56,15 +47,13 @@ class AndroidJUnitPlatformTestTreeTests { if (isolated) { assertThat(childDescription.methodName).isEqualTo(expected.format(num)) } else { - assertThat(childDescription.methodName).isEqualTo(expected.format(childMethodNames[index])) + assertThat(childDescription.methodName) + .isEqualTo(expected.format(childMethodNames[index])) } } } - @CsvSource( - "false, method[String] - %s", - "true, method[%d]", - ) + @CsvSource("false, method[String] - %s", "true, method[%d]") @ParameterizedTest fun `test template`(isolated: Boolean, expected: String) = runTestWith(HasTestTemplate::class, isolated) { identifier -> @@ -77,15 +66,13 @@ class AndroidJUnitPlatformTestTreeTests { if (isolated) { assertThat(childDescription.methodName).isEqualTo(expected.format(num)) } else { - assertThat(childDescription.methodName).isEqualTo(expected.format(childMethodNames[index])) + assertThat(childDescription.methodName) + .isEqualTo(expected.format(childMethodNames[index])) } } } - @CsvSource( - "false, method[String] - [%d] %s", - "true, method[%d]", - ) + @CsvSource("false, method[String] - [%d] %s", "true, method[%d]") @ParameterizedTest fun `parameterized test`(isolated: Boolean, expected: String) = runTestWith(HasParameterizedTest::class, isolated) { identifier -> @@ -98,7 +85,8 @@ class AndroidJUnitPlatformTestTreeTests { if (isolated) { assertThat(childDescription.methodName).isEqualTo(expected.format(num)) } else { - assertThat(childDescription.methodName).isEqualTo(expected.format(num, childMethodNames[index])) + assertThat(childDescription.methodName) + .isEqualTo(expected.format(num, childMethodNames[index])) } } } @@ -113,20 +101,24 @@ class AndroidJUnitPlatformTestTreeTests { // Prepare a test plan to launch val launcher = LauncherFactory.create() val plan = discoverTests(cls, launcher, executeAsWell = false) - val tree = AndroidJUnitPlatformTestTree( - testPlan = plan, - testClass = cls.java, - needLegacyFormat = isIsolatedMethodRun, - isParallelExecutionEnabled = false, - ) + val tree = + AndroidJUnitPlatformTestTree( + testPlan = plan, + testClass = cls.java, + needLegacyFormat = isIsolatedMethodRun, + isParallelExecutionEnabled = false, + ) // Execute the test plan, adding dynamic tests with the tree // as they are registered during execution - launcher.execute(plan, object : TestExecutionListener { - override fun dynamicTestRegistered(testIdentifier: TestIdentifier) { - tree.addDynamicDescription(testIdentifier, testIdentifier.parentId.get()) - } - }) + launcher.execute( + plan, + object : TestExecutionListener { + override fun dynamicTestRegistered(testIdentifier: TestIdentifier) { + tree.addDynamicDescription(testIdentifier, testIdentifier.parentId.get()) + } + }, + ) // For concrete assertions, delegate to the given block val root = plan.roots.first() @@ -138,7 +130,7 @@ class AndroidJUnitPlatformTestTreeTests { private fun AndroidJUnitPlatformTestTree.assertChildren( identifier: TestIdentifier, expectedCount: Int, - block: (Int, TestIdentifier) -> Unit + block: (Int, TestIdentifier) -> Unit, ) { with(getChildren(identifier)) { assertThat(size).isEqualTo(expectedCount) diff --git a/instrumentation/sample/build.gradle.kts b/instrumentation/sample/build.gradle.kts index 64d2201d..e70be489 100644 --- a/instrumentation/sample/build.gradle.kts +++ b/instrumentation/sample/build.gradle.kts @@ -15,7 +15,8 @@ android { versionCode = 1 versionName = "1.0" - // Make sure to use the AndroidJUnitRunner (or a sub-class) in order to hook in the JUnit 5 Test Builder + // Make sure to use the AndroidJUnitRunner (or a sub-class) in order to hook in the JUnit 5 + // Test Builder testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" // These two lines are not needed for a normal integration; @@ -25,23 +26,17 @@ android { testInstrumentationRunnerArguments["configurationParameters"] = "junit.jupiter.execution.parallel.enabled=true,junit.jupiter.execution.parallel.mode.default=concurrent" - buildFeatures { - buildConfig = true - } + buildFeatures { buildConfig = true } buildConfigField("boolean", "MY_VALUE", "true") - testOptions { - animationsDisabled = true - } + testOptions { animationsDisabled = true } } } junitPlatform { // Configure JUnit 5 tests here - filters("debug") { - excludeTags("slow") - } + filters("debug") { excludeTags("slow") } // Using local dependency instead of Maven coordinates instrumentationTests.enabled = false diff --git a/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/ActivityOneTest.kt b/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/ActivityOneTest.kt index 86bf8c4d..92b8c58b 100644 --- a/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/ActivityOneTest.kt +++ b/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/ActivityOneTest.kt @@ -10,6 +10,8 @@ import de.mannodermaus.junit5.ActivityScenarioExtension import de.mannodermaus.junit5.condition.EnabledIfBuildConfigValue import de.mannodermaus.junit5.sample.ActivityOne import de.mannodermaus.junit5.sample.R +import java.util.function.Supplier +import java.util.stream.Stream import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.RepeatedTest @@ -20,78 +22,71 @@ import org.junit.jupiter.api.extension.RegisterExtension import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.FieldSource import org.junit.jupiter.params.provider.ValueSource -import java.util.function.Supplier -import java.util.stream.Stream class ActivityOneTest { - companion object { - val someLettersOfTheAlphabet = Supplier { Stream.of("A", "B", "C") } - } - - @JvmField - @RegisterExtension - val scenarioExtension = ActivityScenarioExtension.launch() + companion object { + val someLettersOfTheAlphabet = Supplier { Stream.of("A", "B", "C") } + } - @DisplayName("test with pretty display name") - @Test - fun testDisplayName() { - onView(withId(R.id.textView)).check(matches(withText("0"))) - } + @JvmField + @RegisterExtension + val scenarioExtension = ActivityScenarioExtension.launch() - @EnabledIfBuildConfigValue(named = "MY_VALUE", matches = "true") - @Test - fun testExample(scenario: ActivityScenario) { - onView(withId(R.id.textView)).check(matches(withText("0"))) - } + @DisplayName("test with pretty display name") + @Test + fun testDisplayName() { + onView(withId(R.id.textView)).check(matches(withText("0"))) + } - // This test is disabled by default, because the sample module - // defines an excludeTags() clause for this tag in its build.gradle file - @Tag("slow") - @Test - fun disabledTest(scenario: ActivityScenario) { - onView(withId(R.id.textView)).check(matches(withText("0"))) - } + @EnabledIfBuildConfigValue(named = "MY_VALUE", matches = "true") + @Test + fun testExample(scenario: ActivityScenario) { + onView(withId(R.id.textView)).check(matches(withText("0"))) + } - @ValueSource(strings = ["value1", "value2"]) - @ParameterizedTest - fun parameterizedTestExample(value: String, scenario: ActivityScenario) { - scenario.onActivity { - assertEquals(0, it.getClickCount()) - it.setButtonLabel(value) + // This test is disabled by default, because the sample module + // defines an excludeTags() clause for this tag in its build.gradle file + @Tag("slow") + @Test + fun disabledTest(scenario: ActivityScenario) { + onView(withId(R.id.textView)).check(matches(withText("0"))) } - onView(withId(R.id.button)).check(matches(withText(value))) - onView(withId(R.id.button)).perform(click()) + @ValueSource(strings = ["value1", "value2"]) + @ParameterizedTest + fun parameterizedTestExample(value: String, scenario: ActivityScenario) { + scenario.onActivity { + assertEquals(0, it.getClickCount()) + it.setButtonLabel(value) + } - scenario.onActivity { - assertEquals(1, it.getClickCount()) - } - } + onView(withId(R.id.button)).check(matches(withText(value))) + onView(withId(R.id.button)).perform(click()) - @FieldSource("someLettersOfTheAlphabet") - @ParameterizedTest - fun parameterizedTestWithFieldSource(letter: String) { - scenarioExtension.scenario.onActivity { - it.setButtonLabel(letter) + scenario.onActivity { assertEquals(1, it.getClickCount()) } } - onView(withText(letter)).perform(click()) + @FieldSource("someLettersOfTheAlphabet") + @ParameterizedTest + fun parameterizedTestWithFieldSource(letter: String) { + scenarioExtension.scenario.onActivity { it.setButtonLabel(letter) } - scenarioExtension.scenario.onActivity { - assertEquals(1, it.getClickCount()) + onView(withText(letter)).perform(click()) + + scenarioExtension.scenario.onActivity { assertEquals(1, it.getClickCount()) } } - } - @RepeatedTest(3) - fun repeatedTestExample(repetitionInfo: RepetitionInfo, scenario: ActivityScenario) { - val count = repetitionInfo.currentRepetition + @RepeatedTest(3) + fun repeatedTestExample( + repetitionInfo: RepetitionInfo, + scenario: ActivityScenario, + ) { + val count = repetitionInfo.currentRepetition - for (i in 0 until count) { - onView(withId(R.id.button)).perform(click()) - } + for (i in 0 until count) { + onView(withId(R.id.button)).perform(click()) + } - scenario.onActivity { - assertEquals(count, it.getClickCount()) + scenario.onActivity { assertEquals(count, it.getClickCount()) } } - } } diff --git a/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/TestRunningOnJUnit4.kt b/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/TestRunningOnJUnit4.kt index 62568128..b2da7b3e 100644 --- a/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/TestRunningOnJUnit4.kt +++ b/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/TestRunningOnJUnit4.kt @@ -4,28 +4,28 @@ import org.junit.Assert import org.junit.Test class TestRunningOnJUnit4 { - @Test - fun junit4() { - Assert.assertEquals(4, 2 + 2) - } + @Test + fun junit4() { + Assert.assertEquals(4, 2 + 2) + } - @Test - fun junit4_2() { - Assert.assertEquals(4, 2 + 2) - } + @Test + fun junit4_2() { + Assert.assertEquals(4, 2 + 2) + } - @Test - fun junit4_3() { - Assert.assertEquals(4, 2 + 2) - } + @Test + fun junit4_3() { + Assert.assertEquals(4, 2 + 2) + } - @Test - fun junit4_4() { - Assert.assertEquals(4, 2 + 2) - } + @Test + fun junit4_4() { + Assert.assertEquals(4, 2 + 2) + } - @Test - fun junit4_5() { - Assert.assertEquals(4, 2 + 2) - } + @Test + fun junit4_5() { + Assert.assertEquals(4, 2 + 2) + } } diff --git a/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/TestTemplateExampleTests.kt b/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/TestTemplateExampleTests.kt index 7c40945e..e33a98a4 100644 --- a/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/TestTemplateExampleTests.kt +++ b/instrumentation/sample/src/androidTest/kotlin/de/mannodermaus/sample/TestTemplateExampleTests.kt @@ -1,5 +1,6 @@ package de.mannodermaus.sample +import java.util.stream.Stream import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.TestTemplate import org.junit.jupiter.api.extension.ExtendWith @@ -9,7 +10,6 @@ import org.junit.jupiter.api.extension.ParameterContext import org.junit.jupiter.api.extension.TestTemplateInvocationContext import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver -import java.util.stream.Stream class TestTemplateExampleTests { @TestTemplate @@ -19,21 +19,17 @@ class TestTemplateExampleTests { } } -data class TemplateTestCase( - val name: String, - val expectedLength: Int, -) +data class TemplateTestCase(val name: String, val expectedLength: Int) class NameAndLengthTemplateContextProvider : TestTemplateInvocationContextProvider { override fun supportsTestTemplate(context: ExtensionContext): Boolean { return true } - override fun provideTestTemplateInvocationContexts(context: ExtensionContext): Stream { - return Stream.of( - createCase("Alice", 5), - createCase("Bob", 3) - ) + override fun provideTestTemplateInvocationContexts( + context: ExtensionContext + ): Stream { + return Stream.of(createCase("Alice", 5), createCase("Bob", 3)) } private fun createCase(name: String, expected: Int): TestTemplateInvocationContext { @@ -45,11 +41,16 @@ class NameAndLengthTemplateContextProvider : TestTemplateInvocationContextProvid } override fun getAdditionalExtensions(): List { - return listOf(object : TypeBasedParameterResolver() { - override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): TemplateTestCase { - return testCase + return listOf( + object : TypeBasedParameterResolver() { + override fun resolveParameter( + parameterContext: ParameterContext, + extensionContext: ExtensionContext, + ): TemplateTestCase { + return testCase + } } - }) + ) } } } diff --git a/instrumentation/sample/src/main/kotlin/de/mannodermaus/junit5/sample/ActivityOne.kt b/instrumentation/sample/src/main/kotlin/de/mannodermaus/junit5/sample/ActivityOne.kt index 1e797793..2a35439b 100644 --- a/instrumentation/sample/src/main/kotlin/de/mannodermaus/junit5/sample/ActivityOne.kt +++ b/instrumentation/sample/src/main/kotlin/de/mannodermaus/junit5/sample/ActivityOne.kt @@ -7,25 +7,25 @@ import android.widget.TextView public class ActivityOne : Activity() { - private val textView by lazy { findViewById(R.id.textView) } - private val button by lazy { findViewById