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