Integration tests for output dependencies
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OutputDepsIt.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OutputDepsIt.kt
new file mode 100644
index 0000000..14bb1a6
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/OutputDepsIt.kt
@@ -0,0 +1,57 @@
+package com.google.devtools.ksp.test
+
+import Artifact
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import java.io.File
+
+class OutputDepsIt {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("output-deps")
+
+ val src2Dirty = listOf(
+ "workload/src/main/java/p1/J1.java" to setOf(
+ "w: [ksp] p1/J1.java",
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] p1/K2.kt",
+ ),
+ "workload/src/main/java/p1/J2.java" to setOf(
+ "w: [ksp] p1/J2.java",
+ ),
+ "workload/src/main/kotlin/p1/K1.kt" to setOf(
+ "w: [ksp] p1/J1.java",
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] p1/K2.kt",
+ ),
+ "workload/src/main/kotlin/p1/K2.kt" to setOf(
+ "w: [ksp] p1/J1.java",
+ "w: [ksp] p1/K1.kt",
+ "w: [ksp] p1/K2.kt",
+ ),
+ )
+
+ @Test
+ fun testOutputDeps() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:assemble")?.outcome)
+ }
+ val cleanArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+
+ src2Dirty.forEach { (src, expectedDirties) ->
+ File(project.root, src).appendText("\n\n")
+ gradleRunner.withArguments("assemble").build().let { result ->
+ Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":workload:kspKotlin")?.outcome)
+ val dirties = result.output.split("\n").filter { it.startsWith("w: [ksp]") }.toSet()
+ Assert.assertEquals(expectedDirties, dirties)
+ }
+ }
+ val incrementalArtifact = Artifact(File(project.root, "workload/build/libs/workload-1.0-SNAPSHOT.jar"))
+ Assert.assertEquals(cleanArtifact, incrementalArtifact)
+ }
+}
diff --git a/integration-tests/src/test/resources/output-deps/build.gradle.kts b/integration-tests/src/test/resources/output-deps/build.gradle.kts
new file mode 100644
index 0000000..f557a53
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/build.gradle.kts
@@ -0,0 +1,9 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+ google()
+}
+
diff --git a/integration-tests/src/test/resources/output-deps/gradle.properties b/integration-tests/src/test/resources/output-deps/gradle.properties
new file mode 100644
index 0000000..f932564
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/gradle.properties
@@ -0,0 +1,2 @@
+ksp.incremental=true
+ksp.incremental.log=true
\ No newline at end of file
diff --git a/integration-tests/src/test/resources/output-deps/settings.gradle.kts b/integration-tests/src/test/resources/output-deps/settings.gradle.kts
new file mode 100644
index 0000000..1c71fa2
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ val kspVersion: String by settings
+ val kotlinVersion: String by settings
+ val testRepo: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion
+ kotlin("jvm") version kotlinVersion
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ google()
+ }
+}
+
+rootProject.name = "incremental-test"
+
+include(":workload")
+include(":test-processor")
diff --git a/integration-tests/src/test/resources/output-deps/test-processor/build.gradle.kts b/integration-tests/src/test/resources/output-deps/test-processor/build.gradle.kts
new file mode 100644
index 0000000..ec59e67
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/test-processor/build.gradle.kts
@@ -0,0 +1,25 @@
+val kspVersion: String by project
+val testRepo: String by project
+
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.example"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ google()
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
+}
+
+sourceSets.main {
+ java.srcDirs("src/main/kotlin")
+}
+
diff --git a/integration-tests/src/test/resources/output-deps/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/output-deps/test-processor/src/main/kotlin/TestProcessor.kt
new file mode 100644
index 0000000..5ef052e
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/test-processor/src/main/kotlin/TestProcessor.kt
@@ -0,0 +1,43 @@
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.Dependencies
+import com.google.devtools.ksp.processing.KSPLogger
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.symbol.*
+import com.google.devtools.ksp.validate
+import com.google.devtools.ksp.visitor.KSDefaultVisitor
+import java.io.File
+import java.io.OutputStream
+import java.io.OutputStreamWriter
+
+class TestProcessor : SymbolProcessor {
+ lateinit var codeGenerator: CodeGenerator
+ lateinit var logger: KSPLogger
+
+ override fun init(options: Map<String, String>, kotlinVersion: KotlinVersion, codeGenerator: CodeGenerator, logger: KSPLogger) {
+ this.codeGenerator = codeGenerator
+ this.logger = logger
+ }
+
+ override fun finish() = Unit
+
+ override fun process(resolver: Resolver) {
+ fun outputForAnno(anno: String) {
+ val annoFiles = resolver.getSymbolsWithAnnotation(anno).map { (it as KSDeclaration).containingFile!! }
+ codeGenerator.createNewFile(Dependencies(false, *annoFiles.toTypedArray()), "", anno, "log").use { output ->
+ OutputStreamWriter(output).use { writer ->
+ writer.write(annoFiles.map { it.fileName }.joinToString(", "))
+ }
+ }
+ }
+
+ outputForAnno("p1.Anno1")
+ outputForAnno("p1.Anno2")
+
+ resolver.getAllFiles().forEach { file ->
+ logger.warn("${file.packageName.asString()}/${file.fileName}")
+ }
+ }
+}
+
+
diff --git a/integration-tests/src/test/resources/output-deps/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessor b/integration-tests/src/test/resources/output-deps/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessor
new file mode 100644
index 0000000..7dcc953
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessor
@@ -0,0 +1 @@
+TestProcessor
diff --git a/integration-tests/src/test/resources/output-deps/workload/build.gradle.kts b/integration-tests/src/test/resources/output-deps/workload/build.gradle.kts
new file mode 100644
index 0000000..e34f0bf
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/build.gradle.kts
@@ -0,0 +1,20 @@
+val testRepo: String by project
+
+plugins {
+ id("com.google.devtools.ksp")
+ kotlin("jvm")
+}
+
+version = "1.0-SNAPSHOT"
+
+repositories {
+ maven(testRepo)
+ mavenCentral()
+ google()
+}
+
+dependencies {
+ implementation(kotlin("stdlib"))
+ ksp(project(":test-processor"))
+}
+
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J1.java b/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J1.java
new file mode 100644
index 0000000..e5e1bc0
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J1.java
@@ -0,0 +1,5 @@
+package p1;
+
+@Anno2
+public class J1 {
+}
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J2.java b/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J2.java
new file mode 100644
index 0000000..7de0687
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/java/p1/J2.java
@@ -0,0 +1,4 @@
+package p1;
+
+public class J2 {
+}
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno1.kt b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno1.kt
new file mode 100644
index 0000000..badbcbd
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno1.kt
@@ -0,0 +1,2 @@
+package p1
+annotation class Anno1
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno2.kt b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno2.kt
new file mode 100644
index 0000000..1c51771
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/Anno2.kt
@@ -0,0 +1,2 @@
+package p1
+annotation class Anno2
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K1.kt b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K1.kt
new file mode 100644
index 0000000..4330181
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K1.kt
@@ -0,0 +1,4 @@
+package p1
+
+@Anno1
+open class K1
diff --git a/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K2.kt b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K2.kt
new file mode 100644
index 0000000..506ed47
--- /dev/null
+++ b/integration-tests/src/test/resources/output-deps/workload/src/main/kotlin/p1/K2.kt
@@ -0,0 +1,5 @@
+package p1
+
+@Anno1
+@Anno2
+open class K2