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 TransitiveProvidesQualifierTest { 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 TransitiveProvidesQualifierTest(String transitiveDependencyType)47 public TransitiveProvidesQualifierTest(String transitiveDependencyType) { 48 this.transitiveDependencyType = transitiveDependencyType; 49 } 50 51 @Test testQualifierOnProvidesMethodParameter()52 public void testQualifierOnProvidesMethodParameter() 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 assertThat(result.getOutput()) 59 .contains( 60 "ComponentProcessingStep was unable to process 'app.MyComponent' because " 61 + "'library2.MyQualifier' could not be resolved." 62 + "\n " 63 + "\n Dependency trace:" 64 + "\n => element (INTERFACE): library1.MyModule" 65 + "\n => element (METHOD): provideString(int)" 66 + "\n => element (PARAMETER): i" 67 + "\n => annotation: @MyQualifier" 68 + "\n => type (ERROR annotation type): library2.MyQualifier"); 69 break; 70 case "api": 71 result = setupRunner().build(); 72 assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS); 73 assertThat(result.getOutput()).contains("REQUEST: @library2.MyQualifier java.lang.Integer"); 74 break; 75 } 76 } 77 setupRunner()78 private GradleRunner setupRunner() throws IOException { 79 File projectDir = folder.getRoot(); 80 GradleModule.create(projectDir) 81 .addSettingsFile( 82 "include 'app'", 83 "include 'library1'", 84 "include 'library2'", 85 "include 'spi-plugin'") 86 .addBuildFile( 87 "buildscript {", 88 " ext {", 89 String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")), 90 " }", 91 "}", 92 "", 93 "allprojects {", 94 " repositories {", 95 " mavenCentral()", 96 " mavenLocal()", 97 " }", 98 "}"); 99 100 GradleModule.create(projectDir, "app") 101 .addBuildFile( 102 "plugins {", 103 " id 'java'", 104 " id 'application'", 105 "}", 106 "tasks.withType(JavaCompile) {", 107 " options.compilerArgs += '-Adagger.experimentalDaggerErrorMessages=ENABLED'", 108 "}", 109 "dependencies {", 110 " implementation project(':library1')", 111 " annotationProcessor project(':spi-plugin')", 112 " implementation \"com.google.dagger:dagger:$dagger_version\"", 113 " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"", 114 "}") 115 .addSrcFile( 116 "MyComponent.java", 117 "package app;", 118 "", 119 "import dagger.Component;", 120 "import library1.MyModule;", 121 "", 122 "@Component(modules = MyModule.class)", 123 "public interface MyComponent {", 124 " String string();", 125 "}"); 126 127 GradleModule.create(projectDir, "library1") 128 .addBuildFile( 129 "plugins {", 130 " id 'java'", 131 " id 'java-library'", 132 "}", 133 "dependencies {", 134 transitiveDependencyType + " project(':library2')", 135 " implementation \"com.google.dagger:dagger:$dagger_version\"", 136 " annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"", 137 "}") 138 .addSrcFile( 139 "MyModule.java", 140 "package library1;", 141 "", 142 "import dagger.Module;", 143 "import dagger.Provides;", 144 "import library2.MyQualifier;", 145 "", 146 "@Module", 147 "public interface MyModule {", 148 " @Provides", 149 " static String provideString(@MyQualifier int i) {", 150 " return \"\";", 151 " }", 152 "", 153 " @Provides", 154 " @MyQualifier", 155 " static int provideInt() {", 156 " return 0;", 157 " }", 158 "}"); 159 160 GradleModule.create(projectDir, "library2") 161 .addBuildFile( 162 "plugins {", 163 " id 'java'", 164 " id 'java-library'", 165 "}", 166 "dependencies {", 167 " implementation 'javax.inject:javax.inject:1'", 168 "}") 169 .addSrcFile( 170 "MyQualifier.java", 171 "package library2;", 172 "", 173 "import javax.inject.Qualifier;", 174 "", 175 "@Qualifier", 176 "public @interface MyQualifier {}"); 177 178 // This plugin is used to print output about bindings that we can assert on in tests. 179 GradleModule.create(projectDir, "spi-plugin") 180 .addBuildFile( 181 "plugins {", 182 " id 'java'", 183 "}", 184 "dependencies {", 185 " implementation \"com.google.dagger:dagger-spi:$dagger_version\"", 186 " implementation 'com.google.auto.service:auto-service-annotations:1.0.1'", 187 " annotationProcessor 'com.google.auto.service:auto-service:1.0.1'", 188 "}") 189 .addSrcFile( 190 "TestBindingGraphPlugin.java", 191 "package spiplugin;", 192 "", 193 "import com.google.auto.service.AutoService;", 194 "import dagger.model.BindingGraph;", 195 "import dagger.model.BindingGraph.DependencyEdge;", 196 "import dagger.model.DependencyRequest;", 197 "import dagger.spi.BindingGraphPlugin;", 198 "import dagger.spi.DiagnosticReporter;", 199 "", 200 "@AutoService(BindingGraphPlugin.class)", 201 "public class TestBindingGraphPlugin implements BindingGraphPlugin {", 202 " @Override", 203 " public void visitGraph(", 204 " BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {", 205 " bindingGraph.dependencyEdges().stream()", 206 " .map(DependencyEdge::dependencyRequest)", 207 " .map(DependencyRequest::key)", 208 " .forEach(key -> System.out.println(\"REQUEST: \" + key));", 209 " }", 210 "}"); 211 212 return GradleRunner.create() 213 .withArguments("--stacktrace", "build") 214 .withProjectDir(projectDir); 215 } 216 } 217