blob: 8c2778a6c43f42c5101b7842d1468cab4e3f7b65 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.build.gradle.internal.tests
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.internal.plugins.BasePlugin
import com.android.build.gradle.internal.fixture.TestConstants
import com.android.build.gradle.internal.fixture.TestProjects
import com.android.build.gradle.internal.fixture.createAndConfig
import com.android.build.gradle.internal.plugins.runAfterEvaluate
import com.android.ide.common.util.multimapOf
import com.android.ide.common.util.multimapWithSingleKeyOf
import com.google.common.collect.ImmutableSetMultimap
import com.google.common.collect.Multimap
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.util.Locale
/**
* Tests that specific configurations properly extendFrom others.
*/
@RunWith(Parameterized::class)
class ConfigurationExtensionTest(private val pluginType: TestProjects.Plugin) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "plugin_{0}")
fun params(): Collection<TestProjects.Plugin> = listOf(
TestProjects.Plugin.APP, TestProjects.Plugin.LIBRARY)
}
@get:Rule
val projectDirectory = TemporaryFolder()
private lateinit var project: Project
private lateinit var plugin: BasePlugin
private lateinit var android: BaseExtension
private lateinit var configExtensionMap: Multimap<String, String>
// basic relationship
private val appBasics = multimapOf(
"implementation" to "api",
"api" to "compile",
"runtimeOnly" to "apk",
"compileOnly" to "provided")
private val libBasics = multimapOf(
"implementation" to "api",
"api" to "compile",
"runtimeOnly" to "publish",
"compileOnly" to "provided")
// variant to basic relationship
private val compileToRaw = multimapWithSingleKeyOf(
"lollipopDemoDebugCompileClasspath",
"api",
"compile",
"implementation",
"compileOnly",
"lollipopImplementation",
"debugImplementation",
"demoImplementation",
"lollipopDemoImplementation",
"lollipopDemoDebugImplementation")
private val runtimeToRaw = multimapWithSingleKeyOf(
"lollipopDemoDebugRuntimeClasspath",
"api",
"compile",
"implementation",
"runtimeOnly",
"lollipopImplementation",
"debugImplementation",
"demoImplementation",
"lollipopDemoImplementation",
"lollipopDemoDebugImplementation")
/** Compile Test to prod relationship, exhaustively listed. */
private val testCompileToRaw = multimapWithSingleKeyOf(
"lollipopDemoDebugUnitTestCompileClasspath",
"api",
"compile",
"debugApi",
"debugCompile",
"debugImplementation",
"demoApi",
"demoCompile",
"demoImplementation",
"implementation",
"lollipopApi",
"lollipopCompile",
"lollipopDemoApi",
"lollipopDemoCompile",
"lollipopDemoDebugApi",
"lollipopDemoDebugCompile",
"lollipopDemoDebugImplementation",
"lollipopDemoImplementation",
"lollipopImplementation",
"testApi",
"testCompile",
"testCompileOnly",
"testDebugApi",
"testDebugCompile",
"testDebugCompileOnly",
"testDebugImplementation",
"testDebugProvided",
"testDemoApi",
"testDemoCompile",
"testDemoCompileOnly",
"testDemoImplementation",
"testDemoProvided",
"testImplementation",
"testLollipopApi",
"testLollipopCompile",
"testLollipopCompileOnly",
"testLollipopDemoApi",
"testLollipopDemoCompile",
"testLollipopDemoCompileOnly",
"testLollipopDemoDebugApi",
"testLollipopDemoDebugCompile",
"testLollipopDemoDebugCompileOnly",
"testLollipopDemoDebugImplementation",
"testLollipopDemoDebugProvided",
"testLollipopDemoImplementation",
"testLollipopDemoProvided",
"testLollipopImplementation",
"testLollipopProvided",
"testProvided")
private val publish = when (pluginType) {
TestProjects.Plugin.APP -> "Apk"
TestProjects.Plugin.LIBRARY -> "Publish"
else -> throw IllegalStateException()
}
/**
* Runtime Test to prod relationship, exhaustively listed.
*
* Modelled after
* [https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph]
* Note that `*testCompileClasspath` extends `implementation` directly, rather than via
* `*testImplementation`, see
* [com.android.build.gradle.internal.dependency.AndroidTestResourceArtifactCollection] for how
* that is used.
*/
private val testRuntimeToRaw = multimapWithSingleKeyOf(
"lollipopDemoDebugUnitTestRuntimeClasspath",
publish.toLowerCase(Locale.US),
"api",
"compile",
"debug$publish",
"debugApi",
"debugCompile",
"debugImplementation",
"debugRuntimeOnly",
"demo$publish",
"demoApi",
"demoCompile",
"demoImplementation",
"demoRuntimeOnly",
"implementation",
"lollipop$publish",
"lollipopApi",
"lollipopCompile",
"lollipopDemo$publish",
"lollipopDemoApi",
"lollipopDemoCompile",
"lollipopDemoDebug$publish",
"lollipopDemoDebugApi",
"lollipopDemoDebugCompile",
"lollipopDemoDebugImplementation",
"lollipopDemoDebugRuntimeOnly",
"lollipopDemoImplementation",
"lollipopDemoRuntimeOnly",
"lollipopImplementation",
"lollipopRuntimeOnly",
"runtimeOnly",
"test$publish",
"testApi",
"testCompile",
"testDebug$publish",
"testDebugApi",
"testDebugCompile",
"testDebugImplementation",
"testDebugRuntimeOnly",
"testDemo$publish",
"testDemoApi",
"testDemoCompile",
"testDemoImplementation",
"testDemoRuntimeOnly",
"testImplementation",
"testLollipop$publish",
"testLollipopApi",
"testLollipopCompile",
"testLollipopDemo$publish",
"testLollipopDemoApi",
"testLollipopDemoCompile",
"testLollipopDemoDebug$publish",
"testLollipopDemoDebugApi",
"testLollipopDemoDebugCompile",
"testLollipopDemoDebugImplementation",
"testLollipopDemoDebugRuntimeOnly",
"testLollipopDemoImplementation",
"testLollipopDemoRuntimeOnly",
"testLollipopImplementation",
"testLollipopRuntimeOnly",
"testRuntimeOnly")
// forbidden relationship
private val forbiddenVariantToRaw = multimapOf(
"lollipopDemoDebugCompileClasspath" to "runtimeOnly",
"lollipopDemoDebugCompileClasspath" to "apk",
"lollipopDemoDebugCompileClasspath" to "publish",
"lollipopDemoDebugRuntimeClasspath" to "provided",
"lollipopDemoDebugRuntimeClasspath" to "compileOnly")
@Before
fun setUp() {
project = TestProjects.builder(projectDirectory.newFolder("project").toPath())
.withPlugin(pluginType)
.build()
android = project.extensions.getByType(pluginType.extensionClass) as BaseExtension
android.setCompileSdkVersion(TestConstants.COMPILE_SDK_VERSION)
android.buildToolsVersion = TestConstants.BUILD_TOOL_VERSION
plugin = project.plugins.getPlugin(pluginType.pluginClass) as BasePlugin
// manually call the DSL to configure the project.
android.flavorDimensions("api", "mode")
android.productFlavors.createAndConfig("demo") {
setDimension("mode")
}
android.productFlavors.createAndConfig("full") {
setDimension("mode")
}
android.productFlavors.createAndConfig("mnc") {
setDimension("api")
}
android.productFlavors.createAndConfig("lollipop") {
setDimension("api")
}
plugin.runAfterEvaluate()
configExtensionMap = getConfigurationExtensions()
}
@Test
fun testBasicRelationships() {
checkValidExtensions(
if (pluginType == TestProjects.Plugin.APP) appBasics else libBasics,
configExtensionMap)
}
@Test
fun testVariantToRawRelationships() {
checkValidExtensions(compileToRaw, configExtensionMap)
checkValidExtensions(runtimeToRaw, configExtensionMap)
}
@Test
fun testForbiddenRelationships() {
checkInvalidExtensions(forbiddenVariantToRaw, configExtensionMap)
}
@Test
fun testMainTestRelationships() {
checkValidExtensionsCensus(testCompileToRaw)
checkValidExtensionsCensus(testRuntimeToRaw)
}
private fun getConfigurationExtensions(): Multimap<String, String> {
val map = ImmutableSetMultimap.builder<String, String>()
for (config in project.configurations) {
fillConfigMap(map, config.name, config.extendsFrom)
}
return map.build()
}
private fun fillConfigMap(
map: ImmutableSetMultimap.Builder<String, String>,
name: String,
children: Set<Configuration>) {
for (config in children) {
map.put(name, config.name)
fillConfigMap(map, name, config.extendsFrom)
}
}
private fun checkValidExtensions(
expected: Multimap<String, String>,
actual: Multimap<String, String>) {
for ((key, value) in expected.entries()) {
Truth.assertThat(actual).containsEntry(key, value)
}
}
private fun checkValidExtensionsCensus(expected: Multimap<String, String>) {
for (key in expected.keys()) {
assertThat(configExtensionMap.get(key))
.named("Configuration $key extends")
.containsExactlyElementsIn(expected.get(key))
}
}
private fun checkInvalidExtensions(
expected: Multimap<String, String>,
actual: Multimap<String, String>) {
for ((key, value) in expected.entries()) {
Truth.assertThat(actual).doesNotContainEntry(key, value)
}
}
}