diff options
Diffstat (limited to 'integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt')
-rw-r--r-- | integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt new file mode 100644 index 00000000..7c9c2dcd --- /dev/null +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/KMPImplementedIT.kt @@ -0,0 +1,369 @@ +package com.google.devtools.ksp.test + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.Assert +import org.junit.Assume +import org.junit.Rule +import org.junit.Test +import java.io.File +import java.util.jar.* + +class KMPImplementedIT { + @Rule + @JvmField + val project: TemporaryTestProject = TemporaryTestProject("kmp") + + private fun verify(jarName: String, contents: List<String>) { + val artifact = File(project.root, jarName) + Assert.assertTrue(artifact.exists()) + + JarFile(artifact).use { jarFile -> + contents.forEach { + Assert.assertTrue(jarFile.getEntry(it).size > 0) + } + } + } + + private fun verifyKexe(path: String) { + val artifact = File(project.root, path) + Assert.assertTrue(artifact.exists()) + Assert.assertTrue(artifact.readBytes().size > 0) + } + + private fun checkExecutionOptimizations(log: String) { + Assert.assertFalse( + "Execution optimizations have been disabled", + log.contains("Execution optimizations have been disabled") + ) + } + + @Test + fun testJvm() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-jvm:build" + ).build().let { + Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-jvm:build")?.outcome) + verify( + "workload-jvm/build/libs/workload-jvm-jvm-1.0-SNAPSHOT.jar", + listOf( + "com/example/Foo.class" + ) + ) + Assert.assertFalse(it.output.contains("kotlin scripting plugin:")) + Assert.assertTrue(it.output.contains("w: [ksp] platforms: [JVM")) + Assert.assertTrue(it.output.contains("w: [ksp] List has superTypes: true")) + checkExecutionOptimizations(it.output) + } + } + + @Test + fun testJvmErrorLog() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + File(project.root, "workload-jvm/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"process\") }\n") + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-jvm:build" + ).buildAndFail().let { + val errors = it.output.lines().filter { it.startsWith("e: [ksp]") } + Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in process", errors.first()) + } + project.restore("workload-jvm/build.gradle.kts") + } + + @Test + fun testJs() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-js:build" + ).build().let { + Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-js:build")?.outcome) + verify( + "workload-js/build/libs/workload-js-jslegacy-1.0-SNAPSHOT.jar", + listOf( + "playground-workload-js-js-legacy.js" + ) + ) + verify( + "workload-js/build/libs/workload-js-jsir-1.0-SNAPSHOT.klib", + listOf( + "default/ir/types.knt" + ) + ) + Assert.assertFalse(it.output.contains("kotlin scripting plugin:")) + Assert.assertTrue(it.output.contains("w: [ksp] platforms: [JS")) + Assert.assertTrue(it.output.contains("w: [ksp] List has superTypes: true")) + checkExecutionOptimizations(it.output) + } + } + + @Test + fun testJsErrorLog() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + File(project.root, "workload-js/build.gradle.kts").appendText("\nksp { arg(\"exception\", \"process\") }\n") + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-js:build" + ).buildAndFail().let { + val errors = it.output.lines().filter { it.startsWith("e: [ksp]") } + Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in process", errors.first()) + } + project.restore("workload-js/build.gradle.kts") + } + + @Test + fun testJsFailWarning() { + File(project.root, "workload-js/build.gradle.kts") + .appendText("\nksp {\n allWarningsAsErrors = true\n}\n") + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-js:build" + ).buildAndFail() + } + + @Test + fun testAndroidNative() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-androidNative:build" + ).build().let { + Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-androidNative:build")?.outcome) + verifyKexe( + "workload-androidNative/build/bin/androidNativeX64/debugExecutable/workload-androidNative.kexe" + ) + verifyKexe( + "workload-androidNative/build/bin/androidNativeX64/releaseExecutable/workload-androidNative.kexe" + ) + verifyKexe( + "workload-androidNative/build/bin/androidNativeArm64/debugExecutable/workload-androidNative.kexe" + ) + verifyKexe( + "workload-androidNative/build/bin/androidNativeArm64/releaseExecutable/workload-androidNative.kexe" + ) + Assert.assertFalse(it.output.contains("kotlin scripting plugin:")) + Assert.assertTrue(it.output.contains("w: [ksp] platforms: [Native")) + checkExecutionOptimizations(it.output) + } + } + + @Test + fun testLinuxX64() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + val genDir = File(project.root, "workload-linuxX64/build/generated/ksp/linuxX64/linuxX64Main/kotlin") + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-linuxX64:build" + ).build().let { + Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-linuxX64:build")?.outcome) + Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-linuxX64:kspTestKotlinLinuxX64")?.outcome) + verifyKexe("workload-linuxX64/build/bin/linuxX64/debugExecutable/workload-linuxX64.kexe") + verifyKexe("workload-linuxX64/build/bin/linuxX64/releaseExecutable/workload-linuxX64.kexe") + + // TODO: Enable after CI's Xcode version catches up. + // Assert.assertTrue( + // result.task(":workload-linuxX64:kspKotlinIosArm64")?.outcome == TaskOutcome.SUCCESS || + // result.task(":workload-linuxX64:kspKotlinIosArm64")?.outcome == TaskOutcome.SKIPPED + // ) + // Assert.assertTrue( + // result.task(":workload-linuxX64:kspKotlinMacosX64")?.outcome == TaskOutcome.SUCCESS || + // result.task(":workload-linuxX64:kspKotlinMacosX64")?.outcome == TaskOutcome.SKIPPED + // ) + Assert.assertTrue( + it.task(":workload-linuxX64:kspKotlinMingwX64")?.outcome == TaskOutcome.SUCCESS || + it.task(":workload-linuxX64:kspKotlinMingwX64")?.outcome == TaskOutcome.SKIPPED + ) + Assert.assertFalse(it.output.contains("kotlin scripting plugin:")) + Assert.assertTrue(it.output.contains("w: [ksp] platforms: [Native")) + Assert.assertTrue(it.output.contains("w: [ksp] List has superTypes: true")) + Assert.assertTrue(File(genDir, "Main_dot_kt.kt").exists()) + Assert.assertTrue(File(genDir, "ToBeRemoved_dot_kt.kt").exists()) + checkExecutionOptimizations(it.output) + } + + File(project.root, "workload-linuxX64/src/linuxX64Main/kotlin/ToBeRemoved.kt").delete() + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + ":workload-linuxX64:build" + ).build().let { + Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-linuxX64:build")?.outcome) + Assert.assertEquals(TaskOutcome.SUCCESS, it.task(":workload-linuxX64:kspTestKotlinLinuxX64")?.outcome) + verifyKexe("workload-linuxX64/build/bin/linuxX64/debugExecutable/workload-linuxX64.kexe") + verifyKexe("workload-linuxX64/build/bin/linuxX64/releaseExecutable/workload-linuxX64.kexe") + Assert.assertTrue(File(genDir, "Main_dot_kt.kt").exists()) + Assert.assertFalse(File(genDir, "ToBeRemoved_dot_kt.kt").exists()) + checkExecutionOptimizations(it.output) + } + } + + @Test + fun testNonEmbeddableArtifact() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "-Pkotlin.native.useEmbeddableCompilerJar=false", + ":workload-linuxX64:kspTestKotlinLinuxX64" + ).build() + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "-Pkotlin.native.useEmbeddableCompilerJar=true", + ":workload-linuxX64:kspTestKotlinLinuxX64" + ).build() + + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + ":workload-linuxX64:kspTestKotlinLinuxX64" + ).build() + } + + @Test + fun testLinuxX64ErrorLog() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + File(project.root, "workload-linuxX64/build.gradle.kts") + .appendText("\nksp { arg(\"exception\", \"process\") }\n") + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + ":workload-linuxX64:build" + ).buildAndFail().let { + val errors = it.output.lines().filter { it.startsWith("e: [ksp]") } + Assert.assertEquals("e: [ksp] java.lang.Exception: Test Exception in process", errors.first()) + } + project.restore("workload-js/build.gradle.kts") + } + + private fun verifyAll(result: BuildResult) { + Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:build")?.outcome) + Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspTestKotlinLinuxX64")?.outcome) + + verify( + "workload/build/libs/workload-jvm-1.0-SNAPSHOT.jar", + listOf( + "com/example/Foo.class" + ) + ) + + verify( + "workload/build/libs/workload-jslegacy-1.0-SNAPSHOT.jar", + listOf( + "playground-workload-js-legacy.js" + ) + ) + + verify( + "workload/build/libs/workload-jsir-1.0-SNAPSHOT.klib", + listOf( + "default/ir/types.knt" + ) + ) + + verifyKexe("workload/build/bin/linuxX64/debugExecutable/workload.kexe") + verifyKexe("workload/build/bin/linuxX64/releaseExecutable/workload.kexe") + verifyKexe("workload/build/bin/androidNativeX64/debugExecutable/workload.kexe") + verifyKexe("workload/build/bin/androidNativeX64/releaseExecutable/workload.kexe") + verifyKexe("workload/build/bin/androidNativeArm64/debugExecutable/workload.kexe") + verifyKexe("workload/build/bin/androidNativeArm64/releaseExecutable/workload.kexe") + + // TODO: Enable after CI's Xcode version catches up. + // Assert.assertTrue( + // result.task(":workload:kspKotlinIosArm64")?.outcome == TaskOutcome.SUCCESS || + // result.task(":workload:kspKotlinIosArm64")?.outcome == TaskOutcome.SKIPPED + // ) + // Assert.assertTrue( + // result.task(":workload:kspKotlinMacosX64")?.outcome == TaskOutcome.SUCCESS || + // result.task(":workload:kspKotlinMacosX64")?.outcome == TaskOutcome.SKIPPED + // ) + Assert.assertTrue( + result.task(":workload:kspKotlinMingwX64")?.outcome == TaskOutcome.SUCCESS || + result.task(":workload:kspKotlinMingwX64")?.outcome == TaskOutcome.SKIPPED + ) + + Assert.assertFalse(result.output.contains("kotlin scripting plugin:")) + Assert.assertTrue(result.output.contains("w: [ksp] platforms: [JVM")) + Assert.assertTrue(result.output.contains("w: [ksp] platforms: [JS")) + Assert.assertTrue(result.output.contains("w: [ksp] platforms: [Native")) + } + + @Test + fun testMainConfiguration() { + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root) + + val buildScript = File(project.root, "workload/build.gradle.kts") + val lines = buildScript.readLines().takeWhile { + it.trimEnd() != "dependencies {" + } + buildScript.writeText(lines.joinToString(System.lineSeparator())) + buildScript.appendText(System.lineSeparator()) + buildScript.appendText("dependencies {") + buildScript.appendText(System.lineSeparator()) + buildScript.appendText(" add(\"ksp\", project(\":test-processor\"))") + buildScript.appendText(System.lineSeparator()) + buildScript.appendText("}") + + val messages = listOf( + "The 'ksp' configuration is deprecated in Kotlin Multiplatform projects. ", + "Please use target-specific configurations like 'kspJvm' instead." + ) + + // KotlinNative doesn't support configuration cache yet. + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + "build", + "-Pksp.allow.all.target.configuration=false" + ).buildAndFail().apply { + Assert.assertTrue( + messages.all { + output.contains(it) + } + ) + checkExecutionOptimizations(output) + } + + // KotlinNative doesn't support configuration cache yet. + gradleRunner.withArguments( + "--configuration-cache-problems=warn", + "clean", + "build" + ).build().apply { + Assert.assertTrue( + messages.all { + output.contains(it) + } + ) + verifyAll(this) + checkExecutionOptimizations(output) + } + } +} |