Migrate IncrementalCompilationMultiProjectIT test to new dsl
^KT-45745 In Progress
This commit is contained in:
committed by
teamcity
parent
a5c1febf88
commit
14dc20186d
+2
-1
@@ -16,8 +16,9 @@ abstract class IncrementalCompilationBaseIT : KGPBaseTest() {
|
|||||||
|
|
||||||
protected abstract val defaultProjectName: String
|
protected abstract val defaultProjectName: String
|
||||||
|
|
||||||
fun defaultProject(
|
open fun defaultProject(
|
||||||
gradleVersion: GradleVersion,
|
gradleVersion: GradleVersion,
|
||||||
|
buildOptions: BuildOptions = defaultBuildOptions,
|
||||||
test: TestProject.() -> Unit = {}
|
test: TestProject.() -> Unit = {}
|
||||||
): TestProject = project(
|
): TestProject = project(
|
||||||
defaultProjectName,
|
defaultProjectName,
|
||||||
|
|||||||
+441
-283
@@ -1,24 +1,29 @@
|
|||||||
package org.jetbrains.kotlin.gradle
|
package org.jetbrains.kotlin.gradle
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.util.*
|
import org.gradle.testkit.runner.BuildResult
|
||||||
import org.junit.Test
|
import org.gradle.util.GradleVersion
|
||||||
import java.io.File
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
|
import org.jetbrains.kotlin.gradle.util.checkedReplace
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import java.nio.file.Path
|
||||||
|
import kotlin.io.path.*
|
||||||
|
|
||||||
|
@JsGradlePluginTests
|
||||||
class IncrementalCompilationJsMultiProjectIT : BaseIncrementalCompilationMultiProjectIT() {
|
class IncrementalCompilationJsMultiProjectIT : BaseIncrementalCompilationMultiProjectIT() {
|
||||||
override fun defaultProject(): Project {
|
override val defaultProjectName: String = "incrementalMultiproject"
|
||||||
val project = Project("incrementalMultiproject")
|
|
||||||
project.setupWorkingDir()
|
|
||||||
|
|
||||||
for (subProject in arrayOf("app", "lib")) {
|
override fun defaultProject(
|
||||||
val subProjectDir = project.projectDir.resolve(subProject)
|
gradleVersion: GradleVersion,
|
||||||
subProjectDir.resolve("src/main/java").deleteRecursively()
|
buildOptions: BuildOptions,
|
||||||
val buildGradle = subProjectDir.resolve("build.gradle")
|
test: TestProject.() -> Unit
|
||||||
val buildJsGradle = subProjectDir.resolve("build-js.gradle")
|
): TestProject = project(defaultProjectName, gradleVersion) {
|
||||||
buildJsGradle.copyTo(buildGradle, overwrite = true)
|
listOf("app", "lib").forEach {
|
||||||
buildJsGradle.delete()
|
val subProject = subProject(it)
|
||||||
|
subProject.javaSourcesDir().deleteRecursively()
|
||||||
|
val buildGradleJs = subProject.projectPath.resolve("build-js.gradle")
|
||||||
|
subProject.buildGradle.writeText(buildGradleJs.readText())
|
||||||
|
buildGradleJs.deleteExisting()
|
||||||
}
|
}
|
||||||
|
|
||||||
return project
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val additionalLibDependencies: String =
|
override val additionalLibDependencies: String =
|
||||||
@@ -28,6 +33,7 @@ class IncrementalCompilationJsMultiProjectIT : BaseIncrementalCompilationMultiPr
|
|||||||
get() = "compileKotlin2Js"
|
get() = "compileKotlin2Js"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmGradlePluginTests
|
||||||
open class IncrementalCompilationJvmMultiProjectIT : BaseIncrementalCompilationMultiProjectIT() {
|
open class IncrementalCompilationJvmMultiProjectIT : BaseIncrementalCompilationMultiProjectIT() {
|
||||||
override val additionalLibDependencies: String =
|
override val additionalLibDependencies: String =
|
||||||
"implementation \"org.jetbrains.kotlin:kotlin-test:${'$'}kotlin_version\""
|
"implementation \"org.jetbrains.kotlin:kotlin-test:${'$'}kotlin_version\""
|
||||||
@@ -35,43 +41,52 @@ open class IncrementalCompilationJvmMultiProjectIT : BaseIncrementalCompilationM
|
|||||||
override val compileKotlinTaskName: String
|
override val compileKotlinTaskName: String
|
||||||
get() = "compileKotlin"
|
get() = "compileKotlin"
|
||||||
|
|
||||||
override fun defaultProject(): Project =
|
override val defaultProjectName: String = "incrementalMultiproject"
|
||||||
Project("incrementalMultiproject")
|
|
||||||
|
|
||||||
// todo: do the same for js backend
|
// todo: do the same for js backend
|
||||||
@Test
|
@DisplayName("Duplicated class")
|
||||||
fun testDuplicatedClass() {
|
@GradleTest
|
||||||
val project = Project("duplicatedClass")
|
fun testDuplicatedClass(gradleVersion: GradleVersion) {
|
||||||
project.build("build") {
|
project("duplicatedClass", gradleVersion) {
|
||||||
assertSuccessful()
|
build("assemble")
|
||||||
}
|
|
||||||
|
|
||||||
val usagesFiles = listOf("useBuzz.kt", "useA.kt").map { project.projectFile(it) }
|
val usagesFiles = listOf("useBuzz.kt", "useA.kt").map {
|
||||||
|
subProject("app").kotlinSourcesDir().resolve(it)
|
||||||
|
}
|
||||||
usagesFiles.forEach { file -> file.modify { "$it\n " } }
|
usagesFiles.forEach { file -> file.modify { "$it\n " } }
|
||||||
|
|
||||||
project.build("build") {
|
build("assemble") {
|
||||||
assertSuccessful()
|
assertCompiledKotlinSources(
|
||||||
assertCompiledKotlinSources(project.relativize(usagesFiles))
|
usagesFiles.map { it.relativeTo(projectPath) },
|
||||||
|
output
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks that multi-project ic is disabled when there is a task that outputs to javaDestination dir
|
@DisplayName(
|
||||||
// that is not JavaCompile or KotlinCompile
|
"checks that multi-project ic is disabled when there is a task that outputs to javaDestination dir " +
|
||||||
@Test
|
"that is not JavaCompile or KotlinCompile"
|
||||||
open fun testCompileLibWithGroovy() {
|
)
|
||||||
testCompileLibWithGroovy_doTest {
|
@GradleTest
|
||||||
assertCompiledKotlinFiles(
|
open fun testCompileLibWithGroovy(gradleVersion: GradleVersion) {
|
||||||
File(project.projectDir, "app").allKotlinFiles() + File(project.projectDir, "lib").getFileByName("A.kt")
|
testCompileLibWithGroovy_doTest(gradleVersion) { project, result ->
|
||||||
|
val expectedSources = project.subProject("app").projectPath.resolve("src").allKotlinSources +
|
||||||
|
listOf(project.subProject("lib").kotlinSourcesDir().resolve("bar/A.kt"))
|
||||||
|
|
||||||
|
assertCompiledKotlinSources(
|
||||||
|
expectedSources.map { it.relativeTo(project.projectPath) },
|
||||||
|
result.output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun testCompileLibWithGroovy_doTest(assertResults: CompiledProject.() -> Unit) {
|
protected fun testCompileLibWithGroovy_doTest(
|
||||||
val project = defaultProject()
|
gradleVersion: GradleVersion,
|
||||||
project.setupWorkingDir()
|
assertResults: (TestProject, BuildResult) -> Unit
|
||||||
val lib = File(project.projectDir, "lib")
|
) {
|
||||||
val libBuildGradle = File(lib, "build.gradle")
|
defaultProject(gradleVersion) {
|
||||||
libBuildGradle.modify {
|
subProject("lib").buildGradle.modify {
|
||||||
"""
|
"""
|
||||||
plugins {
|
plugins {
|
||||||
id 'groovy'
|
id 'groovy'
|
||||||
@@ -85,33 +100,33 @@ open class IncrementalCompilationJvmMultiProjectIT : BaseIncrementalCompilationM
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
val libGroovySrcBar = File(lib, "src/main/groovy/bar").apply { mkdirs() }
|
val libGroovySrcBar = subProject("lib")
|
||||||
val groovyClass = File(libGroovySrcBar, "GroovyClass.groovy")
|
.projectPath
|
||||||
|
.resolve("src/main/groovy/bar")
|
||||||
|
.apply { createDirectories() }
|
||||||
|
val groovyClass = libGroovySrcBar.resolve("GroovyClass.groovy")
|
||||||
groovyClass.writeText(
|
groovyClass.writeText(
|
||||||
"""
|
"""
|
||||||
package bar
|
package bar
|
||||||
|
|
||||||
class GroovyClass {}
|
class GroovyClass {}
|
||||||
"""
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
|
|
||||||
project.build("build") {
|
build("assemble")
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
project.changeMethodBodyInLib()
|
changeMethodBodyInLib()
|
||||||
project.build("build") {
|
build("build") {
|
||||||
assertSuccessful()
|
assertResults(this@defaultProject, this)
|
||||||
assertResults()
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Regression test for KT-43489. Make sure build history mapping is not initialized too early. */
|
@DisplayName("KT-43489: Make sure build history mapping is not initialized too early")
|
||||||
@Test
|
@GradleTest
|
||||||
fun testBuildHistoryMappingLazilyComputedWithWorkers() {
|
fun testBuildHistoryMappingLazilyComputedWithWorkers(gradleVersion: GradleVersion) {
|
||||||
val project = defaultProject()
|
defaultProject(gradleVersion) {
|
||||||
project.setupWorkingDir()
|
subProject("app").buildGradle.appendText(
|
||||||
project.projectDir.resolve("app/build.gradle").appendText(
|
|
||||||
"""
|
"""
|
||||||
// added to force eager configuration
|
// added to force eager configuration
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
@@ -119,12 +134,10 @@ open class IncrementalCompilationJvmMultiProjectIT : BaseIncrementalCompilationM
|
|||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
val options = defaultBuildOptions().copy(parallelTasksInProject = true)
|
|
||||||
project.build(options = options, params = arrayOf("build")) {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
val aKt = project.projectDir.getFileByName("A.kt")
|
build("assemble")
|
||||||
|
|
||||||
|
val aKt = subProject("lib").kotlinSourcesDir().resolve("bar/A.kt")
|
||||||
aKt.writeText(
|
aKt.writeText(
|
||||||
"""
|
"""
|
||||||
package bar
|
package bar
|
||||||
@@ -133,94 +146,114 @@ open class A {
|
|||||||
fun a() {}
|
fun a() {}
|
||||||
fun newA() {}
|
fun newA() {}
|
||||||
}
|
}
|
||||||
"""
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
|
|
||||||
project.build(options = options, params = arrayOf("build")) {
|
build("assemble") {
|
||||||
assertSuccessful()
|
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
||||||
val affectedSources = project.projectDir.getFilesByNames("A.kt", "B.kt", "AA.kt", "AAA.kt", "BB.kt")
|
libSources = listOf("bar/A.kt", "bar/B.kt"),
|
||||||
val relativePaths = project.relativize(affectedSources)
|
appSources = listOf("foo/AA.kt", "foo/AAA.kt", "foo/BB.kt")
|
||||||
assertCompiledKotlinSources(relativePaths)
|
)
|
||||||
|
assertCompiledKotlinSources(expectedSources, output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IncrementalCompilationFirJvmMultiProjectIT : IncrementalCompilationJvmMultiProjectIT() {
|
class IncrementalCompilationFirJvmMultiProjectIT : IncrementalCompilationJvmMultiProjectIT() {
|
||||||
override fun defaultBuildOptions(): BuildOptions {
|
override val defaultBuildOptions: BuildOptions = super.defaultBuildOptions.copy(useFir = true)
|
||||||
return super.defaultBuildOptions().copy(useFir = true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IncrementalCompilationClasspathSnapshotJvmMultiProjectIT : IncrementalCompilationJvmMultiProjectIT() {
|
class IncrementalCompilationClasspathSnapshotJvmMultiProjectIT : IncrementalCompilationJvmMultiProjectIT() {
|
||||||
|
|
||||||
override fun defaultBuildOptions() = super.defaultBuildOptions().copy(useClasspathSnapshot = true)
|
override val defaultBuildOptions = super.defaultBuildOptions.copy(useGradleClasspathSnapshot = true)
|
||||||
|
|
||||||
@Test
|
@DisplayName("Lib: Non ABI change in method body")
|
||||||
override fun testNonAbiChangeInLib_changeMethodBody() {
|
@GradleTest
|
||||||
doTest(
|
override fun testNonAbiChangeInLib_changeMethodBody(gradleVersion: GradleVersion) {
|
||||||
modifyProject = changeMethodBodyInLib,
|
defaultProject(gradleVersion) {
|
||||||
assertResults = {
|
build("assemble")
|
||||||
assertTasksExecuted(":lib:$compileKotlinTaskName")
|
|
||||||
assertTasksUpToDate(":app:$compileKotlinTaskName") // App compilation has 'compile avoidance'
|
|
||||||
assertCompiledKotlinFiles(File(project.projectDir, "lib").getFilesByNames("A.kt"))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
changeMethodBodyInLib()
|
||||||
override fun testAddDependencyInLib() {
|
|
||||||
doTest(
|
build("assemble") {
|
||||||
modifyProject = { testAddDependencyInLib_modifyProject() },
|
|
||||||
assertResults = {
|
|
||||||
assertTasksExecuted(":lib:$compileKotlinTaskName")
|
assertTasksExecuted(":lib:$compileKotlinTaskName")
|
||||||
assertTasksUpToDate(":app:$compileKotlinTaskName")
|
assertTasksUpToDate(":app:$compileKotlinTaskName")
|
||||||
assertCompiledKotlinFiles(emptyList()) // Lib compilation is incremental (no files are recompiled)
|
assertCompiledKotlinSources(
|
||||||
}
|
getExpectedKotlinSourcesForDefaultProject(libSources = listOf("bar/A.kt")),
|
||||||
|
output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("Add dependency in lib subproject")
|
||||||
override fun testAbiChangeInLib_afterLibClean() {
|
@GradleTest
|
||||||
doTest(
|
override fun testAddDependencyInLib(gradleVersion: GradleVersion) {
|
||||||
modifyProject = {
|
defaultProject(gradleVersion) {
|
||||||
build(":lib:clean") { assertSuccessful() }
|
build("assemble")
|
||||||
changeMethodSignatureInLib()
|
|
||||||
},
|
|
||||||
assertResults = {
|
|
||||||
assertCompiledKotlinFiles(
|
|
||||||
// App compilation is incremental
|
|
||||||
File(project.projectDir, "app").getFilesByNames("AA.kt", "AAA.kt", "BB.kt", "fooUseA.kt") +
|
|
||||||
File(project.projectDir, "lib").allKotlinFiles()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
testAddDependencyInLib_modifyProject()
|
||||||
override fun testCompileLibWithGroovy() {
|
|
||||||
testCompileLibWithGroovy_doTest {
|
build("assemble") {
|
||||||
assertTasksExecuted(":lib:$compileKotlinTaskName")
|
assertTasksExecuted(":lib:$compileKotlinTaskName")
|
||||||
assertTasksUpToDate(":app:$compileKotlinTaskName") // App compilation has 'compile avoidance'
|
assertTasksUpToDate(":app:$compileKotlinTaskName")
|
||||||
assertCompiledKotlinFiles(listOf(File(project.projectDir, "lib").getFileByName("A.kt")))
|
// Lib compilation is incremental (no files are recompiled)
|
||||||
|
assertCompiledKotlinSources(emptyList(), output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("after lib project clean")
|
||||||
override fun testAbiChangeInLib_afterLibClean_withAbiSnapshot() {
|
@GradleTest
|
||||||
doTest(
|
override fun testAbiChangeInLib_afterLibClean(gradleVersion: GradleVersion) {
|
||||||
options = defaultBuildOptions().copy(abiSnapshot = true),
|
defaultProject(gradleVersion) {
|
||||||
modifyProject = {
|
build("assemble")
|
||||||
build(":lib:clean") { assertSuccessful() }
|
|
||||||
|
build(":lib:clean")
|
||||||
changeMethodSignatureInLib()
|
changeMethodSignatureInLib()
|
||||||
},
|
|
||||||
assertResults = {
|
build("assemble") {
|
||||||
assertCompiledKotlinFiles(
|
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
||||||
// App compilation is incremental
|
appSources = listOf("foo/AA.kt", "foo/AAA.kt", "foo/BB.kt", "foo/fooUseA.kt")
|
||||||
File(project.projectDir, "app").getFilesByNames("AA.kt", "AAA.kt", "BB.kt", "fooUseA.kt") +
|
) + subProject("lib").projectPath.resolve("src").allKotlinSources.map { it.relativeTo(projectPath) }
|
||||||
File(project.projectDir, "lib").allKotlinFiles()
|
|
||||||
|
assertCompiledKotlinSources(expectedSources, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("Compile lib with Groovy")
|
||||||
|
@GradleTest
|
||||||
|
override fun testCompileLibWithGroovy(gradleVersion: GradleVersion) {
|
||||||
|
testCompileLibWithGroovy_doTest(gradleVersion) { project, result ->
|
||||||
|
result.assertTasksExecuted(":lib:$compileKotlinTaskName")
|
||||||
|
result.assertTasksUpToDate(":app:$compileKotlinTaskName") // App compilation has 'compile avoidance'
|
||||||
|
|
||||||
|
assertCompiledKotlinSources(
|
||||||
|
project.getExpectedKotlinSourcesForDefaultProject(libSources = listOf("bar/A.kt")),
|
||||||
|
result.output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
@DisplayName("Lib: after cleaning lib project")
|
||||||
|
@GradleTest
|
||||||
|
override fun testAbiChangeInLib_afterLibClean_withAbiSnapshot(gradleVersion: GradleVersion) {
|
||||||
|
defaultProject(gradleVersion) {
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
|
build(":lib:clean")
|
||||||
|
changeMethodSignatureInLib()
|
||||||
|
|
||||||
|
build("assemble") {
|
||||||
|
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
||||||
|
appSources = listOf("foo/AA.kt", "foo/AAA.kt", "foo/BB.kt", "foo/fooUseA.kt")
|
||||||
|
) + subProject("lib").projectPath.resolve("src").allKotlinSources.map { it.relativeTo(projectPath) }
|
||||||
|
|
||||||
|
assertCompiledKotlinSources(expectedSources, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,68 +263,124 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
|
|
||||||
protected abstract val additionalLibDependencies: String
|
protected abstract val additionalLibDependencies: String
|
||||||
|
|
||||||
protected val changeMethodSignatureInLib: Project.() -> Unit = {
|
protected fun TestProject.changeMethodSignatureInLib() {
|
||||||
File(projectDir, "lib").getFileByName("A.kt").modify {
|
subProject("lib").kotlinSourcesDir().resolve("bar/A.kt").modify {
|
||||||
it.replace("fun a() {}", "fun a(): Int = 1")
|
it.replace("fun a() {}", "fun a(): Int = 1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val changeMethodBodyInLib: Project.() -> Unit = {
|
protected fun TestProject.changeMethodBodyInLib() {
|
||||||
File(projectDir, "lib").getFileByName("A.kt").modify {
|
subProject("lib").kotlinSourcesDir().resolve("bar/A.kt").modify {
|
||||||
it.replace("fun a() {}", "fun a() { println() }")
|
it.replace("fun a() {}", "fun a() { println() }")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
protected fun TestProject.getExpectedKotlinSourcesForDefaultProject(
|
||||||
fun testAbiChangeInLib_changeMethodSignature() {
|
libSources: List<String> = emptyList(),
|
||||||
doTest(
|
appSources: List<String> = emptyList()
|
||||||
modifyProject = changeMethodSignatureInLib,
|
): Iterable<Path> {
|
||||||
expectedCompiledFileNames = listOf(
|
val expectedLibSources = if (libSources.isNotEmpty()) {
|
||||||
"A.kt", "B.kt", "barUseA.kt", // In lib
|
sourceFilesRelativeToProject(
|
||||||
"AA.kt", "AAA.kt", "BB.kt", "fooUseA.kt" // In app
|
libSources,
|
||||||
)
|
sourcesDir = { kotlinSourcesDir() },
|
||||||
|
subProjectName = "lib"
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
val expectedAppSources = if (appSources.isNotEmpty()) {
|
||||||
fun testAbiChangeInLib_addNewMethod() {
|
sourceFilesRelativeToProject(
|
||||||
doTest(
|
appSources,
|
||||||
modifyProject = {
|
sourcesDir = { kotlinSourcesDir() },
|
||||||
File(projectDir, "lib").getFileByName("A.kt").modify {
|
subProjectName = "app"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
return expectedLibSources + expectedAppSources
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("Lib: method signature ABI change")
|
||||||
|
@GradleTest
|
||||||
|
fun testAbiChangeInLib_changeMethodSignature(gradleVersion: GradleVersion) {
|
||||||
|
defaultProject(gradleVersion) {
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
|
changeMethodSignatureInLib()
|
||||||
|
|
||||||
|
build("assemble") {
|
||||||
|
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
||||||
|
libSources = listOf("bar/A.kt", "bar/B.kt", "bar/barUseA.kt"),
|
||||||
|
appSources = listOf("foo/AA.kt", "foo/AAA.kt", "foo/BB.kt", "foo/fooUseA.kt")
|
||||||
|
)
|
||||||
|
|
||||||
|
assertCompiledKotlinSources(expectedSources, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("Lib: add new method changing ABI")
|
||||||
|
@GradleTest
|
||||||
|
fun testAbiChangeInLib_addNewMethod(gradleVersion: GradleVersion) {
|
||||||
|
defaultProject(gradleVersion) {
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
|
subProject("lib").kotlinSourcesDir().resolve("bar/A.kt").modify {
|
||||||
it.replace("fun a() {}", "fun a() {}\nfun newA() {}")
|
it.replace("fun a() {}", "fun a() {}\nfun newA() {}")
|
||||||
}
|
}
|
||||||
},
|
|
||||||
expectedCompiledFileNames = listOf(
|
build("assemble") {
|
||||||
"A.kt", "B.kt", // In lib
|
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
||||||
"AA.kt", "AAA.kt", "BB.kt" // In app
|
libSources = listOf("bar/A.kt", "bar/B.kt"),
|
||||||
)
|
appSources = listOf("foo/AA.kt", "foo/AAA.kt", "foo/BB.kt")
|
||||||
)
|
)
|
||||||
|
assertCompiledKotlinSources(expectedSources, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("Lib: change method body with non-ABI change")
|
||||||
open fun testNonAbiChangeInLib_changeMethodBody() {
|
@GradleTest
|
||||||
doTest(
|
open fun testNonAbiChangeInLib_changeMethodBody(gradleVersion: GradleVersion) {
|
||||||
modifyProject = changeMethodBodyInLib,
|
defaultProject(gradleVersion) {
|
||||||
assertResults = {
|
build("assemble")
|
||||||
assertCompiledKotlinFiles(File(project.projectDir, "lib").getFilesByNames("A.kt"))
|
|
||||||
}
|
changeMethodBodyInLib()
|
||||||
|
|
||||||
|
build("assemble") {
|
||||||
|
assertCompiledKotlinSources(
|
||||||
|
getExpectedKotlinSourcesForDefaultProject(
|
||||||
|
libSources = listOf("bar/A.kt")
|
||||||
|
),
|
||||||
|
output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("Add new dependency in lib project")
|
||||||
open fun testAddDependencyInLib() {
|
@GradleTest
|
||||||
doTest(
|
open fun testAddDependencyInLib(gradleVersion: GradleVersion) {
|
||||||
modifyProject = { testAddDependencyInLib_modifyProject() },
|
defaultProject(gradleVersion) {
|
||||||
assertResults = {
|
build("assemble")
|
||||||
|
|
||||||
|
testAddDependencyInLib_modifyProject()
|
||||||
|
|
||||||
|
build("assemble") {
|
||||||
assertTasksExecuted(":lib:$compileKotlinTaskName")
|
assertTasksExecuted(":lib:$compileKotlinTaskName")
|
||||||
assertTasksUpToDate(":app:$compileKotlinTaskName")
|
assertTasksUpToDate(":app:$compileKotlinTaskName")
|
||||||
assertCompiledKotlinFiles(File(project.projectDir, "lib").allKotlinFiles())
|
assertCompiledKotlinSources(
|
||||||
}
|
subProject("lib").projectPath.resolve("src").allKotlinSources.relativizeTo(projectPath),
|
||||||
|
output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected fun Project.testAddDependencyInLib_modifyProject() {
|
protected fun TestProject.testAddDependencyInLib_modifyProject() {
|
||||||
File(projectDir, "lib/build.gradle").modify {
|
subProject("lib").buildGradle.modify {
|
||||||
"""
|
"""
|
||||||
$it
|
$it
|
||||||
|
|
||||||
@@ -302,75 +391,98 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("ABI change in lib after lib clean")
|
||||||
open fun testAbiChangeInLib_afterLibClean() { // To see if app compilation can be incremental after non-incremental lib compilation
|
@GradleTest
|
||||||
doTest(
|
open fun testAbiChangeInLib_afterLibClean(gradleVersion: GradleVersion) {
|
||||||
modifyProject = {
|
// To see if app compilation can be incremental after non-incremental lib compilation
|
||||||
build(":lib:clean") { assertSuccessful() }
|
defaultProject(gradleVersion) {
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
|
build(":lib:clean")
|
||||||
changeMethodSignatureInLib()
|
changeMethodSignatureInLib()
|
||||||
},
|
|
||||||
assertResults = {
|
build("assemble") {
|
||||||
// App compilation is non-incremental
|
assertCompiledKotlinSources(
|
||||||
assertCompiledKotlinFiles(project.projectDir.allKotlinFiles())
|
subProject("lib")
|
||||||
}
|
.projectPath
|
||||||
|
.resolve("src")
|
||||||
|
.allKotlinSources
|
||||||
|
.relativizeTo(projectPath) +
|
||||||
|
subProject("app")
|
||||||
|
.projectPath
|
||||||
|
.resolve("src")
|
||||||
|
.allKotlinSources
|
||||||
|
.relativizeTo(projectPath),
|
||||||
|
output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("Move function from lib module into app module")
|
||||||
fun testMoveFunctionFromLibToApp() {
|
@GradleTest
|
||||||
doTest(
|
fun testMoveFunctionFromLibToApp(gradleVersion: GradleVersion) {
|
||||||
modifyProject = {
|
defaultProject(gradleVersion) {
|
||||||
val barUseABKt = projectDir.getFileByName("barUseAB.kt")
|
build("assemble")
|
||||||
val barInApp = File(projectDir, "app/src/main/kotlin/bar").apply { mkdirs() }
|
|
||||||
barUseABKt.copyTo(File(barInApp, barUseABKt.name))
|
val origFile = subProject("lib").kotlinSourcesDir().resolve("bar/barUseAB.kt")
|
||||||
barUseABKt.delete()
|
subProject("app").kotlinSourcesDir().run {
|
||||||
},
|
resolve("bar").createDirectory()
|
||||||
expectedCompiledFileNames = listOf("fooCallUseAB.kt", "barUseAB.kt")
|
origFile.copyTo(resolve("bar/barUseAB.kt"))
|
||||||
|
origFile.deleteExisting()
|
||||||
|
}
|
||||||
|
|
||||||
|
build("assemble") {
|
||||||
|
assertCompiledKotlinSources(
|
||||||
|
getExpectedKotlinSourcesForDefaultProject(
|
||||||
|
appSources = listOf("foo/fooCallUseAB.kt", "bar/barUseAB.kt")
|
||||||
|
),
|
||||||
|
output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@Test
|
|
||||||
fun testLibClassBecameFinal() {
|
|
||||||
// TODO: fix fir IC and remove
|
|
||||||
if (defaultBuildOptions().useFir) return
|
|
||||||
|
|
||||||
val project = defaultProject()
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val bKt = project.projectDir.getFileByName("B.kt")
|
@DisplayName("Lib project classes became final")
|
||||||
bKt.modify { it.replace("open class", "class") }
|
@GradleTest
|
||||||
|
fun testLibClassBecameFinal(gradleVersion: GradleVersion) {
|
||||||
|
defaultProject(gradleVersion) {
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
project.build("build") {
|
subProject("lib").kotlinSourcesDir().resolve("bar/B.kt").modify {
|
||||||
assertFailed()
|
it.replace("open class", "class")
|
||||||
val affectedSources = project.projectDir.getFilesByNames(
|
}
|
||||||
"B.kt", "barUseAB.kt", "barUseB.kt",
|
|
||||||
"BB.kt", "fooCallUseAB.kt", "fooUseB.kt"
|
buildAndFail("assemble") {
|
||||||
|
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
||||||
|
libSources = listOf("bar/B.kt", "bar/barUseAB.kt", "bar/barUseB.kt"),
|
||||||
|
appSources = listOf("foo/BB.kt", "foo/fooCallUseAB.kt", "foo/fooUseB.kt")
|
||||||
)
|
)
|
||||||
val relativePaths = project.relativize(affectedSources)
|
assertCompiledKotlinSources(expectedSources, output)
|
||||||
assertCompiledKotlinSources(relativePaths)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("compile error in lib project")
|
||||||
fun testCompileErrorInLib() {
|
@GradleTest
|
||||||
val project = defaultProject()
|
fun testCompileErrorInLib(gradleVersion: GradleVersion) {
|
||||||
project.build("build") {
|
defaultProject(gradleVersion) {
|
||||||
assertSuccessful()
|
build("assemble")
|
||||||
}
|
|
||||||
|
|
||||||
val bKt = project.projectDir.getFileByName("B.kt")
|
val bKt = subProject("lib").kotlinSourcesDir().resolve("bar/B.kt")
|
||||||
val bKtContent = bKt.readText()
|
val bKtContent = bKt.readText()
|
||||||
bKt.delete()
|
bKt.deleteExisting()
|
||||||
|
|
||||||
fun runFailingBuild() {
|
fun runFailingBuild() {
|
||||||
project.build("build") {
|
buildAndFail("assemble") {
|
||||||
assertFailed()
|
assertOutputContains("B.kt has been removed")
|
||||||
assertContains("B.kt has been removed")
|
|
||||||
assertTasksFailed(":lib:$compileKotlinTaskName")
|
assertTasksFailed(":lib:$compileKotlinTaskName")
|
||||||
val affectedFiles = project.projectDir.getFilesByNames("barUseAB.kt", "barUseB.kt")
|
assertCompiledKotlinSources(
|
||||||
assertCompiledKotlinSources(project.relativize(affectedFiles))
|
getExpectedKotlinSourcesForDefaultProject(
|
||||||
|
libSources = listOf("bar/barUseAB.kt", "bar/barUseB.kt")
|
||||||
|
),
|
||||||
|
output
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,48 +491,56 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
|
|
||||||
bKt.writeText(bKtContent.replace("fun b", "open fun b"))
|
bKt.writeText(bKtContent.replace("fun b", "open fun b"))
|
||||||
|
|
||||||
project.build("build") {
|
build("assemble") {
|
||||||
assertSuccessful()
|
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
||||||
val affectedFiles = project.projectDir.getFilesByNames(
|
libSources = listOf("bar/B.kt", "bar/barUseAB.kt", "bar/barUseB.kt"),
|
||||||
"B.kt", "barUseAB.kt", "barUseB.kt",
|
appSources = listOf("foo/BB.kt", "foo/fooUseB.kt")
|
||||||
"BB.kt", "fooUseB.kt"
|
|
||||||
)
|
)
|
||||||
assertCompiledKotlinSources(project.relativize(affectedFiles))
|
assertCompiledKotlinSources(expectedSources, output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("Remove library from classpath")
|
||||||
fun testRemoveLibFromClasspath() {
|
@GradleTest
|
||||||
val project = defaultProject()
|
fun testRemoveLibFromClasspath(gradleVersion: GradleVersion) {
|
||||||
project.build("build") {
|
defaultProject(gradleVersion) {
|
||||||
assertSuccessful()
|
build("assemble")
|
||||||
|
|
||||||
|
val appBuildGradleContent = subProject("app").buildGradle.readText()
|
||||||
|
subProject("app").buildGradle.modify { it.checkedReplace("implementation project(':lib')", "") }
|
||||||
|
val aaKt = subProject("app").kotlinSourcesDir().resolve("foo/AA.kt")
|
||||||
|
aaKt.modify {
|
||||||
|
"""
|
||||||
|
$it
|
||||||
|
|
||||||
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
val appBuildGradle = project.projectDir.resolve("app/build.gradle")
|
buildAndFail("assemble")
|
||||||
val appBuildGradleContent = appBuildGradle.readText()
|
|
||||||
appBuildGradle.modify { it.checkedReplace("implementation project(':lib')", "") }
|
|
||||||
val aaKt = project.projectDir.getFileByName("AA.kt")
|
|
||||||
aaKt.addNewLine()
|
|
||||||
|
|
||||||
project.build("build") {
|
subProject("app").buildGradle.writeText(appBuildGradleContent)
|
||||||
assertFailed()
|
aaKt.modify {
|
||||||
|
"""
|
||||||
|
$it
|
||||||
|
|
||||||
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
appBuildGradle.writeText(appBuildGradleContent)
|
build("assemble") {
|
||||||
aaKt.addNewLine()
|
assertCompiledKotlinSources(
|
||||||
|
listOf(aaKt.relativeTo(projectPath)),
|
||||||
project.build("build") {
|
output
|
||||||
assertSuccessful()
|
)
|
||||||
assertCompiledKotlinSources(project.relativize(aaKt))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Regression test for KT-40875. */
|
@DisplayName("KT-40875: move function from lib with remapped build dirs")
|
||||||
@Test
|
@GradleTest
|
||||||
fun testMoveFunctionFromLibWithRemappedBuildDirs() {
|
fun testMoveFunctionFromLibWithRemappedBuildDirs(gradleVersion: GradleVersion) {
|
||||||
val project = defaultProject()
|
defaultProject(gradleVersion) {
|
||||||
project.setupWorkingDir()
|
buildGradle.appendText(
|
||||||
project.projectDir.resolve("build.gradle").appendText(
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
@@ -428,65 +548,103 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
build("assemble")
|
||||||
|
|
||||||
|
val barUseABKt = subProject("lib").kotlinSourcesDir().resolve("bar/barUseAB.kt")
|
||||||
|
subProject("app").kotlinSourcesDir().run {
|
||||||
|
resolve("bar").createDirectory()
|
||||||
|
barUseABKt.copyTo(resolve("bar/barUseAB.kt"))
|
||||||
|
barUseABKt.deleteExisting()
|
||||||
}
|
}
|
||||||
|
|
||||||
val barUseABKt = project.projectDir.getFileByName("barUseAB.kt")
|
build("assemble") {
|
||||||
val barInApp = File(project.projectDir, "app/src/main/kotlin/bar").apply { mkdirs() }
|
assertCompiledKotlinSources(
|
||||||
barUseABKt.copyTo(File(barInApp, barUseABKt.name))
|
getExpectedKotlinSourcesForDefaultProject(
|
||||||
barUseABKt.delete()
|
appSources = listOf("foo/fooCallUseAB.kt", "bar/barUseAB.kt")
|
||||||
|
),
|
||||||
project.build("build") {
|
output
|
||||||
assertSuccessful()
|
)
|
||||||
val affectedSources = project.projectDir.getFilesByNames("fooCallUseAB.kt", "barUseAB.kt")
|
}
|
||||||
val relativePaths = project.relativize(affectedSources)
|
|
||||||
assertCompiledKotlinSources(relativePaths)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("Lib with ABI snapshot: add new ABI method")
|
||||||
fun testAbiChangeInLib_addNewMethod_withAbiSnapshot() {
|
@GradleTest
|
||||||
doTest(
|
fun testAbiChangeInLib_addNewMethod_withAbiSnapshot(gradleVersion: GradleVersion) {
|
||||||
options = defaultBuildOptions().copy(abiSnapshot = true),
|
defaultProject(
|
||||||
modifyProject = {
|
gradleVersion,
|
||||||
File(projectDir, "lib").getFileByName("A.kt").modify {
|
buildOptions = defaultBuildOptions.copy(useGradleClasspathSnapshot = true)
|
||||||
|
) {
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
|
subProject("lib").kotlinSourcesDir().resolve("bar/A.kt").modify {
|
||||||
it.replace("fun a() {}", "fun a() {}\nfun newA() {}")
|
it.replace("fun a() {}", "fun a() {}\nfun newA() {}")
|
||||||
}
|
}
|
||||||
},
|
|
||||||
expectedCompiledFileNames = listOf(
|
build("assemble") {
|
||||||
"A.kt", "B.kt", // In lib
|
val expectedSources = getExpectedKotlinSourcesForDefaultProject(
|
||||||
|
libSources = listOf("bar/A.kt", "bar/B.kt"),
|
||||||
// TODO(valtman): for abi-snapshot "BB.kt" should not be recompiled
|
// TODO(valtman): for abi-snapshot "BB.kt" should not be recompiled
|
||||||
"AA.kt", "AAA.kt", "BB.kt" // In app
|
appSources = listOf("foo/AA.kt", "foo/AAA.kt", "foo/BB.kt")
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assertCompiledKotlinSources(expectedSources, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("Lib with abi snapshot: after clean build")
|
||||||
open fun testAbiChangeInLib_afterLibClean_withAbiSnapshot() {
|
@GradleTest
|
||||||
doTest(
|
open fun testAbiChangeInLib_afterLibClean_withAbiSnapshot(gradleVersion: GradleVersion) {
|
||||||
options = defaultBuildOptions().copy(abiSnapshot = true),
|
defaultProject(
|
||||||
modifyProject = {
|
gradleVersion,
|
||||||
build(":lib:clean") { assertSuccessful() }
|
buildOptions = defaultBuildOptions.copy(useGradleClasspathSnapshot = true)
|
||||||
|
) {
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
|
build(":lib:clean")
|
||||||
changeMethodSignatureInLib()
|
changeMethodSignatureInLib()
|
||||||
},
|
|
||||||
assertResults = {
|
build("assemble") {
|
||||||
// TODO: With ABI snapshot, app compilation should be incremental, currently it is not.
|
// TODO: With ABI snapshot, app compilation should be incremental, currently it is not.
|
||||||
assertCompiledKotlinFiles(project.projectDir.allKotlinFiles())
|
assertCompiledKotlinSources(
|
||||||
}
|
(subProject("lib")
|
||||||
|
.projectPath
|
||||||
|
.resolve("src")
|
||||||
|
.allKotlinSources +
|
||||||
|
subProject("app")
|
||||||
|
.projectPath
|
||||||
|
.resolve("src")
|
||||||
|
.allKotlinSources)
|
||||||
|
.map { it.relativeTo(projectPath) },
|
||||||
|
output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@DisplayName("Lib with classpath snapshot: change isolated class")
|
||||||
fun testChangeIsolatedClassInLib_withAbiSnapshot() {
|
@GradleTest
|
||||||
doTest(
|
fun testChangeIsolatedClassInLib_withAbiSnapshot(gradleVersion: GradleVersion) {
|
||||||
options = defaultBuildOptions().copy(abiSnapshot = true),
|
defaultProject(
|
||||||
modifyProject = {
|
gradleVersion,
|
||||||
File(projectDir, "lib").getFileByName("BarDummy.kt").modify {
|
buildOptions = defaultBuildOptions.copy(useGradleClasspathSnapshot = true)
|
||||||
|
) {
|
||||||
|
build("assemble")
|
||||||
|
|
||||||
|
subProject("lib").kotlinSourcesDir().resolve("bar/BarDummy.kt").modify {
|
||||||
"$it { fun m() = 42}"
|
"$it { fun m() = 42}"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
expectedCompiledFileNames = listOf("BarDummy.kt") // In lib
|
build("assemble") {
|
||||||
|
assertCompiledKotlinSources(
|
||||||
|
getExpectedKotlinSourcesForDefaultProject(
|
||||||
|
libSources = listOf("bar/BarDummy.kt")
|
||||||
|
),
|
||||||
|
output
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user