Skip to content

Commit

Permalink
Fix multi-dimension projects that try to access non-existing filters
Browse files Browse the repository at this point in the history
Fixes #110
  • Loading branch information
mannodermaus committed Sep 2, 2018
1 parent 35dbbf0 commit b2d4778
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<FiltersExtension>(name)
assertThat(extension).isNotNull()
}
}
}

on("using flavor-specific filters") {
project.android.flavorDimensions("tier")
project.android.productFlavors.apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
}
Expand Down

0 comments on commit b2d4778

Please sign in to comment.