[Gradle] Split & migrate AbstractKotlinAndroidGradleTests to the new dsl
#KT-45748 In Progress
This commit is contained in:
committed by
Space Team
parent
8bbf98f24c
commit
fc088bb84a
-1137
File diff suppressed because it is too large
Load Diff
+202
@@ -450,6 +450,208 @@ class Kapt3AndroidIT : Kapt3BaseIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DisplayName("kapt uses AGP annotation processor option providers as nested inputs")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testKaptUsingApOptionProvidersAsNestedInputOutput(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion, kaptOptions = null),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
subProject("Android").buildGradle.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
|
class MyNested implements org.gradle.process.CommandLineArgumentProvider {
|
||||||
|
private final File argsFile
|
||||||
|
|
||||||
|
MyNested(File argsFile) {
|
||||||
|
this.argsFile = argsFile
|
||||||
|
}
|
||||||
|
|
||||||
|
@InputFile
|
||||||
|
File inputFile = null
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Iterable<String> asArguments() {
|
||||||
|
// Read the arguments from a file, because changing them in a build script is treated as an
|
||||||
|
// implementation change by Gradle:
|
||||||
|
return [argsFile.text]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def nested = new MyNested(rootProject.file("args.txt"))
|
||||||
|
nested.inputFile = file("${'$'}projectDir/in.txt")
|
||||||
|
|
||||||
|
android.applicationVariants.all {
|
||||||
|
it.javaCompileOptions.annotationProcessorOptions.compilerArgumentProviders.add(nested)
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val inFile = subProject("Android").projectPath.resolve("in.txt")
|
||||||
|
inFile.writeText("1234")
|
||||||
|
val argsFile = projectPath.resolve("args.txt")
|
||||||
|
argsFile.writeText("1234")
|
||||||
|
|
||||||
|
val kaptTasks = listOf(":Android:kaptFlavor1DebugKotlin")
|
||||||
|
val javacTasks = listOf(":Android:compileFlavor1DebugJavaWithJavac")
|
||||||
|
|
||||||
|
val buildTasks = (kaptTasks + javacTasks).toTypedArray()
|
||||||
|
|
||||||
|
build(*buildTasks) {
|
||||||
|
assertTasksExecuted(kaptTasks + javacTasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
inFile.appendText("5678")
|
||||||
|
|
||||||
|
build(*buildTasks) {
|
||||||
|
assertTasksExecuted(kaptTasks)
|
||||||
|
assertTasksUpToDate(javacTasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changing only the annotation provider arguments should not trigger the tasks to run, as the arguments may be outputs,
|
||||||
|
// internals or neither:
|
||||||
|
argsFile.appendText("5678")
|
||||||
|
|
||||||
|
build(*buildTasks) {
|
||||||
|
assertTasksUpToDate(javacTasks + kaptTasks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("agp annotation processor nested arguments are not evaluated at configuration time")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testAgpNestedArgsNotEvaluatedDuringConfiguration(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
subProject("Android").buildGradle.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
|
class MyNested implements org.gradle.process.CommandLineArgumentProvider {
|
||||||
|
@Override
|
||||||
|
Iterable<String> asArguments() {
|
||||||
|
throw new RuntimeException("This should not be invoked during configuration.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def nested = new MyNested()
|
||||||
|
|
||||||
|
android.applicationVariants.all {
|
||||||
|
it.javaCompileOptions.annotationProcessorOptions.compilerArgumentProviders.add(nested)
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
build(":Android:kaptFlavor1DebugKotlin", "--dry-run")
|
||||||
|
|
||||||
|
build(
|
||||||
|
":Android:kaptFlavor1DebugKotlin", "--dry-run",
|
||||||
|
buildOptions = buildOptions.copy(kaptOptions = BuildOptions.KaptOptions(verbose = false))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("incremental compilation works with dagger")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testAndroidDaggerIC(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidDaggerProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("assembleDebug")
|
||||||
|
|
||||||
|
val androidModuleKt = subProject("app").javaSourcesDir().resolve("com/example/dagger/kotlin/AndroidModule.kt")
|
||||||
|
androidModuleKt.modify {
|
||||||
|
it.replace(
|
||||||
|
"fun provideApplicationContext(): Context {",
|
||||||
|
"fun provideApplicationContext(): Context? {"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
build(":app:assembleDebug", buildOptions = buildOptions.copy(logLevel = LogLevel.DEBUG)) {
|
||||||
|
assertTasksExecuted(
|
||||||
|
":app:kaptGenerateStubsDebugKotlin",
|
||||||
|
":app:kaptDebugKotlin",
|
||||||
|
":app:compileDebugKotlin",
|
||||||
|
":app:compileDebugJavaWithJavac"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Output is combined with previous build, but we are only interested in the compilation
|
||||||
|
// from second build to avoid false positive test failure
|
||||||
|
val filteredOutput = output
|
||||||
|
.lineSequence()
|
||||||
|
.filter { it.contains("[KOTLIN] compile iteration:") }
|
||||||
|
.drop(1)
|
||||||
|
.joinToString(separator = "/n")
|
||||||
|
assertCompiledKotlinSources(listOf(androidModuleKt).relativizeTo(projectPath), output = filteredOutput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("incremental compilation with android and kapt")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testAndroidWithKaptIncremental(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidIncrementalMultiModule",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
val appProject = subProject("app")
|
||||||
|
appProject.buildGradle.modify {
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
apply plugin: 'org.jetbrains.kotlin.kapt'
|
||||||
|
$it
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
|
||||||
|
build(":app:testDebugUnitTest")
|
||||||
|
|
||||||
|
appProject.kotlinSourcesDir().resolve("com/example/KotlinActivity.kt").appendText(
|
||||||
|
//language=kt
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
private val x = 1
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
build(":app:testDebugUnitTest") {
|
||||||
|
assertOutputDoesNotContain(NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun TestProject.setupDataBinding() {
|
private fun TestProject.setupDataBinding() {
|
||||||
buildGradle.appendText(
|
buildGradle.appendText(
|
||||||
//language=Gradle
|
//language=Gradle
|
||||||
|
|||||||
+284
@@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.android
|
||||||
|
|
||||||
|
import org.gradle.api.logging.LogLevel
|
||||||
|
import org.gradle.testkit.runner.BuildResult
|
||||||
|
import org.gradle.util.GradleVersion
|
||||||
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
|
import org.jetbrains.kotlin.gradle.util.checkedReplace
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import java.nio.file.Files
|
||||||
|
import kotlin.io.path.appendText
|
||||||
|
import kotlin.io.path.readLines
|
||||||
|
import kotlin.io.path.writeText
|
||||||
|
import kotlin.test.assertContains
|
||||||
|
|
||||||
|
@DisplayName("base kotlin-android tests")
|
||||||
|
@AndroidGradlePluginTests
|
||||||
|
class KotlinAndroidIT : KGPBaseTest() {
|
||||||
|
|
||||||
|
@DisplayName("android project compilation smoke test")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testSimpleCompile(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
fun BuildResult.assertKotlinGradleBuildServicesAreInitialized() {
|
||||||
|
assertOutputContainsExactTimes("Initialized KotlinGradleBuildServices", expectedRepetitionTimes = 1)
|
||||||
|
assertOutputContainsExactTimes("Disposed KotlinGradleBuildServices", expectedRepetitionTimes = 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
project(
|
||||||
|
"AndroidProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion, logLevel = LogLevel.DEBUG),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
val modules = listOf("Android", "Lib")
|
||||||
|
val flavors = listOf("Flavor1", "Flavor2")
|
||||||
|
val buildTypes = listOf("Debug")
|
||||||
|
|
||||||
|
val expectedTasks = mutableListOf<String>()
|
||||||
|
for (module in modules) {
|
||||||
|
for (flavor in flavors) {
|
||||||
|
for (buildType in buildTypes) {
|
||||||
|
expectedTasks.add(":$module:compile$flavor${buildType}Kotlin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build("assembleDebug", "test") {
|
||||||
|
val pattern = ":Test:compile[\\w\\d]+Kotlin"
|
||||||
|
expectedTasks.addAll(findTasksByPattern(pattern.toRegex()))
|
||||||
|
assertTasksExecuted(expectedTasks)
|
||||||
|
assertOutputContains("InternalDummyTest PASSED")
|
||||||
|
assertKotlinGradleBuildServicesAreInitialized()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the a build second time, assert everything is up-to-date
|
||||||
|
build("assembleDebug") {
|
||||||
|
assertTasksUpToDate(expectedTasks)
|
||||||
|
assertKotlinGradleBuildServicesAreInitialized()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-16897: the `assembleAndroidTest` task builds fine without the `build` task")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testAssembleAndroidTest(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("assembleAndroidTest")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-12303: compilation works fine with icepick")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testAndroidIcepickProject(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidIcepickProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("assembleDebug")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("compilation works fine with parcelize")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testParcelize(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidParcelizeProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("assembleDebug")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-46626: kotlin-android produces clear error message when no android plugin is applied")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun shouldAllowToApplyPluginWhenAndroidPluginIsMissing(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"simpleProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
fun replaceKotlinJvmByKotlinAndroid(specifyPluginVersion: Boolean): (String) -> CharSequence = { line ->
|
||||||
|
if (line.contains("id \"org.jetbrains.kotlin.jvm\"")) {
|
||||||
|
" id \"org.jetbrains.kotlin.android\"" + if (specifyPluginVersion) " version \"${'$'}kotlin_version\"" else ""
|
||||||
|
} else {
|
||||||
|
line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildGradle.modify {
|
||||||
|
it.lines().joinToString(
|
||||||
|
separator = "\n",
|
||||||
|
transform = replaceKotlinJvmByKotlinAndroid(false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
settingsGradle.modify {
|
||||||
|
it.lines().joinToString(
|
||||||
|
separator = "\n",
|
||||||
|
transform = replaceKotlinJvmByKotlinAndroid(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildAndFail("tasks") {
|
||||||
|
assertOutputContains("'kotlin-android' plugin requires one of the Android Gradle plugins.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-49483: lint dependencies are resolved properly")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testLintDependencyResolutionKt49483(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
buildGradle.modify {
|
||||||
|
it.replace(
|
||||||
|
"plugins {",
|
||||||
|
"""
|
||||||
|
plugins {
|
||||||
|
id("com.android.lint")
|
||||||
|
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
subProject("Lib").buildGradle.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
android {
|
||||||
|
lintOptions.checkDependencies = true
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":java-lib"))
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
settingsGradle.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
include("java-lib")
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
subProject("java-lib").buildGradle.apply {
|
||||||
|
Files.createDirectories(parent)
|
||||||
|
writeText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
plugins {
|
||||||
|
id("java-library")
|
||||||
|
id("com.android.lint")
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gradle 6 + AGP 4 produce a deprecation warning on parallel executions about resolving a configuration from another project
|
||||||
|
build(":Lib:lintFlavor1Debug", buildOptions = buildOptions.copy(parallel = gradleVersion >= GradleVersion.version("7.0"))) {
|
||||||
|
assertOutputDoesNotContain("as an external dependency and not analyze it.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("publish with omitted stdlib version sets proper version")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testOmittedStdlibVersion(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
subProject("Lib").buildGradle.modify {
|
||||||
|
it.checkedReplace(
|
||||||
|
"kotlin-stdlib:\$kotlin_version",
|
||||||
|
"kotlin-stdlib"
|
||||||
|
) +
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
apply plugin: 'maven-publish'
|
||||||
|
|
||||||
|
android {
|
||||||
|
defaultPublishConfig 'flavor1Debug'
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
flavorDebug(MavenPublication) {
|
||||||
|
from components.flavor1Debug
|
||||||
|
|
||||||
|
group = 'com.example'
|
||||||
|
artifactId = 'flavor1Debug'
|
||||||
|
version = '1.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url = "file://${'$'}buildDir/repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
|
||||||
|
build(":Lib:assembleFlavor1Debug", ":Lib:publish") {
|
||||||
|
assertTasksExecuted(":Lib:compileFlavor1DebugKotlin", ":Lib:publishFlavorDebugPublicationToMavenRepository")
|
||||||
|
val pomLines = subProject("Lib").projectPath.resolve("build/repo/com/example/flavor1Debug/1.0/flavor1Debug-1.0.pom").readLines()
|
||||||
|
val stdlibVersionLineNumber = pomLines.indexOfFirst { "<artifactId>kotlin-stdlib</artifactId>" in it } + 1
|
||||||
|
val versionLine = pomLines[stdlibVersionLineNumber]
|
||||||
|
assertContains(versionLine, "<version>${buildOptions.kotlinVersion}</version>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+183
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.android
|
||||||
|
|
||||||
|
import org.gradle.api.logging.LogLevel
|
||||||
|
import org.gradle.util.GradleVersion
|
||||||
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
|
import org.jetbrains.kotlin.gradle.util.getFileByName
|
||||||
|
import org.jetbrains.kotlin.gradle.util.getFilesByNames
|
||||||
|
import org.jetbrains.kotlin.gradle.util.modify
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import kotlin.io.path.appendText
|
||||||
|
import kotlin.io.path.writeText
|
||||||
|
|
||||||
|
@DisplayName("kotlin-android incremental compilation tests")
|
||||||
|
@AndroidGradlePluginTests
|
||||||
|
class KotlinAndroidIncrementalIT : KGPBaseTest() {
|
||||||
|
@DisplayName("incremental compilation works with single-module android projects")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testIncrementalCompilation(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidIncrementalSingleModuleProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("assembleDebug")
|
||||||
|
|
||||||
|
val modifiedSrc = subProject("app").kotlinSourcesDir().resolve("com/example/getSomething.kt")
|
||||||
|
modifiedSrc.writeText(
|
||||||
|
//language=kt
|
||||||
|
"""
|
||||||
|
package com.example
|
||||||
|
|
||||||
|
fun getSomething() = 10
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
build("assembleDebug", buildOptions = buildOptions.copy(logLevel = LogLevel.DEBUG)) {
|
||||||
|
val affectedKotlinFiles = listOf(
|
||||||
|
"app/src/main/kotlin/com/example/KotlinActivity1.kt",
|
||||||
|
"app/src/main/kotlin/com/example/getSomething.kt",
|
||||||
|
)
|
||||||
|
val affectedJavaFiles = listOf(
|
||||||
|
"app/src/main/java/com/example/JavaActivity.java",
|
||||||
|
)
|
||||||
|
assertCompiledKotlinSources(affectedKotlinFiles.toPaths(), output)
|
||||||
|
assertCompiledJavaSources(affectedJavaFiles.toPaths(), output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("incremental compilation works with multi-module android projects")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testMultiModuleIC(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidIncrementalMultiModule",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("assembleDebug")
|
||||||
|
|
||||||
|
val libAndroidUtilKt = subProject("libAndroid").kotlinSourcesDir().resolve("com/example/libAndroidUtil.kt")
|
||||||
|
libAndroidUtilKt.modify { it.replace("fun libAndroidUtil(): String", "fun libAndroidUtil(): CharSequence") }
|
||||||
|
|
||||||
|
val optionsWithDebug = buildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||||
|
|
||||||
|
build("assembleDebug", buildOptions = optionsWithDebug) {
|
||||||
|
val affectedSources = listOf(
|
||||||
|
libAndroidUtilKt,
|
||||||
|
subProject("app").kotlinSourcesDir().resolve("com/example/useLibAndroidUtil.kt")
|
||||||
|
).relativizeTo(projectPath)
|
||||||
|
assertCompiledKotlinSources(affectedSources, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
val libAndroidClassesOnlyUtilKt = subProject("libAndroidClassesOnly").kotlinSourcesDir().resolve("com/example/LibAndroidClassesOnlyUtil.kt")
|
||||||
|
libAndroidClassesOnlyUtilKt.modify {
|
||||||
|
it.replace(
|
||||||
|
"fun libAndroidClassesOnlyUtil(): String",
|
||||||
|
"fun libAndroidClassesOnlyUtil(): CharSequence"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
build("assembleDebug", buildOptions = optionsWithDebug) {
|
||||||
|
val affectedSources = listOf(
|
||||||
|
libAndroidClassesOnlyUtilKt,
|
||||||
|
subProject("app").kotlinSourcesDir().resolve("com/example/useLibAndroidClassesOnlyUtil.kt")
|
||||||
|
).relativizeTo(projectPath)
|
||||||
|
assertCompiledKotlinSources(affectedSources, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
val libJvmUtilKt = subProject("libJvmClassesOnly").kotlinSourcesDir().resolve("com/example/LibJvmUtil.kt")
|
||||||
|
libJvmUtilKt.modify { it.replace("fun libJvmUtil(): String", "fun libJvmUtil(): CharSequence") }
|
||||||
|
|
||||||
|
build("assembleDebug", buildOptions = optionsWithDebug) {
|
||||||
|
val affectedSources = listOf(
|
||||||
|
libJvmUtilKt,
|
||||||
|
subProject("app").kotlinSourcesDir().resolve("com/example/useLibJvmUtil.kt")
|
||||||
|
).relativizeTo(projectPath)
|
||||||
|
assertCompiledKotlinSources(affectedSources, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("incremental compilation does nothing without changes")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testIncrementalBuildWithNoChanges(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidIncrementalSingleModuleProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
val expectedTasks = listOf(
|
||||||
|
":app:compileDebugKotlin",
|
||||||
|
":app:compileDebugJavaWithJavac"
|
||||||
|
)
|
||||||
|
|
||||||
|
build("assembleDebug") {
|
||||||
|
assertTasksExecuted(expectedTasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
build("assembleDebug") {
|
||||||
|
assertTasksUpToDate(expectedTasks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-49066: incremental compilation with custom module name")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testCustomModuleName(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidIncrementalMultiModule",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
subProject("libAndroid").buildGradle.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
android.kotlinOptions {
|
||||||
|
moduleName = "custom_path"
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
build("assembleDebug") {
|
||||||
|
assertFileInProjectExists("libAndroid/build/tmp/kotlin-classes/debug/META-INF/custom_path.kotlin_module")
|
||||||
|
}
|
||||||
|
|
||||||
|
val libAndroidUtilKt = subProject("libAndroid").kotlinSourcesDir().resolve("com/example/libAndroidUtil.kt")
|
||||||
|
libAndroidUtilKt.modify { it.replace("fun libAndroidUtil(): String", "fun libAndroidUtil(): CharSequence") }
|
||||||
|
build("assembleDebug", buildOptions = buildOptions.copy(logLevel = LogLevel.DEBUG)) {
|
||||||
|
val affectedSources = listOf(
|
||||||
|
libAndroidUtilKt,
|
||||||
|
subProject("app").kotlinSourcesDir().resolve("com/example/useLibAndroidUtil.kt")
|
||||||
|
).relativizeTo(projectPath)
|
||||||
|
assertCompiledKotlinSources(affectedSources, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+706
@@ -0,0 +1,706 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.android
|
||||||
|
|
||||||
|
import org.gradle.util.GradleVersion
|
||||||
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
|
import org.jetbrains.kotlin.gradle.tooling.BuildKotlinToolingMetadataTask
|
||||||
|
import org.jetbrains.kotlin.gradle.util.AGPVersion
|
||||||
|
import org.jetbrains.kotlin.gradle.util.testResolveAllConfigurations
|
||||||
|
import org.junit.jupiter.api.Disabled
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
import kotlin.io.path.appendText
|
||||||
|
import kotlin.io.path.extension
|
||||||
|
import kotlin.io.path.readText
|
||||||
|
import kotlin.io.path.writeText
|
||||||
|
import kotlin.streams.toList
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
@DisplayName("kotlin-android with mpp")
|
||||||
|
@AndroidGradlePluginTests
|
||||||
|
class KotlinAndroidMppIT : KGPBaseTest() {
|
||||||
|
@DisplayName("KT-50736: whenEvaluated waits for AGP being applied later")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testAfterEvaluateOrdering(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
subProject("Lib").buildGradle.writeText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
google()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath "com.android.tools.build:gradle:${'$'}android_tools_version"
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${'$'}kotlin_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.multiplatform'
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyAction implements kotlin.jvm.functions.Function1<Project, Void> {
|
||||||
|
Void invoke (Project p) {
|
||||||
|
println("compilations: " + p.kotlin.targets.getByName("android").compilations.names)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginKt.whenEvaluated(project, new MyAction ())
|
||||||
|
|
||||||
|
apply plugin : "android-library"
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 22
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin { android("android") { } }
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
build("help") {
|
||||||
|
val reportedCompilations = output.lines()
|
||||||
|
.single { it.contains("compilations: ") }
|
||||||
|
.substringAfter("compilations: ")
|
||||||
|
.removeSurrounding("[", "]")
|
||||||
|
.split(", ")
|
||||||
|
.toSet()
|
||||||
|
assertEquals(
|
||||||
|
setOf("debug", "debugAndroidTest", "debugUnitTest", "release", "releaseUnitTest"),
|
||||||
|
reportedCompilations
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KotlinToolingMetadataArtifact is bundled into apk")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testKotlinToolingMetadataBundle(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"kotlinToolingMetadataAndroid",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("assembleDebug") {
|
||||||
|
assertTasksAreNotInTaskGraph(":${BuildKotlinToolingMetadataTask.defaultTaskName}")
|
||||||
|
|
||||||
|
val debugApk = projectPath.resolve("build/outputs/apk/debug/project-debug.apk")
|
||||||
|
assertFileExists(debugApk)
|
||||||
|
ZipFile(debugApk.toFile()).use { zip ->
|
||||||
|
assertNull(zip.getEntry("kotlin-tooling-metadata.json"), "Expected metadata *not* being packaged into debug apk")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build("assembleRelease") {
|
||||||
|
assertTasksExecuted(":${BuildKotlinToolingMetadataTask.defaultTaskName}")
|
||||||
|
val releaseApk = projectPath.resolve("build/outputs/apk/release/project-release-unsigned.apk")
|
||||||
|
|
||||||
|
assertFileExists(releaseApk)
|
||||||
|
ZipFile(releaseApk.toFile()).use { zip ->
|
||||||
|
assertNotNull(zip.getEntry("kotlin-tooling-metadata.json"), "Expected metadata being packaged into release apk")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("mpp source sets are registered in AGP")
|
||||||
|
@GradleAndroidTest
|
||||||
|
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_42)
|
||||||
|
fun testAndroidMppSourceSets(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"new-mpp-android-source-sets",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
// AbstractReportTask#generate() task action was removed in Gradle 6.8+,
|
||||||
|
// that SourceSetTask is using: https://github.com/gradle/gradle/commit/4dac91ab87ea33ee8689d2a62b691b119198e7c7
|
||||||
|
// leading to the issue that ":sourceSets" task is always in 'UP-TO-DATE' state.
|
||||||
|
// Skipping this check until the test will start using AGP 7.0-alpha03+
|
||||||
|
// AGP 4.x is not compatible with Gradle 7.0, so just skip when the Gradle version is lower than 7.0
|
||||||
|
if (gradleVersion >= GradleVersion.version("7.0")) {
|
||||||
|
build("sourceSets") {
|
||||||
|
fun assertOutputContainsOsIndependent(expectedString: String) {
|
||||||
|
assertOutputContains(expectedString.replace("/", File.separator))
|
||||||
|
}
|
||||||
|
assertOutputContainsOsIndependent("Android resources: [lib/src/main/res, lib/src/androidMain/res]")
|
||||||
|
assertOutputContainsOsIndependent("Assets: [lib/src/main/assets, lib/src/androidMain/assets]")
|
||||||
|
assertOutputContainsOsIndependent("AIDL sources: [lib/src/main/aidl, lib/src/androidMain/aidl]")
|
||||||
|
assertOutputContainsOsIndependent("RenderScript sources: [lib/src/main/rs, lib/src/androidMain/rs]")
|
||||||
|
assertOutputContainsOsIndependent("JNI sources: [lib/src/main/jni, lib/src/androidMain/jni]")
|
||||||
|
assertOutputContainsOsIndependent("JNI libraries: [lib/src/main/jniLibs, lib/src/androidMain/jniLibs]")
|
||||||
|
assertOutputContainsOsIndependent("Java-style resources: [lib/src/main/resources, lib/src/androidMain/resources]")
|
||||||
|
|
||||||
|
assertOutputContainsOsIndependent("Android resources: [lib/src/androidTestDebug/res, lib/src/androidAndroidTestDebug/res]")
|
||||||
|
assertOutputContainsOsIndependent("Assets: [lib/src/androidTestDebug/assets, lib/src/androidAndroidTestDebug/assets]")
|
||||||
|
assertOutputContainsOsIndependent("AIDL sources: [lib/src/androidTestDebug/aidl, lib/src/androidAndroidTestDebug/aidl]")
|
||||||
|
assertOutputContainsOsIndependent("RenderScript sources: [lib/src/androidTestDebug/rs, lib/src/androidAndroidTestDebug/rs]")
|
||||||
|
assertOutputContainsOsIndependent("JNI sources: [lib/src/androidTestDebug/jni, lib/src/androidAndroidTestDebug/jni]")
|
||||||
|
assertOutputContainsOsIndependent("JNI libraries: [lib/src/androidTestDebug/jniLibs, lib/src/androidAndroidTestDebug/jniLibs]")
|
||||||
|
assertOutputContainsOsIndependent("Java-style resources: [lib/src/androidTestDebug/resources, lib/src/androidAndroidTestDebug/resources]")
|
||||||
|
|
||||||
|
assertOutputContainsOsIndependent("Java-style resources: [lib/betaSrc/paidBeta/resources, lib/src/androidPaidBeta/resources]")
|
||||||
|
assertOutputContainsOsIndependent("Java-style resources: [lib/betaSrc/paidBetaDebug/resources, lib/src/androidPaidBetaDebug/resources]")
|
||||||
|
assertOutputContainsOsIndependent("Java-style resources: [lib/betaSrc/paidBetaRelease/resources, lib/src/androidPaidBetaRelease/resources]")
|
||||||
|
|
||||||
|
assertOutputContainsOsIndependent("Java-style resources: [lib/betaSrc/freeBeta/resources, lib/src/androidFreeBeta/resources]")
|
||||||
|
assertOutputContainsOsIndependent("Java-style resources: [lib/betaSrc/freeBetaDebug/resources, lib/src/androidFreeBetaDebug/resources]")
|
||||||
|
assertOutputContainsOsIndependent("Java-style resources: [lib/betaSrc/freeBetaRelease/resources, lib/src/androidFreeBetaRelease/resources]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildAndFail("testFreeBetaDebug") {
|
||||||
|
assertOutputContains("CommonTest > fail FAILED")
|
||||||
|
assertOutputContains("TestKotlin > fail FAILED")
|
||||||
|
assertOutputContains("AndroidTestKotlin > fail FAILED")
|
||||||
|
assertOutputContains("TestJava > fail FAILED")
|
||||||
|
}
|
||||||
|
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
|
buildAndFail("connectedAndroidTest") {
|
||||||
|
assertOutputContains("No connected devices!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("android app can depend on mpp lib")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testAndroidWithNewMppApp(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"new-mpp-android",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("assemble", "compileDebugUnitTestJavaWithJavac", "printCompilerPluginOptions") {
|
||||||
|
// KT-30784
|
||||||
|
assertOutputDoesNotContain("API 'variant.getPackageLibrary()' is obsolete and has been replaced")
|
||||||
|
|
||||||
|
assertOutputContains("KT-29964 OK") // Output from lib/build.gradle
|
||||||
|
|
||||||
|
assertTasksExecuted(
|
||||||
|
":lib:compileDebugKotlinAndroidLib",
|
||||||
|
":lib:compileReleaseKotlinAndroidLib",
|
||||||
|
":lib:compileKotlinJvmLib",
|
||||||
|
":lib:compileKotlinJsLib",
|
||||||
|
":lib:compileCommonMainKotlinMetadata",
|
||||||
|
":app:compileDebugKotlinAndroidApp",
|
||||||
|
":app:compileReleaseKotlinAndroidApp",
|
||||||
|
":app:compileKotlinJvmApp",
|
||||||
|
":app:compileKotlinJsApp",
|
||||||
|
":app:compileCommonMainKotlinMetadata",
|
||||||
|
":lib:compileDebugUnitTestJavaWithJavac",
|
||||||
|
":app:compileDebugUnitTestJavaWithJavac"
|
||||||
|
)
|
||||||
|
|
||||||
|
listOf("debug", "release").forEach { variant ->
|
||||||
|
assertFileInProjectExists("lib/build/tmp/kotlin-classes/$variant/com/example/lib/ExpectedLibClass.class")
|
||||||
|
assertFileInProjectExists("lib/build/tmp/kotlin-classes/$variant/com/example/lib/CommonLibClass.class")
|
||||||
|
assertFileInProjectExists("lib/build/tmp/kotlin-classes/$variant/com/example/lib/AndroidLibClass.class")
|
||||||
|
|
||||||
|
assertFileInProjectExists("app/build/tmp/kotlin-classes/$variant/com/example/app/AKt.class")
|
||||||
|
assertFileInProjectExists("app/build/tmp/kotlin-classes/$variant/com/example/app/KtUsageKt.class")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val groupDir = subProject("lib").projectPath.resolve("build/repo/com/example")
|
||||||
|
build("publish") {
|
||||||
|
assertDirectoryExists(groupDir.resolve("lib-jvmlib"))
|
||||||
|
assertDirectoryExists(groupDir.resolve("lib-jslib"))
|
||||||
|
assertDirectoryExists(groupDir.resolve("lib-androidlib"))
|
||||||
|
assertDirectoryExists(groupDir.resolve("lib-androidlib-debug"))
|
||||||
|
}
|
||||||
|
groupDir.deleteRecursively()
|
||||||
|
|
||||||
|
// Choose a single variant to publish, check that it's there:
|
||||||
|
subProject("lib").buildGradle.appendText("\nkotlin.android('androidLib').publishLibraryVariants = ['release']")
|
||||||
|
build("publish") {
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0.aar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0-sources.jar"))
|
||||||
|
assertFileInProjectNotExists("$groupDir/lib-androidlib-debug")
|
||||||
|
}
|
||||||
|
groupDir.deleteRecursively()
|
||||||
|
|
||||||
|
// Enable publishing for all Android variants:
|
||||||
|
subProject("lib").buildGradle.appendText("\nkotlin.android('androidLib') { publishAllLibraryVariants() }")
|
||||||
|
build("publish") {
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0.aar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0-sources.jar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib-debug/1.0/lib-androidlib-debug-1.0.aar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib-debug/1.0/lib-androidlib-debug-1.0-sources.jar"))
|
||||||
|
}
|
||||||
|
groupDir.deleteRecursively()
|
||||||
|
|
||||||
|
// Then group the variants by flavor and check that only one publication is created:
|
||||||
|
subProject("lib").buildGradle.appendText("\nkotlin.android('androidLib').publishLibraryVariantsGroupedByFlavor = true")
|
||||||
|
build("publish") {
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0.aar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0-sources.jar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0-debug.aar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0-debug-sources.jar"))
|
||||||
|
}
|
||||||
|
groupDir.deleteRecursively()
|
||||||
|
|
||||||
|
// Add one flavor dimension with two flavors, check that the flavors produce grouped publications:
|
||||||
|
subProject("lib").buildGradle.appendText(
|
||||||
|
"\nandroid { flavorDimensions('foo'); productFlavors { fooBar { dimension 'foo' }; fooBaz { dimension 'foo' } } }"
|
||||||
|
)
|
||||||
|
build("publish") {
|
||||||
|
listOf("foobar", "foobaz").forEach { flavor ->
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib-$flavor/1.0/lib-androidlib-$flavor-1.0.aar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib-$flavor/1.0/lib-androidlib-$flavor-1.0-sources.jar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib-$flavor/1.0/lib-androidlib-$flavor-1.0-debug.aar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib-$flavor/1.0/lib-androidlib-$flavor-1.0-debug-sources.jar"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
groupDir.deleteRecursively()
|
||||||
|
|
||||||
|
// Disable the grouping and check that all the variants are published under separate artifactIds:
|
||||||
|
subProject("lib").buildGradle.appendText(
|
||||||
|
"\nkotlin.android('androidLib') { publishLibraryVariantsGroupedByFlavor = false }"
|
||||||
|
)
|
||||||
|
build("publish") {
|
||||||
|
listOf("foobar", "foobaz").forEach { flavor ->
|
||||||
|
listOf("-debug", "").forEach { buildType ->
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib-$flavor$buildType/1.0/lib-androidlib-$flavor$buildType-1.0.aar"))
|
||||||
|
assertFileExists(groupDir.resolve("lib-androidlib-$flavor$buildType/1.0/lib-androidlib-$flavor$buildType-1.0-sources.jar"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
groupDir.deleteRecursively()
|
||||||
|
|
||||||
|
// Convert the 'app' project to a library, publish the two without metadata,
|
||||||
|
// check that the dependencies in the POMs are correctly rewritten:
|
||||||
|
val appGroupDir = subProject("app").projectPath.resolve("build/repo/com/example")
|
||||||
|
|
||||||
|
subProject("app").buildGradle.modify {
|
||||||
|
it.replace("com.android.application", "com.android.library")
|
||||||
|
.replace("applicationId", "//") +
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
apply plugin: 'maven-publish'
|
||||||
|
publishing { repositories { maven { url = uri("${'$'}buildDir/repo") } } }
|
||||||
|
kotlin.android('androidApp') { publishAllLibraryVariants() }
|
||||||
|
android { flavorDimensions('foo'); productFlavors { fooBar { dimension 'foo' }; fooBaz { dimension 'foo' } } }
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
build("publish") {
|
||||||
|
listOf("foobar", "foobaz").forEach { flavor ->
|
||||||
|
listOf("-debug", "").forEach { buildType ->
|
||||||
|
assertFileExists(appGroupDir.resolve("app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0.aar"))
|
||||||
|
assertFileExists(appGroupDir.resolve("app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0-sources.jar"))
|
||||||
|
val pomText =
|
||||||
|
appGroupDir.resolve("app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0.pom").readText()
|
||||||
|
.replace("\\s+".toRegex(), "")
|
||||||
|
assertContains(
|
||||||
|
pomText,
|
||||||
|
"<artifactId>lib-androidlib-$flavor$buildType</artifactId><version>1.0</version><scope>runtime</scope>"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appGroupDir.deleteRecursively()
|
||||||
|
|
||||||
|
// Also check that api and runtimeOnly MPP dependencies get correctly published with the appropriate scope, KT-29476:
|
||||||
|
subProject("app").buildGradle.modify {
|
||||||
|
it.replace("implementation project(':lib')", "api project(':lib')") +
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
kotlin.sourceSets.commonMain.dependencies {
|
||||||
|
runtimeOnly(kotlin('reflect'))
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
build("publish") {
|
||||||
|
listOf("foobar", "foobaz").forEach { flavor ->
|
||||||
|
listOf("-debug", "").forEach { buildType ->
|
||||||
|
val pomText =
|
||||||
|
appGroupDir.resolve("app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0.pom").readText()
|
||||||
|
.replace("\\s+".toRegex(), "")
|
||||||
|
assertContains(
|
||||||
|
pomText,
|
||||||
|
"<artifactId>lib-androidlib-$flavor$buildType</artifactId><version>1.0</version><scope>compile</scope>"
|
||||||
|
)
|
||||||
|
assertContains(
|
||||||
|
pomText,
|
||||||
|
"<artifactId>kotlin-reflect</artifactId><version>${buildOptions.kotlinVersion}</version><scope>runtime</scope>"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-29343: mpp source set dependencies are propagated to android tests")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testAndroidMppProductionDependenciesInTests(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"new-mpp-android",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
// Test the fix for KT-29343
|
||||||
|
subProject("lib").buildGradle.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
kotlin.sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin("stdlib-common")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
androidLibDebug {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin("reflect")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
androidLibRelease {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin("test-junit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val kotlinVersion = buildOptions.kotlinVersion
|
||||||
|
testResolveAllConfigurations("lib") { _, buildResult ->
|
||||||
|
// androidLibDebug:
|
||||||
|
buildResult.assertOutputContains(">> :lib:debugCompileClasspath --> kotlin-reflect-$kotlinVersion.jar")
|
||||||
|
buildResult.assertOutputDoesNotContain(">> :lib:releaseCompileClasspath --> kotlin-reflect-$kotlinVersion.jar")
|
||||||
|
buildResult.assertOutputContains(">> :lib:debugAndroidTestCompileClasspath --> kotlin-reflect-$kotlinVersion.jar")
|
||||||
|
buildResult.assertOutputContains(">> :lib:debugUnitTestCompileClasspath --> kotlin-reflect-$kotlinVersion.jar")
|
||||||
|
buildResult.assertOutputDoesNotContain(">> :lib:releaseUnitTestCompileClasspath --> kotlin-reflect-$kotlinVersion.jar")
|
||||||
|
|
||||||
|
// androidLibRelease:
|
||||||
|
buildResult.assertOutputDoesNotContain(">> :lib:debugCompileClasspath --> kotlin-test-junit-$kotlinVersion.jar")
|
||||||
|
buildResult.assertOutputContains(">> :lib:releaseCompileClasspath --> kotlin-test-junit-$kotlinVersion.jar")
|
||||||
|
buildResult.assertOutputDoesNotContain(">> :lib:debugAndroidTestCompileClasspath --> kotlin-test-junit-$kotlinVersion.jar")
|
||||||
|
buildResult.assertOutputDoesNotContain(">> :lib:debugUnitTestCompileClasspath --> kotlin-test-junit-$kotlinVersion.jar")
|
||||||
|
buildResult.assertOutputContains(">> :lib:releaseUnitTestCompileClasspath --> kotlin-test-junit-$kotlinVersion.jar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-27714: custom attributes are copied to android compilation configurations")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testCustomAttributesInAndroidTargets(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"new-mpp-android",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
val libBuildScript = subProject("lib").buildGradle
|
||||||
|
val appBuildScript = subProject("app").buildGradle
|
||||||
|
|
||||||
|
// Enable publishing for all Android variants:
|
||||||
|
libBuildScript.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
kotlin.android('androidLib') { publishAllLibraryVariants() }
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val groupDir = subProject("lib").projectPath.resolve("build/repo/com/example")
|
||||||
|
|
||||||
|
build("publish") {
|
||||||
|
// Also check that custom user-specified attributes are written in all Android modules metadata:
|
||||||
|
assertFileContains(
|
||||||
|
groupDir.resolve("lib-androidlib/1.0/lib-androidlib-1.0.module"),
|
||||||
|
"\"com.example.target\": \"androidLib\"",
|
||||||
|
"\"com.example.compilation\": \"release\""
|
||||||
|
)
|
||||||
|
assertFileContains(
|
||||||
|
groupDir.resolve("lib-androidlib-debug/1.0/lib-androidlib-debug-1.0.module"),
|
||||||
|
"\"com.example.target\": \"androidLib\"",
|
||||||
|
"\"com.example.compilation\": \"debug\""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
groupDir.deleteRecursively()
|
||||||
|
|
||||||
|
// Check that the consumer side uses custom attributes specified in the target and compilations:
|
||||||
|
val appBuildScriptBackup = appBuildScript.readText()
|
||||||
|
|
||||||
|
libBuildScript.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
kotlin.targets.all {
|
||||||
|
attributes.attribute(
|
||||||
|
Attribute.of("com.example.target", String),
|
||||||
|
targetName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
appBuildScript.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
kotlin.targets.androidApp.attributes.attribute(
|
||||||
|
Attribute.of("com.example.target", String),
|
||||||
|
"notAndroidLib"
|
||||||
|
)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
buildAndFail(":app:compileDebugKotlinAndroidApp") {
|
||||||
|
// dependency resolution should fail
|
||||||
|
assertOutputContainsAny(
|
||||||
|
"Required com.example.target 'notAndroidLib'",
|
||||||
|
"attribute 'com.example.target' with value 'notAndroidLib'",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
libBuildScript.writeText(
|
||||||
|
appBuildScriptBackup +
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
kotlin.targets.all {
|
||||||
|
compilations.all {
|
||||||
|
attributes.attribute(
|
||||||
|
Attribute.of("com.example.compilation", String),
|
||||||
|
targetName + compilationName.capitalize()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
appBuildScript.writeText(
|
||||||
|
appBuildScriptBackup +
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
kotlin.targets.androidApp.compilations.all {
|
||||||
|
attributes.attribute(
|
||||||
|
Attribute.of("com.example.compilation", String),
|
||||||
|
"notDebug"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
buildAndFail(":app:compileDebugKotlinAndroidApp") {
|
||||||
|
assertOutputContainsAny(
|
||||||
|
"Required com.example.compilation 'notDebug'",
|
||||||
|
"attribute 'com.example.compilation' with value 'notDebug'",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-27170: android lint works with dependency on non-android mpp project")
|
||||||
|
@GradleAndroidTest
|
||||||
|
@Disabled // not fully migrated yet
|
||||||
|
fun testLintInAndroidProjectsDependingOnMppWithoutAndroid(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"AndroidProject",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
// embedProject(Project("sample-lib", directoryPrefix = "new-mpp-lib-and-app")) // TODO
|
||||||
|
subProject("lib").buildGradle.appendText(
|
||||||
|
//language=Gradle
|
||||||
|
"""
|
||||||
|
|
||||||
|
dependencies { implementation(project(':sample-lib')) }
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
val lintTask = ":Lib:lintFlavor1Debug"
|
||||||
|
build(lintTask) {
|
||||||
|
assertTasksExecuted(lintTask) // Check that the lint task ran successfully, KT-27170
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("MPP allTests task depending on Android unit tests")
|
||||||
|
@GradleAndroidTest
|
||||||
|
fun testMppAllTests(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"new-mpp-android",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build(":lib:allTests", "--dry-run") {
|
||||||
|
assertOutputContains(":lib:testDebugUnitTest SKIPPED")
|
||||||
|
assertOutputContains(":lib:testReleaseUnitTest SKIPPED")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starting from AGP version 7.1.0-alpha13, a new attribute com.android.build.api.attributes.AgpVersionAttr was added.
|
||||||
|
* This attribute is *not intended* to be published.
|
||||||
|
*/
|
||||||
|
@DisplayName("KT-49798: com.android.build.api.attributes.AgpVersionAttr is not published")
|
||||||
|
@GradleAndroidTest
|
||||||
|
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_71)
|
||||||
|
fun testKT49798AgpVersionAttrNotPublished(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"new-mpp-android",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("publish") {
|
||||||
|
val libProject = subProject("lib")
|
||||||
|
val debugPublicationDirectory = libProject.projectPath.resolve("build/repo/com/example/lib-androidlib-debug")
|
||||||
|
val releasePublicationDirectory = libProject.projectPath.resolve("build/repo/com/example/lib-androidlib")
|
||||||
|
|
||||||
|
listOf(debugPublicationDirectory, releasePublicationDirectory).forEach { publicationDirectory ->
|
||||||
|
assertDirectoryExists(publicationDirectory)
|
||||||
|
val moduleFiles = Files.walk(publicationDirectory).use { it.filter { file -> file.extension == "module" }.toList() }
|
||||||
|
assertTrue(moduleFiles.isNotEmpty(), "Missing .module file in $publicationDirectory")
|
||||||
|
assertTrue(moduleFiles.size == 1, "Multiple .module files in $publicationDirectory: $moduleFiles")
|
||||||
|
|
||||||
|
val moduleFile = moduleFiles.single()
|
||||||
|
val moduleFileText = moduleFile.readText()
|
||||||
|
assertTrue("AgpVersionAttr" !in moduleFileText, ".module file $moduleFile leaks AgpVersionAttr")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("produced artifacts are consumable by projects with various AGP versions")
|
||||||
|
@GradleAndroidTest
|
||||||
|
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_71)
|
||||||
|
fun testAndroidMultiplatformPublicationAGPCompatibility(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"new-mpp-android-agp-compatibility",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
/* Publish a producer library with the current version of AGP */
|
||||||
|
build(":producer:publishAllPublicationsToBuildDirRepository") {
|
||||||
|
/* Check expected publication layout */
|
||||||
|
assertDirectoryInProjectExists("build/repo/com/example/producer-android")
|
||||||
|
assertDirectoryInProjectExists("build/repo/com/example/producer-android-debug")
|
||||||
|
assertDirectoryInProjectExists("build/repo/com/example/producer-jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
val checkedConsumerAGPVersions = AGPVersion.testedVersions
|
||||||
|
// Special version added for testing KT-49798
|
||||||
|
.plus(AGPVersion.fromString("7.1.0-beta02"))
|
||||||
|
.filter { version -> version >= AGPVersion.fromString(TestVersions.AGP.AGP_42) }
|
||||||
|
.filter { version -> version < AGPVersion.fromString(TestVersions.AGP.MAX_SUPPORTED) }
|
||||||
|
.map { it.toString() }
|
||||||
|
|
||||||
|
checkedConsumerAGPVersions.forEach { consumerAgpVersion ->
|
||||||
|
println("Testing compatibility for AGP consumer version $consumerAgpVersion (Producer: $agpVersion)")
|
||||||
|
val buildOptions = buildOptions.copy(androidVersion = consumerAgpVersion)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Project: multiplatformAndroidConsumer is a mpp project with jvm and android targets.
|
||||||
|
This project depends on the previous publication as 'commonMainImplementation' dependency
|
||||||
|
*/
|
||||||
|
build(":multiplatformAndroidConsumer:assemble", buildOptions = buildOptions)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Project: plainAndroidConsumer only uses the 'kotlin("android")' plugin
|
||||||
|
This project depends on the previous publication as 'implementation' dependency
|
||||||
|
*/
|
||||||
|
build(":plainAndroidConsumer:assemble", buildOptions = buildOptions)
|
||||||
|
println("Successfully tested compatibility for AGP consumer version $consumerAgpVersion (Producer: $agpVersion)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("KT-49877, KT-35916: associate compilation dependencies are passed correctly to android test compilations")
|
||||||
|
@GradleAndroidTest
|
||||||
|
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_71)
|
||||||
|
fun testAssociateCompilationDependenciesArePassedToAndroidTestCompilations(
|
||||||
|
gradleVersion: GradleVersion,
|
||||||
|
agpVersion: String,
|
||||||
|
jdkVersion: JdkVersions.ProvidedJdk,
|
||||||
|
) {
|
||||||
|
project(
|
||||||
|
"kt-49877",
|
||||||
|
gradleVersion,
|
||||||
|
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion),
|
||||||
|
buildJdk = jdkVersion.location
|
||||||
|
) {
|
||||||
|
build("allTests") {
|
||||||
|
assertTasksExecuted(
|
||||||
|
":compileDebugKotlinAndroid",
|
||||||
|
":compileReleaseKotlinAndroid",
|
||||||
|
":compileDebugUnitTestKotlinAndroid",
|
||||||
|
":compileReleaseUnitTestKotlinAndroid",
|
||||||
|
":testDebugUnitTest",
|
||||||
|
":testReleaseUnitTest",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// instrumented tests don't work without a device, so we only compile them
|
||||||
|
build("packageDebugAndroidTest") {
|
||||||
|
assertTasksExecuted(
|
||||||
|
":compileDebugAndroidTestKotlinAndroid",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -85,6 +85,20 @@ fun assertCompiledKotlinSources(
|
|||||||
assertSameFiles(expectedSources, actualSources, "Compiled Kotlin files differ${errorMessageSuffix}:\n")
|
assertSameFiles(expectedSources, actualSources, "Compiled Kotlin files differ${errorMessageSuffix}:\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts all the .java files from [expectedSources] and only they are compiled
|
||||||
|
*
|
||||||
|
* Note: log level of output should be set to [LogLevel.DEBUG]
|
||||||
|
*/
|
||||||
|
fun GradleProject.assertCompiledJavaSources(
|
||||||
|
expectedSources: Iterable<Path>,
|
||||||
|
output: String,
|
||||||
|
errorMessageSuffix: String = ""
|
||||||
|
) {
|
||||||
|
val actualSources = extractCompiledJavaFiles(projectPath.toRealPath().toFile(), output)
|
||||||
|
assertSameFiles(expectedSources, actualSources, "Compiled Java files differ${errorMessageSuffix}:\n")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that compilation was non-incremental.
|
* Asserts that compilation was non-incremental.
|
||||||
*
|
*
|
||||||
|
|||||||
+13
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.testbase
|
package org.jetbrains.kotlin.gradle.testbase
|
||||||
|
|
||||||
|
import org.gradle.api.logging.LogLevel
|
||||||
import org.gradle.testkit.runner.BuildResult
|
import org.gradle.testkit.runner.BuildResult
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,6 +20,18 @@ fun BuildResult.assertOutputContains(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts Gradle output contains any of [expectedSubString] strings.
|
||||||
|
*/
|
||||||
|
fun BuildResult.assertOutputContainsAny(
|
||||||
|
vararg expectedSubStrings: String
|
||||||
|
) {
|
||||||
|
assert(expectedSubStrings.any { output.contains(it) }) {
|
||||||
|
printBuildOutput()
|
||||||
|
"Build output does not contain any of \"$expectedSubStrings\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts Gradle output contains [expectedSubString] string exact times.
|
* Asserts Gradle output contains [expectedSubString] string exact times.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+27
@@ -8,6 +8,26 @@ package org.jetbrains.kotlin.gradle.testbase
|
|||||||
import org.gradle.testkit.runner.BuildResult
|
import org.gradle.testkit.runner.BuildResult
|
||||||
import org.gradle.testkit.runner.TaskOutcome
|
import org.gradle.testkit.runner.TaskOutcome
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts given tasks are not present in the build task graph
|
||||||
|
*/
|
||||||
|
fun BuildResult.assertTasksAreNotInTaskGraph(vararg tasks: String) {
|
||||||
|
val presentTasks = tasks.filter { task(it) != null }
|
||||||
|
assert(presentTasks.isEmpty()) {
|
||||||
|
printBuildOutput()
|
||||||
|
"Tasks ${tasks.joinToString(prefix = "[", postfix = "]")} shouldn't be present in the task graph, but $presentTasks were present"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the affected during the build tasks, whose [org.gradle.api.Task.getPath] satisfies the [pattern]
|
||||||
|
*/
|
||||||
|
fun BuildResult.findTasksByPattern(pattern: Regex): Set<String> {
|
||||||
|
return tasks.map { it.path }.filter { taskPath ->
|
||||||
|
pattern.matches(taskPath)
|
||||||
|
}.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts given [tasks] have 'SUCCESS' execution state.
|
* Asserts given [tasks] have 'SUCCESS' execution state.
|
||||||
*/
|
*/
|
||||||
@@ -51,6 +71,13 @@ fun BuildResult.assertTasksUpToDate(vararg tasks: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts given [tasks] have 'UP-TO-DATE' execution state.
|
||||||
|
*/
|
||||||
|
fun BuildResult.assertTasksUpToDate(tasks: Collection<String>) {
|
||||||
|
assertTasksUpToDate(*tasks.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts given [tasks] have 'SKIPPED' execution state.
|
* Asserts given [tasks] have 'SKIPPED' execution state.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+4
-3
@@ -53,12 +53,13 @@ fun TestProject.testResolveAllConfigurations(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (!skipSetup) {
|
if (!skipSetup) {
|
||||||
|
val targetProject = subproject?.let { subProject(it) } ?: this
|
||||||
when {
|
when {
|
||||||
Files.exists(buildGradle) -> buildGradle
|
Files.exists(targetProject.buildGradle) -> targetProject.buildGradle
|
||||||
.append("\n${generateResolveAllConfigurationsTask(excludeConfigurations)}")
|
.append("\n${generateResolveAllConfigurationsTask(excludeConfigurations)}")
|
||||||
Files.exists(buildGradleKts) -> buildGradleKts
|
Files.exists(targetProject.buildGradleKts) -> targetProject.buildGradleKts
|
||||||
.append("\n${generateResolveAllConfigurationsTaskKts(excludeConfigurations)}")
|
.append("\n${generateResolveAllConfigurationsTaskKts(excludeConfigurations)}")
|
||||||
else -> error("Build script does not exists under $projectPath")
|
else -> error("Build script does not exist under $projectPath")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -49,5 +49,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'com.google.dagger:dagger:2.9'
|
implementation 'com.google.dagger:dagger:2.9'
|
||||||
kapt 'com.google.dagger:dagger-compiler:2.9'
|
kapt 'com.google.dagger:dagger-compiler:2.9'
|
||||||
|
kapt 'javax.annotation:javax.annotation-api:1.3.2'
|
||||||
compileOnly 'org.glassfish:javax.annotation:10.0-b28'
|
compileOnly 'org.glassfish:javax.annotation:10.0-b28'
|
||||||
}
|
}
|
||||||
+1
-1
@@ -9,7 +9,7 @@ import org.gradle.api.logging.Logger
|
|||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
|
|
||||||
// todo: remove when https://github.com/gradle/gradle/issues/2678 is resolved
|
// todo: remove when https://github.com/gradle/gradle/issues/16991 is resolved
|
||||||
internal object TaskLoggers {
|
internal object TaskLoggers {
|
||||||
private val taskLoggers = HashMap<String, WeakReference<Logger>>()
|
private val taskLoggers = HashMap<String, WeakReference<Logger>>()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user