1 /* 2 * Copyright (C) 2023 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package buildtests; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import java.io.File; 22 import java.io.IOException; 23 import java.nio.file.Files; 24 import java.nio.file.Path; 25 import java.util.Set; 26 import java.util.stream.Collectors; 27 import org.gradle.testkit.runner.BuildResult; 28 import org.gradle.testkit.runner.GradleRunner; 29 import org.junit.Rule; 30 import org.junit.Test; 31 import org.junit.rules.TemporaryFolder; 32 import org.junit.runner.RunWith; 33 import org.junit.runners.JUnit4; 34 35 // This is a regression test for https://github.com/google/dagger/issues/4054 36 @RunWith(JUnit4.class) 37 public class IncrementalProcessingTest { 38 @Rule public TemporaryFolder tmpFolder = new TemporaryFolder(); 39 40 @Test testIncrementalProcessing()41 public void testIncrementalProcessing() throws IOException { 42 File projectDir = tmpFolder.getRoot(); 43 GradleModule.create(projectDir) 44 .addSettingsFile("include 'app'") 45 .addBuildFile( 46 "buildscript {", 47 " ext {", 48 String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")), 49 String.format("kotlin_version = \"%s\"", System.getProperty("kotlin_version")), 50 String.format("ksp_version = \"%s\"", System.getProperty("ksp_version")), 51 " }", 52 "}", 53 "", 54 "allprojects {", 55 " repositories {", 56 " mavenCentral()", 57 " mavenLocal()", 58 " }", 59 "}"); 60 61 GradleModule appModule = 62 GradleModule.create(projectDir, "app") 63 .addBuildFile( 64 "plugins {", 65 " id 'application'", 66 " id 'org.jetbrains.kotlin.jvm' version \"$kotlin_version\"", 67 " id 'com.google.devtools.ksp' version \"$ksp_version\"", 68 "}", 69 "dependencies {", 70 " implementation \"org.jetbrains.kotlin:kotlin-stdlib\"", 71 " implementation \"com.google.dagger:dagger:$dagger_version\"", 72 " ksp \"com.google.dagger:dagger-compiler:$dagger_version\"", 73 "}") 74 // Note: both A and AFactory need to be in the same source file for this to test the 75 // regression in https://github.com/google/dagger/issues/4054. 76 .addSrcFile( 77 "A.kt", 78 "package app", 79 "", 80 "import dagger.assisted.AssistedFactory", 81 "import dagger.assisted.AssistedInject", 82 "", 83 "class A @AssistedInject constructor()", 84 "", 85 "@AssistedFactory", 86 "interface AFactory {", 87 " fun create(): A", 88 "}"); 89 90 // We'll be changing the contents of MyComponent between builds, so store it in a variable. 91 String myComponentContent = 92 String.join( 93 "\n", 94 "package app", 95 "", 96 "import dagger.Component", 97 "", 98 "@Component", 99 "interface MyComponent {", 100 " fun factory(): AFactory", 101 "}"); 102 appModule.addSrcFile("MyComponent.kt", myComponentContent); 103 104 // Build #1 105 build(projectDir); 106 assertThat(getAllKspGeneratedFileNames(appModule.getDir())) 107 .containsExactly( 108 "A_Factory.java", 109 "AFactory_Impl.java", 110 "DaggerMyComponent.java"); 111 112 // Change method name in MyComponent.kt to trigger incremental processing of only MyComponent. 113 appModule.addSrcFile("MyComponent.kt", myComponentContent.replace("factory()", "factory2()")); 114 115 // Build #2 116 build(projectDir); 117 assertThat(getAllKspGeneratedFileNames(appModule.getDir())) 118 .containsExactly( 119 "A_Factory.java", 120 "AFactory_Impl.java", 121 "DaggerMyComponent.java"); 122 } 123 build(File projectDir)124 private static BuildResult build(File projectDir) { 125 return GradleRunner.create() 126 .withArguments("--stacktrace", "build") 127 .withProjectDir(projectDir) 128 .build(); 129 } 130 getAllKspGeneratedFileNames(Path moduleDir)131 private static Set<String> getAllKspGeneratedFileNames(Path moduleDir) throws IOException { 132 return getAllFileNames(moduleDir.resolve("build/generated/ksp/main/java/")); 133 } 134 getAllFileNames(Path dir)135 private static Set<String> getAllFileNames(Path dir) throws IOException { 136 if (!Files.isDirectory(dir)) { 137 throw new IllegalArgumentException("Expected directory: " + dir); 138 } 139 return Files.walk(dir) 140 .filter(Files::isRegularFile) 141 .map(file -> file.getFileName().toString()) 142 .collect(Collectors.toSet()); 143 } 144 } 145