From baa3610c7d3eb488482b971729b6271c5341507e Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Thu, 27 Jan 2022 16:51:11 +0100 Subject: [PATCH] Migrate KaptIncrementalWithIsolatingApt to new test DSL ^KT-45745 In Progress --- .../kotlin/gradle/KaptIncrementalIT.kt | 37 +- .../gradle/KaptIncrementalWithIsolatingApt.kt | 683 +++++++++--------- .../baseLibrary/build.gradle | 4 +- .../kaptIncrementalWithParceler/build.gradle | 17 +- .../mylibrary/build.gradle | 4 +- 5 files changed, 352 insertions(+), 393 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt index 8755a590fbc..52e7a140da3 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt @@ -6,6 +6,7 @@ import org.gradle.testkit.runner.BuildResult import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.testbase.* import org.junit.jupiter.api.DisplayName +import java.io.File import java.nio.file.Path import java.util.* import kotlin.io.path.createDirectories @@ -31,10 +32,23 @@ open class KaptIncrementalIT : KGPBaseTest() { kaptOptions = BuildOptions.KaptOptions(incrementalKapt = true) ) + protected open fun KGPBaseTest.kaptProject( + gradleVersion: GradleVersion, + buildOptions: BuildOptions = defaultBuildOptions, + buildJdk: File? = null, + test: TestProject.() -> Unit + ): TestProject = project( + PROJECT_NAME, + gradleVersion, + buildOptions = buildOptions, + buildJdk = buildJdk, + test = test + ) + @DisplayName("After adding new line compilation is incremental") @GradleTest fun testAddNewLine(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("clean", "build") javaSourcesDir().resolve("bar/useB.kt").modify { "\n$it" } @@ -49,8 +63,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("On rebuild without changes tasks should be UP-TO-DATE") @GradleTest fun testBasic(gradleVersion: GradleVersion) { - project( - PROJECT_NAME, + kaptProject( gradleVersion, buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG) ) { @@ -77,7 +90,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("Successfully rebuild after error") @GradleTest fun testCompileError(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("assemble") val bKt = javaSourcesDir().resolve("bar/B.kt") @@ -100,7 +113,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("Change in the function body without changing the signature") @GradleTest fun testChangeFunctionBodyWithoutChangingSignature(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("build", buildOptions = buildOptions.copy(logLevel = LogLevel.DEBUG)) { checkGenerated(kaptGeneratedToPath, *annotatedElements) checkNotGenerated(kaptGeneratedToPath, "notAnnotatedFun") @@ -123,7 +136,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("Adding new annotated element") @GradleTest fun testAddAnnotatedElement(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("assemble") val utilKt = javaSourcesDir().resolve("baz/util.kt") @@ -148,7 +161,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("Adding new annotation triggers kapt run") @GradleTest fun testAddAnnotation(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("assemble") val utilKt = javaSourcesDir().resolve("baz/util.kt") @@ -167,7 +180,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("Kapt run is incremental after source file was removed") @GradleTest fun testRemoveSourceFile(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { val kapt3IncDataPath = "build/tmp/kapt3/incrementalData/main" val kapt3StubsPath = "build/tmp/kapt3/stubs/main" @@ -214,7 +227,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("Incremental kapt run is correct after removing all Kotlin sources") @GradleTest fun testRemoveAllKotlinSources(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("assemble") { assertFileInProjectExists("$KAPT3_STUBS_PATH/bar/UseBKt.java") } @@ -259,7 +272,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("On all annotations remove kapt and compile runs incremenatally") @GradleTest fun testRemoveAnnotations(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("assemble") val bKt = javaSourcesDir().resolve("bar/B.kt") @@ -294,7 +307,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("Changing annotated property type is handled correctly") @GradleTest fun testChangeAnnotatedPropertyType(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("assemble") val bKt = javaSourcesDir().resolve("bar/B.kt") @@ -315,7 +328,7 @@ open class KaptIncrementalIT : KGPBaseTest() { @DisplayName("Change in inline delegate is handled correctly") @GradleTest fun testChangeInlineDelegate(gradleVersion: GradleVersion) { - project(PROJECT_NAME, gradleVersion) { + kaptProject(gradleVersion) { build("assemble") val file = javaSourcesDir().resolve("delegate/Usage.kt") diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt index b67c254cf4b..66edec8c525 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt @@ -5,299 +5,313 @@ package org.jetbrains.kotlin.gradle +import org.gradle.api.JavaVersion +import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.incapt.IncrementalAggregatingReferencingClasspathProcessor import org.jetbrains.kotlin.gradle.incapt.IncrementalBinaryIsolatingProcessor import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessor import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessorReferencingClasspath -import org.jetbrains.kotlin.gradle.testbase.TestProject -import org.jetbrains.kotlin.gradle.util.AGPVersion -import org.jetbrains.kotlin.gradle.util.modify -import org.junit.Assert.assertEquals -import org.junit.Assert.assertTrue -import org.junit.Assume -import org.junit.Test +import org.jetbrains.kotlin.gradle.testbase.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.condition.DisabledOnOs +import org.junit.jupiter.api.condition.OS import test.kt33617.MyClass import java.io.File import java.nio.file.Path import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream -import kotlin.io.path.ExperimentalPathApi -import kotlin.io.path.readText -import kotlin.io.path.writeText +import kotlin.io.path.* +import kotlin.test.assertEquals +@DisplayName("Kapt incremental tests with isolating apt") class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() { - override fun getProject() = - Project( - "kaptIncrementalCompilationProject", - GradleVersionRequired.None - ).apply { + override val defaultBuildOptions = super.defaultBuildOptions.copy( + incremental = true, + kaptOptions = super.defaultBuildOptions.kaptOptions!!.copy( + verbose = true, + useWorkers = true, + incrementalKapt = true, + includeCompileClasspath = false + ) + ) + + override fun KGPBaseTest.kaptProject( + gradleVersion: GradleVersion, + buildOptions: BuildOptions, + buildJdk: File?, + test: TestProject.() -> Unit + ): TestProject { + return project(PROJECT_NAME, gradleVersion, buildOptions = buildOptions, buildJdk = buildJdk) { setupIncrementalAptProject("ISOLATING") - } - override fun defaultBuildOptions(): BuildOptions = - super.defaultBuildOptions().copy( - incremental = true, - kaptOptions = KaptOptions( - verbose = true, - useWorkers = true, - incrementalKapt = true, - includeCompileClasspath = false - ) - ) - - @Test - fun testIncrementalChanges() { - val project = getProject() - - project.build("clean", "build") { - assertSuccessful() - } - - project.projectFile("useB.kt").modify { current -> "$current\nfun otherFunction() {}" } - project.build("build") { - assertSuccessful() - - assertEquals( - setOf( - fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/UseBKt.java").canonicalPath, - fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath - ), getProcessedSources(output) - ) - } - - project.projectFile("B.kt").modify { current -> - val lastBrace = current.lastIndexOf("}") - current.substring(0, lastBrace) + "fun anotherFun() {}\n }" - } - project.build("build") { - assertSuccessful() - assertEquals( - setOf( - fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/B.java").canonicalPath, - fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/UseBKt.java").canonicalPath, - fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath - ), - getProcessedSources(output) - ) + test(this) } } - @Test - fun testChangingAnnotationProcessorClasspath() { - val project = getProject() + @DisplayName("Incremental changes") + @GradleTest + fun testIncrementalChanges(gradleVersion: GradleVersion) { + kaptProject(gradleVersion) { + build("clean", "assemble") - project.build("clean", "build") { - assertSuccessful() - } - - project.gradleBuildScript().appendText( - """ - - dependencies { - kapt 'com.google.guava:guava:12.0' + javaSourcesDir().resolve("bar/useB.kt").modify { current -> "$current\nfun otherFunction() {}" } + build("assemble") { + assertEquals( + setOf( + "$KAPT3_STUBS_PATH/bar/UseBKt.java", + "$KAPT3_STUBS_PATH/error/NonExistentClass.java" + ) + .map { projectPath.resolve(it).toRealPath().toString() } + .toSet(), + getProcessedSources(output) + ) + } + + javaSourcesDir().resolve("bar/B.kt").modify { current -> + val lastBrace = current.lastIndexOf("}") + current.substring(0, lastBrace) + "fun anotherFun() {}\n }" + } + build("assemble") { + assertEquals( + setOf( + "$KAPT3_STUBS_PATH/bar/B.java", + "$KAPT3_STUBS_PATH/bar/UseBKt.java", + "$KAPT3_STUBS_PATH/error/NonExistentClass.java", + ) + .map { projectPath.resolve(it).toRealPath().toString() } + .toSet(), + getProcessedSources(output) + ) } - """.trimIndent() - ) - project.build("build") { - assertSuccessful() - assertContains("The input changes require a full rebuild for incremental task ':kaptKotlin'.") } } - @Test - fun testUnchangedAnnotationProcessorClasspathButContentChanged() { - val project = getProject() - val processorJar = project.projectDir.resolve("processor.jar").also { - ZipOutputStream(it.outputStream()).use { - // create an empty jar - } - } - project.gradleBuildScript().appendText( - """ - - dependencies { - kapt files("processor.jar") - } - """.trimIndent() - ) + @DisplayName("On changing annotation processor classpath") + @GradleTest + fun testChangingAnnotationProcessorClasspath(gradleVersion: GradleVersion) { + kaptProject(gradleVersion) { + build("clean", "assemble") - project.build("clean", "build") { - assertSuccessful() - } + buildGradle.append( + """ + + dependencies { + kapt 'com.google.guava:guava:12.0' + } + """.trimIndent() + ) - ZipOutputStream(processorJar.outputStream()).use { - it.putNextEntry(ZipEntry("resource.txt")) - it.closeEntry() - } - project.build("build") { - assertSuccessful() - assertContains("The input changes require a full rebuild for incremental task ':kaptKotlin'.") + build("assemble") { + assertOutputContains("The input changes require a full rebuild for incremental task ':kaptKotlin'.") + } } } - @Test - fun testNonIncrementalWithUnrecognizedInputs() { - val project = getProject() - - val additionalInputs = project.projectDir.resolve("additionalInputs").also { it.mkdirs() } - project.gradleBuildScript().appendText( - """ - - tasks.whenTaskAdded { - if (it.name == "kaptKotlin") { - it.getInputs().files("${additionalInputs.invariantSeparatorsPath}") + @DisplayName("On unchanged annotation processor classpath, but processor itself is updated") + @GradleTest + fun testUnchangedAnnotationProcessorClasspathButContentChanged(gradleVersion: GradleVersion) { + kaptProject(gradleVersion) { + val processorJar = projectPath.resolve("processor.jar").also { + ZipOutputStream(it.outputStream()).use { + // create an empty jar } } - """.trimIndent() - ) - project.build("clean", "build") { - assertSuccessful() - } - - additionalInputs.resolve("layout.xml").createNewFile() - project.build("build") { - assertSuccessful() - assertContains("Incremental annotation processing (apt mode): false") - } - } - - /** Regression test for https://youtrack.jetbrains.com/issue/KT-33617. */ - @Test - fun testSourcesInCompileClasspathJars() { - val javaHome = File(System.getProperty("jdk9Home")!!) - Assume.assumeTrue("JDK 9 isn't available", javaHome.isDirectory) - val options = defaultBuildOptions().copy(javaHome = javaHome) - - val project = getProject() - // create jar with .class and .java file for the same type - ZipOutputStream(project.projectDir.resolve("lib-with-sources.jar").outputStream()).use { - it.putNextEntry(ZipEntry("test/kt33617/MyClass.class")) - MyClass::class.java.classLoader.getResourceAsStream("test/kt33617/MyClass.class").use { input -> - it.write(input!!.readBytes()) - } - it.closeEntry() - - it.putNextEntry(ZipEntry("test/kt33617/MyClass.java")) - it.write( + buildGradle.append( """ - package test.kt33617; - public class MyClass {} - """.trimIndent().toByteArray(Charsets.UTF_8) + + dependencies { + kapt files("processor.jar") + } + """.trimIndent() ) - it.closeEntry() - } - project.gradleBuildScript().appendText( - """ - - dependencies { - implementation files('lib-with-sources.jar') - } - """.trimIndent() - ) - project.projectFile("useB.kt").modify { current -> "$current\nfun otherFunction(param: test.kt33617.MyClass) {}" } - project.build("clean", "kaptKotlin", options = options) { - assertSuccessful() + build("clean", "assemble") + + ZipOutputStream(processorJar.outputStream()).use { + it.putNextEntry(ZipEntry("resource.txt")) + it.closeEntry() + } + + build("assemble") { + assertOutputContains("The input changes require a full rebuild for incremental task ':kaptKotlin'.") + } } } - /** Regression test for https://youtrack.jetbrains.com/issue/KT-42182. */ - @Test - fun testGeneratedSourcesImpactedByClasspathChanges() { - val project = Project( - "kaptIncrementalCompilationProject", - GradleVersionRequired.None - ).apply { - setupIncrementalAptProject("ISOLATING", procClass = IncrementalProcessorReferencingClasspath::class.java) - } - project.gradleSettingsScript().appendText("\ninclude ':', ':lib'") - val classpathTypeSource = project.projectDir.resolve("lib").run { - mkdirs() - resolve("build.gradle").writeText( + @DisplayName("Runs non-incrementally on unrecognized inputs") + @GradleTest + fun testNonIncrementalWithUnrecognizedInputs(gradleVersion: GradleVersion) { + kaptProject(gradleVersion) { + val additionalInputs = projectPath.resolve("additionalInputs").also { it.createDirectories() } + buildGradle.appendText( """ - plugins { - id 'java' + + tasks.whenTaskAdded { + if (it.name == "kaptKotlin") { + it.getInputs().files("${additionalInputs.invariantSeparatorsPathString}") + } + } + """.trimIndent() + ) + + build("clean", "assemble") + + additionalInputs.resolve("layout.xml").createFile() + build("assemble") { + assertOutputContains("Incremental annotation processing (apt mode): false") + } + } + } + + @DisplayName("KT-33617: sources in compile classpath jars") + @JdkVersions(versions = [JavaVersion.VERSION_1_9]) + @GradleWithJdkTest + fun testSourcesInCompileClasspathJars(gradleVersion: GradleVersion, jdk: JdkVersions.ProvidedJdk) { + kaptProject(gradleVersion, buildJdk = jdk.location) { + // create jar with .class and .java file for the same type + ZipOutputStream(projectPath.resolve("lib-with-sources.jar").outputStream()).use { + it.putNextEntry(ZipEntry("test/kt33617/MyClass.class")) + MyClass::class.java.classLoader.getResourceAsStream("test/kt33617/MyClass.class").use { input -> + it.write(input!!.readBytes()) + } + it.closeEntry() + + it.putNextEntry(ZipEntry("test/kt33617/MyClass.java")) + it.write( + """ + package test.kt33617; + public class MyClass {} + """.trimIndent().toByteArray(Charsets.UTF_8) + ) + it.closeEntry() + } + + buildGradle.append( + """ + + dependencies { + implementation files('lib-with-sources.jar') + } + """.trimIndent() + ) + javaSourcesDir().resolve("bar/useB.kt").modify { current -> + "$current\nfun otherFunction(param: test.kt33617.MyClass) {}" + } + + build("clean", "kaptKotlin") + } + } + + @DisplayName("KT-42182: generated sources are updated on classpath changes") + @GradleTest + fun testGeneratedSourcesImpactedByClasspathChanges(gradleVersion: GradleVersion) { + project(PROJECT_NAME, gradleVersion) { + setupIncrementalAptProject( + "ISOLATING", + procClass = IncrementalProcessorReferencingClasspath::class.java + ) + + settingsGradle.append("\ninclude ':', ':lib'") + + val classpathTypeSource = subProject("lib").run { + projectPath.createDirectory() + buildGradle.writeText( + """ + plugins { + id 'java' + } + """.trimIndent() + ) + val source = javaSourcesDir() + .resolve( + IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE + .replace(".", "/") + ".java" + ) + source.parent.createDirectories() + + source.writeText( + """ + package ${IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.substringBeforeLast(".")}; + public class ${IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.substringAfterLast(".")} {} + """.trimIndent() + ) + return@run source + } + + buildGradle.appendText( + """ + + dependencies { + implementation project(':lib') } """.trimIndent() ) - val source = resolve("src/main/java/" + IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.replace(".", "/") + ".java") - source.parentFile.mkdirs() - source.writeText( - """ - package ${IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.substringBeforeLast(".")}; - public class ${IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.substringAfterLast(".")} {} - """.trimIndent() + val annotatedKotlinStubs = listOf( + "$KAPT3_STUBS_PATH/foo/A.java", + "$KAPT3_STUBS_PATH/bar/B.java", + "$KAPT3_STUBS_PATH/bar/UseBKt.java", + "$KAPT3_STUBS_PATH/baz/UtilKt.java", + "$KAPT3_STUBS_PATH/baz/UtilKt.java", + "$KAPT3_STUBS_PATH/error/NonExistentClass.java" ) - return@run source - } - project.gradleBuildScript().appendText( - """ - - dependencies { - implementation project(':lib') + + val allKotlinStubs = annotatedKotlinStubs + listOf( + "$KAPT3_STUBS_PATH/delegate/Delegate.java", + "$KAPT3_STUBS_PATH/delegate/Usage.java" + ) + + build("clean", "assemble") { + assertEquals( + allKotlinStubs + .plus("src/main/java/foo/JavaClass.java") + .map { projectPath.resolve(it).toRealPath().toString() }.toSet(), + getProcessedSources(output) + ) } - """.trimIndent() - ) - val annotatedKotlinStubs = setOf( - project.projectDir.resolve("build/tmp/kapt3/stubs/main/foo/A.java").canonicalPath, - project.projectDir.resolve("build/tmp/kapt3/stubs/main/bar/B.java").canonicalPath, - project.projectDir.resolve("build/tmp/kapt3/stubs/main/bar/UseBKt.java").canonicalPath, - project.projectDir.resolve("build/tmp/kapt3/stubs/main/baz/UtilKt.java").canonicalPath, - project.projectDir.resolve("build/tmp/kapt3/stubs/main/baz/UtilKt.java").canonicalPath, - project.projectDir.resolve("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath - ) - - val allKotlinStubs = annotatedKotlinStubs + setOf( - project.projectDir.resolve("build/tmp/kapt3/stubs/main/delegate/Delegate.java").canonicalPath, - project.projectDir.resolve("build/tmp/kapt3/stubs/main/delegate/Usage.java").canonicalPath - ) - - project.build("clean", "build") { - assertSuccessful() - assertEquals(allKotlinStubs + fileInWorkingDir("src/main/java/foo/JavaClass.java").canonicalPath, getProcessedSources(output)) - } - - // change type that all generated sources reference - classpathTypeSource.writeText(classpathTypeSource.readText().replace("}", "int i = 10;\n}")) - project.build("build") { - assertSuccessful() - assertEquals(annotatedKotlinStubs, getProcessedSources(output)) + // change type that all generated sources reference + classpathTypeSource.writeText( + classpathTypeSource.readText().replace("}", "int i = 10;\n}") + ) + build("assemble") { + assertEquals( + annotatedKotlinStubs.map { projectPath.resolve(it).toRealPath().toString() }.toSet(), + getProcessedSources(output) + ) + } } } - /** Regression test for KT-34340. */ - @Test - fun testIsolatingWithOriginsInClasspath() { - //https://youtrack.jetbrains.com/issue/KTI-405 - if (System.getProperty("os.name")?.toLowerCase()?.contains("windows") == true) return + @DisplayName("KT-34340: origins in classpath") + @GradleTest + @DisabledOnOs(OS.WINDOWS, disabledReason = "https://youtrack.jetbrains.com/issue/KTI-405") + fun testIsolatingWithOriginsInClasspath(gradleVersion: GradleVersion) { + project( + "kaptIncrementalWithParceler", + gradleVersion, + buildOptions = defaultBuildOptions.copy(androidVersion = TestVersions.AGP.AGP_42) + ) { + build("clean", ":mylibrary:assembleDebug") - val project = Project( - projectName = "kaptIncrementalWithParceler" - ).apply { - setupWorkingDir() - } - val options = defaultBuildOptions().copy(androidGradlePluginVersion = AGPVersion.v4_2_0) - project.build("clean", ":mylibrary:assembleDebug", options = options) { - assertSuccessful() - } + subProject("baseLibrary") + .javaSourcesDir() + .resolve("com/example/lib2/basemodule/BaseClassParcel.java") + .modify { current -> + current.replace("protected FieldClassParcel", "private FieldClassParcel") + } - project.projectFile("BaseClassParcel.java").modify { current -> - current.replace("protected FieldClassParcel", "private FieldClassParcel") - } - - project.build(":mylibrary:assembleDebug", options = options) { - assertSuccessful() - assertEquals( - setOf( - fileInWorkingDir("mylibrary/src/main/java/com/example/lib/ExampleParcel.java").canonicalPath, - fileInWorkingDir("baseLibrary/src/main/java/com/example/lib2/basemodule/BaseClassParcel.java").canonicalPath, - ), - getProcessedSources(output) - ) + build(":mylibrary:assembleDebug") { + assertEquals( + listOf( + "mylibrary/src/main/java/com/example/lib/ExampleParcel.java", + "baseLibrary/src/main/java/com/example/lib2/basemodule/BaseClassParcel.java", + ).map { projectPath.resolve(it).toRealPath().toString() }.toSet(), + getProcessedSources(output) + ) + } } } @@ -305,54 +319,56 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() { * Make sure that changes to classpath can cause types to be reprocessed (i.e types in generated .class files that contain annotations * claimed by annotation processors). */ - @Test - fun testClasspathChangesCauseTypesToBeReprocessed() { - val project = Project( - "kaptIncrementalCompilationProject", - GradleVersionRequired.None - ).apply { + @DisplayName("Changed types causing incremental compilation") + @GradleTest + fun testClasspathChangesCauseTypesToBeReprocessed(gradleVersion: GradleVersion) { + project(PROJECT_NAME, gradleVersion) { setupIncrementalAptProject( Pair("ISOLATING", IncrementalBinaryIsolatingProcessor::class.java), Pair("AGGREGATING", IncrementalAggregatingReferencingClasspathProcessor::class.java), ) - } - project.gradleSettingsScript().appendText("\ninclude ':', ':lib'\n") - val classpathTypeSource = project.projectDir.resolve("lib").run { - mkdirs() - resolve("build.gradle").writeText( + + settingsGradle.append("\ninclude ':', ':lib'\n") + val classpathTypeSource = subProject("lib").run { + projectPath.createDirectories() + + buildGradle.writeText( + """ + plugins { + id 'java' + } + + """.trimIndent() + ) + val source = javaSourcesDir() + .resolve( + IncrementalAggregatingReferencingClasspathProcessor.CLASSPATH_TYPE + .replace(".", "/") + ".java" + ) + source.parent.createDirectories() + + source.writeText( + """ + package ${IncrementalAggregatingReferencingClasspathProcessor.CLASSPATH_TYPE.substringBeforeLast(".")}; + public class ${IncrementalAggregatingReferencingClasspathProcessor.CLASSPATH_TYPE.substringAfterLast(".")} {} + """.trimIndent() + ) + return@run source + } + + buildGradle.append( """ - plugins { - id 'java' + + dependencies { + implementation project(':lib') } - """.trimIndent() ) - val source = - resolve("src/main/java/" + IncrementalAggregatingReferencingClasspathProcessor.CLASSPATH_TYPE.replace(".", "/") + ".java") - source.parentFile.mkdirs() - source.writeText( - """ - package ${IncrementalAggregatingReferencingClasspathProcessor.CLASSPATH_TYPE.substringBeforeLast(".")}; - public class ${IncrementalAggregatingReferencingClasspathProcessor.CLASSPATH_TYPE.substringAfterLast(".")} {} - """.trimIndent() - ) - return@run source - } - project.gradleBuildScript().appendText( - """ - - dependencies { - implementation project(':lib') - } - """.trimIndent() - ) - - // Remove all sources, and add only 1 source file - project.projectDir.resolve("src").let { - it.deleteRecursively() - with(it.resolve("main/java/example/A.kt")) { - parentFile.mkdirs() + // Remove all sources, and add only 1 source file + javaSourcesDir().deleteRecursively() + with(javaSourcesDir().resolve("example/A.kt")) { + parent.createDirectories() writeText( """ package example @@ -360,37 +376,31 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() { annotation class ExampleAnnotation @ExampleAnnotation class A - """.trimIndent() + """.trimIndent() ) } - } - val allKotlinStubs = setOf( - project.projectDir.resolve("build/tmp/kapt3/stubs/main/example/ExampleAnnotation.java").canonicalPath, - project.projectDir.resolve("build/tmp/kapt3/stubs/main/example/A.java").canonicalPath, - project.projectDir.resolve("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath - ) - - project.build("clean", "build") { - assertSuccessful() - assertEquals(allKotlinStubs, getProcessedSources(output)) - - assertTrue( - "Aggregating sources exists", - fileInWorkingDir("build/generated/source/kapt/main/com/example/AggGenerated.java").exists() + val allKotlinStubs = setOf( + "build/tmp/kapt3/stubs/main/example/ExampleAnnotation.java", + "build/tmp/kapt3/stubs/main/example/A.java", + "build/tmp/kapt3/stubs/main/error/NonExistentClass.java" ) - } - // change type that the aggregated generated source reference - classpathTypeSource.writeText(classpathTypeSource.readText().replace("}", "int i = 10;\n}")) - project.build("build") { - assertSuccessful() - assertEquals(emptySet(), getProcessedSources(output)) - assertEquals(setOf("example.AGenerated"), getProcessedTypes(output)) - assertTrue( - "Aggregating sources exists", - fileInWorkingDir("build/generated/source/kapt/main/com/example/AggGenerated.java").exists() - ) + build("clean", "assemble") { + assertEquals( + allKotlinStubs.map { projectPath.resolve(it).toRealPath().toString() }.toSet(), + getProcessedSources(output) + ) + assertFileInProjectExists("build/generated/source/kapt/main/com/example/AggGenerated.java") + } + + // change type that the aggregated generated source reference + classpathTypeSource.writeText(classpathTypeSource.readText().replace("}", "int i = 10;\n}")) + build("assemble") { + assertEquals(emptySet(), getProcessedSources(output)) + assertEquals(setOf("example.AGenerated"), getProcessedTypes(output)) + assertFileInProjectExists("build/generated/source/kapt/main/com/example/AggGenerated.java") + } } } } @@ -399,7 +409,7 @@ private const val patternApt = "Processing java sources with annotation processo fun getProcessedSources(output: String): Set { return output.lines().filter { it.contains(patternApt) }.flatMapTo(HashSet()) { logging -> val indexOf = logging.indexOf(patternApt) + patternApt.length - logging.drop(indexOf).split(",").map { it.trim() }.filter { !it.isEmpty() }.toSet() + logging.drop(indexOf).split(",").map { it.trim() }.filter { it.isNotEmpty() }.toSet() } } @@ -407,59 +417,10 @@ private const val patternClassesApt = "Processing types with annotation processo fun getProcessedTypes(output: String): Set { return output.lines().filter { it.contains(patternClassesApt) }.flatMapTo(HashSet()) { logging -> val indexOf = logging.indexOf(patternClassesApt) + patternClassesApt.length - logging.drop(indexOf).split(",").map { it.trim() }.filter { !it.isEmpty() }.toSet() + logging.drop(indexOf).split(",").map { it.trim() }.filter { it.isNotEmpty() }.toSet() } } -fun BaseGradleIT.Project.setupIncrementalAptProject( - procType: String, - buildFile: File = projectDir.resolve("build.gradle"), - procClass: Class<*> = IncrementalProcessor::class.java -) { - setupIncrementalAptProject(procType to procClass, buildFile = buildFile) -} - -fun BaseGradleIT.Project.setupIncrementalAptProject( - vararg processors: Pair>, - buildFile: File = projectDir.resolve("build.gradle") -) { - setupWorkingDir() - val content = buildFile.readText() - val processorPath = generateProcessor(*processors) - - val updatedContent = content.replace( - Regex("^\\s*kapt\\s\"org\\.jetbrains\\.kotlin.*$", RegexOption.MULTILINE), - " kapt files(\"${processorPath.invariantSeparatorsPath}\")" - ) - buildFile.writeText(updatedContent) -} - -fun BaseGradleIT.Project.generateProcessor(vararg processors: Pair>): File { - val processorPath = projectDir.resolve("incrementalProcessor.jar") - - ZipOutputStream(processorPath.outputStream()).use { - for ((_, procClass) in processors) { - val path = procClass.name.replace(".", "/") + ".class" - procClass.classLoader.getResourceAsStream(path).use { inputStream -> - it.putNextEntry(ZipEntry(path)) - it.write(inputStream.readBytes()) - it.closeEntry() - } - } - it.putNextEntry(ZipEntry("META-INF/gradle/incremental.annotation.processors")) - it.write(processors.joinToString("\n") { (procType, procClass) -> - "${procClass.name},$procType" - }.toByteArray()) - it.closeEntry() - it.putNextEntry(ZipEntry("META-INF/services/javax.annotation.processing.Processor")) - it.write(processors.joinToString("\n") { (_, procClass) -> - procClass.name - }.toByteArray()) - it.closeEntry() - } - return processorPath -} - fun TestProject.setupIncrementalAptProject( procType: String, buildFile: Path = buildGradle, @@ -493,7 +454,7 @@ fun TestProject.generateProcessor( val path = procClass.name.replace(".", "/") + ".class" procClass.classLoader.getResourceAsStream(path).use { inputStream -> it.putNextEntry(ZipEntry(path)) - it.write(inputStream.readBytes()) + it.write(inputStream!!.readBytes()) it.closeEntry() } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/baseLibrary/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/baseLibrary/build.gradle index de1826342f2..23f355b3d64 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/baseLibrary/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/baseLibrary/build.gradle @@ -1,7 +1,7 @@ plugins { id 'com.android.library' - id 'kotlin-android' - id 'kotlin-kapt' + id 'org.jetbrains.kotlin.android' + id 'org.jetbrains.kotlin.kapt' } android { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/build.gradle index 4bfb97464b1..54ed3e9e7ec 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/build.gradle @@ -1,22 +1,7 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - repositories { - mavenLocal() - maven { url 'https://maven.google.com' } - mavenCentral() - maven { url = uri("https://jcenter.bintray.com/") } - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "com.android.tools.build:gradle:$android_tools_version" - } -} - allprojects { repositories { mavenLocal() - maven { url 'https://maven.google.com' } + google() mavenCentral() - maven { url = uri("https://jcenter.bintray.com/") } } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/mylibrary/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/mylibrary/build.gradle index af869d82f01..2eb4b67df7e 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/mylibrary/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kaptIncrementalWithParceler/mylibrary/build.gradle @@ -1,7 +1,7 @@ plugins { id 'com.android.library' - id 'kotlin-android' - id 'kotlin-kapt' + id 'org.jetbrains.kotlin.android' + id 'org.jetbrains.kotlin.kapt' } android {