1 /* 2 * Copyright (C) 2022 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 import static org.gradle.testkit.runner.TaskOutcome.SUCCESS; 21 22 import java.io.File; 23 import java.io.IOException; 24 import java.util.Arrays; 25 import java.util.Collection; 26 import org.gradle.testkit.runner.BuildResult; 27 import org.gradle.testkit.runner.GradleRunner; 28 import org.junit.Rule; 29 import org.junit.Test; 30 import org.junit.rules.TemporaryFolder; 31 import org.junit.runner.RunWith; 32 import org.junit.runners.Parameterized; 33 import org.junit.runners.Parameterized.Parameters; 34 35 // This is a regression test for https://github.com/google/dagger/issues/3136 36 @RunWith(Parameterized.class) 37 public class TransitiveComponentDependenciesTest { 38 @Parameters(name = "{0}") parameters()39 public static Collection<Object[]> parameters() { 40 return Arrays.asList(new Object[][] {{"implementation"}, {"api"}}); 41 } 42 43 @Rule public TemporaryFolder folder = new TemporaryFolder(); 44 45 private final String transitiveDependencyType; 46 TransitiveComponentDependenciesTest(String transitiveDependencyType)47 public TransitiveComponentDependenciesTest(String transitiveDependencyType) { 48 this.transitiveDependencyType = transitiveDependencyType; 49 } 50 51 @Test testsComponentDependencies()52 public void testsComponentDependencies() throws IOException { 53 BuildResult result; 54 switch (transitiveDependencyType) { 55 case "implementation": 56 result = setupRunner().buildAndFail(); 57 assertThat(result.getOutput()).contains("Task :app:compileJava FAILED"); 58 String expectedErrorMsg = 59 "error: ComponentProcessingStep was unable to process 'app.ComponentC' because" 60 + " 'libraryA.ComponentA' could not be resolved." 61 + "\n " 62 + "\n Dependency trace:" 63 + "\n => element (CLASS): libraryB.ComponentB" 64 + "\n => annotation type: dagger.Component" 65 + "\n => annotation: @dagger.Component(" 66 + "modules={}, dependencies={libraryA.ComponentA})" 67 + "\n => annotation value (TYPE_ARRAY): dependencies={libraryA.ComponentA}" 68 + "\n => annotation value (TYPE): dependencies=libraryA.ComponentA"; 69 assertThat(result.getOutput()).contains(expectedErrorMsg); 70 break; 71 case "api": 72 result = setupRunner().build(); 73 assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS); 74 break; 75 } 76 } 77 setupRunner()78 private GradleRunner setupRunner() throws IOException { 79 File projectDir = folder.getRoot(); 80 GradleModule.create(projectDir) 81 .addSettingsFile("include 'app'", "include 'libraryB'", "include 'libraryA'") 82 .addBuildFile( 83 "buildscript {", 84 " ext {", 85 String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")), 86 " }", 87 "}", 88 "", 89 "allprojects {", 90 " repositories {", 91 " mavenCentral()", 92 " mavenLocal()", 93 " }", 94 "}"); 95 96 GradleModule.create(projectDir, "app") 97 .addBuildFile( 98 "plugins {", 99 " id 'java'", 100 " id 'application'", 101 "}", 102 "tasks.withType(JavaCompile) {", 103 " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'", 104 "}", 105 "dependencies {", 106 " implementation project(':libraryB')", 107 " implementation \"com.google.dagger:dagger:$dagger_version\"", 108 " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"", 109 "}") 110 .addSrcFile( 111 "ComponentC.java", 112 "package app;", 113 "", 114 "import dagger.Component;", 115 "import libraryB.ComponentB;", 116 "", 117 "@Component(dependencies = ComponentB.class)", 118 "public interface ComponentC {", 119 " public abstract C getC();", 120 "}") 121 .addSrcFile( 122 "C.java", 123 "package app;", 124 "", 125 "import javax.inject.Inject;", 126 "import libraryB.B;", 127 "", 128 "public class C {", 129 " @Inject C(B b) {}", 130 "}"); 131 132 GradleModule.create(projectDir, "libraryB") 133 .addBuildFile( 134 "plugins {", 135 " id 'java'", 136 " id 'java-library'", 137 "}", 138 "dependencies {", 139 transitiveDependencyType + " project(':libraryA')", 140 " implementation \"com.google.dagger:dagger:$dagger_version\"", 141 " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"", 142 "}") 143 .addSrcFile( 144 "ComponentB.java", 145 "package libraryB;", 146 "", 147 "import dagger.Component;", 148 "import libraryA.ComponentA;", 149 "", 150 "@Component(dependencies = ComponentA.class)", 151 "public abstract class ComponentB {", 152 " public abstract B getB();", 153 "}") 154 .addSrcFile( 155 "B.java", 156 "package libraryB;", 157 "", 158 "import javax.inject.Inject;", 159 "import libraryA.A;", 160 "", 161 "public class B {", 162 " @Inject B(A a) {}", 163 "}"); 164 165 GradleModule.create(projectDir, "libraryA") 166 .addBuildFile( 167 "plugins {", 168 " id 'java'", 169 " id 'java-library'", 170 "}", 171 "dependencies {", 172 " implementation \"com.google.dagger:dagger:$dagger_version\"", 173 " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"", 174 "}") 175 .addSrcFile( 176 "ComponentA.java", 177 "package libraryA;", 178 "", 179 "import dagger.Component;", 180 "", 181 "@Component", 182 "public abstract class ComponentA {", 183 " public abstract A getA();", 184 "}") 185 .addSrcFile( 186 "A.java", 187 "package libraryA;", 188 "", 189 "import javax.inject.Inject;", 190 "", 191 "public class A {", 192 " @Inject A() {}", 193 "}") 194 .addSrcFile( 195 "AScope.java", 196 "package libraryA;", 197 "", 198 "import javax.inject.Scope;", 199 "", 200 "@Scope", 201 "public @interface AScope {}"); 202 203 return GradleRunner.create().withArguments("--stacktrace", "build").withProjectDir(projectDir); 204 } 205 } 206