diff --git a/android-junit5-tests/src/test/groovy/de/mannodermaus/gradle/plugins/junit5/DslGroovyTests.groovy b/android-junit5-tests/src/test/groovy/de/mannodermaus/gradle/plugins/junit5/DslGroovyTests.groovy index b58713f7..2d8e691e 100644 --- a/android-junit5-tests/src/test/groovy/de/mannodermaus/gradle/plugins/junit5/DslGroovyTests.groovy +++ b/android-junit5-tests/src/test/groovy/de/mannodermaus/gradle/plugins/junit5/DslGroovyTests.groovy @@ -113,4 +113,74 @@ class DslGroovyTests { containsOnly("some-tag", "paid-tag", "release-tag") assertThat(paidReleaseTask.testFramework.options.excludeTags).containsOnly("other-tag") } + + @org.junit.jupiter.api.Test + @DisplayName("complex example with multiple flavor dimensions & build types") + void complexExampleWithMultipleFlavorDimensionsAndBuildTypes() { + def project = factory.newProject(testRoot) + .asAndroidApplication() + .build() + + project.android { + flavorDimensions "brand", "environment", "payment" + productFlavors { + brandA { + dimension "brand" + } + brandB { + dimension "brand" + } + + development { + dimension "environment" + } + production { + dimension "environment" + } + + free { + dimension "payment" + } + paid { + dimension "payment" + } + } + + buildTypes { + ci { + initWith debug + } + } + + testOptions.junitPlatform { + filters { + includeTags "global-tag" + } + + brandAFilters { + includeTags "brandA-tag" + includeTags "some-other-tag" + } + + developmentFilters { + includeTags "development-tag" + } + + paidFilters { + includeTags "paid-tag" + excludeTags "some-other-tag" + } + } + } + + project.evaluate() + + def brandADevelopmentPaidDebugTask = project.tasks + .getByName("testBrandADevelopmentPaidDebugUnitTest") as Test + + assertThat(brandADevelopmentPaidDebugTask.testFramework.options.includeTags). + containsOnly("global-tag", "brandA-tag", "development-tag", "paid-tag") + assertThat(brandADevelopmentPaidDebugTask.testFramework.options.excludeTags). + containsOnly("some-other-tag") + } } diff --git a/android-junit5-tests/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/PluginSpec.kt b/android-junit5-tests/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/PluginSpec.kt index 39d6bc98..1ab3a7d8 100644 --- a/android-junit5-tests/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/PluginSpec.kt +++ b/android-junit5-tests/src/test/kotlin/de/mannodermaus/gradle/plugins/junit5/PluginSpec.kt @@ -19,7 +19,6 @@ import org.gradle.api.ProjectConfigurationException import org.gradle.api.Task import org.gradle.api.internal.plugins.PluginApplicationException import org.gradle.api.tasks.testing.Test -import org.gradle.testkit.runner.GradleRunner import org.jetbrains.spek.api.Spek import org.jetbrains.spek.api.dsl.context import org.jetbrains.spek.api.dsl.describe @@ -575,6 +574,76 @@ class PluginSpec : Spek({ } } + on("using custom build types & multiple flavor dimensions") { + project.android.apply { + flavorDimensions("brand", "environment", "payment") + productFlavors.apply { + create("brandA").dimension = "brand" + create("brandB").dimension = "brand" + + create("development").dimension = "environment" + create("production").dimension = "environment" + + create("free").dimension = "payment" + create("paid").dimension = "payment" + } + buildTypes.apply { + create("ci").initWith(findByName("debug")) + } + } + + project.evaluate() + + listOf( + "filters", + + "debugFilters", + "releaseFilters", + "ciFilters", + + "brandAFilters", + "brandBFilters", + + "developmentFilters", + "productionFilters", + + "freeFilters", + "paidFilters", + + "brandADevelopmentPaidDebugFilters", + "brandADevelopmentPaidReleaseFilters", + "brandADevelopmentPaidCiFilters", + "brandADevelopmentFreeDebugFilters", + "brandADevelopmentFreeReleaseFilters", + "brandADevelopmentFreeCiFilters", + "brandAProductionPaidDebugFilters", + "brandAProductionPaidReleaseFilters", + "brandAProductionPaidCiFilters", + "brandAProductionFreeDebugFilters", + "brandAProductionFreeReleaseFilters", + "brandAProductionFreeCiFilters", + + "brandBDevelopmentPaidDebugFilters", + "brandBDevelopmentPaidReleaseFilters", + "brandBDevelopmentPaidCiFilters", + "brandBDevelopmentFreeDebugFilters", + "brandBDevelopmentFreeReleaseFilters", + "brandBDevelopmentFreeCiFilters", + "brandBProductionPaidDebugFilters", + "brandBProductionPaidReleaseFilters", + "brandBProductionPaidCiFilters", + "brandBProductionFreeDebugFilters", + "brandBProductionFreeReleaseFilters", + "brandBProductionFreeCiFilters" + ).forEach { name -> + it("creates an extension named '$name'") { + val ju5 = project.android.testOptions.junitPlatform + val extension = ju5.extensionByName(name) + assertThat(extension).isNotNull() + } + } + } + on("using flavor-specific filters") { project.android.flavorDimensions("tier") project.android.productFlavors.apply { diff --git a/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Configuration.kt b/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Configuration.kt index 309d9127..8c23a395 100644 --- a/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Configuration.kt +++ b/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Configuration.kt @@ -94,16 +94,33 @@ internal class JUnit5TaskConfig( // 2) Build-type-specific (e.g. "debug") // 3) Flavor-specific (e.g. "free") // 4) Variant-specific (e.g. "freeDebug") - private fun collect(collectorFunction: (FiltersExtension) -> IncludeExcludeContainer) = - collectorFunction(extension.filters) + - collectorFunction(extension.findFilters(variant.buildType.name)) + - collectorFunction(extension.findFilters(variant.flavorName)) + - collectorFunction(extension.findFilters(variant.name)) - - val combinedIncludePatterns = this.collect { it.patterns }.include.toTypedArray() - val combinedExcludePatterns = this.collect { it.patterns }.exclude.toTypedArray() - val combinedIncludeTags = this.collect { it.tags }.include.toTypedArray() - val combinedExcludeTags = this.collect { it.tags }.exclude.toTypedArray() - val combinedIncludeEngines = this.collect { it.engines }.include.toTypedArray() - val combinedExcludeEngines = this.collect { it.engines }.exclude.toTypedArray() + private fun collect( + func: FiltersExtension.() -> IncludeExcludeContainer): IncludeExcludeContainer { + // 1) + val layer1 = filtersOf(null, func) + // 2) + val layer2 = layer1 + filtersOf(variant.buildType.name, func) + // 3) + val layer3 = variant.productFlavors + .map { filtersOf(it.name, func) } + .fold(layer2) { a, b -> a + b } + // 4) + return layer3 + filtersOf(variant.name, func) + } + + private inline fun filtersOf( + qualifier: String?, + func: FiltersExtension.() -> IncludeExcludeContainer) = + if (qualifier == null) { + extension.filters.func() + } else { + extension.findFilters(qualifier).func() + } + + val combinedIncludePatterns = this.collect { patterns }.include.toTypedArray() + val combinedExcludePatterns = this.collect { patterns }.exclude.toTypedArray() + val combinedIncludeTags = this.collect { tags }.include.toTypedArray() + val combinedExcludeTags = this.collect { tags }.exclude.toTypedArray() + val combinedIncludeEngines = this.collect { engines }.include.toTypedArray() + val combinedExcludeEngines = this.collect { engines }.exclude.toTypedArray() } diff --git a/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Dsl.kt b/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Dsl.kt index f25e519f..daaa685c 100644 --- a/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Dsl.kt +++ b/android-junit5/src/main/kotlin/de/mannodermaus/gradle/plugins/junit5/Dsl.kt @@ -27,16 +27,30 @@ internal fun attachDsl(project: Project, projectConfig: ProjectConfig) { // as well as composed variants (e.g. "freeDebug" or "paidRelease") // and product flavors (e.g. "free" or "paid") project.android.buildTypes.all { buildType -> + // "debugFilters" + // "releaseFilters" ju5.attachFiltersDsl(qualifier = buildType.name) } + // Attach DSL objects for all permutations of variants available. + // As an example, assume the incoming `variant` to be: + // Name: "brandADevelopmentDebug" + // Dimension "brand": "brandA" + // Dimension "environment": "development" + // Build Type Name: "debug" + // + // The following DSL objects have to be generated from this: + // 1) brandADevelopmentDebugFilters + // 2) brandAFilters + // 3) developmentFilters projectConfig.unitTestVariants.all { variant -> + // 1) Fully-specialized name ("brandADevelopmentDebugFilters") ju5.attachFiltersDsl(qualifier = variant.name) - ju5.attachFiltersDsl(qualifier = variant.buildType.name) - } - project.android.productFlavors.all { flavor -> - ju5.attachFiltersDsl(qualifier = flavor.name) + variant.productFlavors.forEach { flavor -> + // 2) & 3) Single flavors ("brandAFilters" & "developmentFilters") + ju5.attachFiltersDsl(qualifier = flavor.name) + } } } }