xref: /aosp_15_r20/external/dagger2/javatests/dagger/internal/codegen/ScopingValidationTest.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1*f585d8a3SJacky Wang /*
2*f585d8a3SJacky Wang  * Copyright (C) 2014 The Dagger Authors.
3*f585d8a3SJacky Wang  *
4*f585d8a3SJacky Wang  * Licensed under the Apache License, Version 2.0 (the "License");
5*f585d8a3SJacky Wang  * you may not use this file except in compliance with the License.
6*f585d8a3SJacky Wang  * You may obtain a copy of the License at
7*f585d8a3SJacky Wang  *
8*f585d8a3SJacky Wang  * http://www.apache.org/licenses/LICENSE-2.0
9*f585d8a3SJacky Wang  *
10*f585d8a3SJacky Wang  * Unless required by applicable law or agreed to in writing, software
11*f585d8a3SJacky Wang  * distributed under the License is distributed on an "AS IS" BASIS,
12*f585d8a3SJacky Wang  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f585d8a3SJacky Wang  * See the License for the specific language governing permissions and
14*f585d8a3SJacky Wang  * limitations under the License.
15*f585d8a3SJacky Wang  */
16*f585d8a3SJacky Wang 
17*f585d8a3SJacky Wang package dagger.internal.codegen;
18*f585d8a3SJacky Wang 
19*f585d8a3SJacky Wang import androidx.room.compiler.processing.XProcessingEnv;
20*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source;
21*f585d8a3SJacky Wang import com.google.common.collect.ImmutableMap;
22*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests;
23*f585d8a3SJacky Wang import org.junit.Test;
24*f585d8a3SJacky Wang import org.junit.runner.RunWith;
25*f585d8a3SJacky Wang import org.junit.runners.JUnit4;
26*f585d8a3SJacky Wang 
27*f585d8a3SJacky Wang @RunWith(JUnit4.class)
28*f585d8a3SJacky Wang public class ScopingValidationTest {
29*f585d8a3SJacky Wang   @Test
componentWithoutScopeIncludesScopedBindings_Fail()30*f585d8a3SJacky Wang   public void componentWithoutScopeIncludesScopedBindings_Fail() {
31*f585d8a3SJacky Wang     Source componentFile =
32*f585d8a3SJacky Wang         CompilerTests.javaSource(
33*f585d8a3SJacky Wang             "test.MyComponent",
34*f585d8a3SJacky Wang             "package test;",
35*f585d8a3SJacky Wang             "",
36*f585d8a3SJacky Wang             "import dagger.Component;",
37*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
38*f585d8a3SJacky Wang             "",
39*f585d8a3SJacky Wang             "@Component(modules = ScopedModule.class)",
40*f585d8a3SJacky Wang             "interface MyComponent {",
41*f585d8a3SJacky Wang             "  ScopedType string();",
42*f585d8a3SJacky Wang             "}");
43*f585d8a3SJacky Wang     Source typeFile =
44*f585d8a3SJacky Wang         CompilerTests.javaSource(
45*f585d8a3SJacky Wang             "test.ScopedType",
46*f585d8a3SJacky Wang             "package test;",
47*f585d8a3SJacky Wang             "",
48*f585d8a3SJacky Wang             "import javax.inject.Inject;",
49*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
50*f585d8a3SJacky Wang             "",
51*f585d8a3SJacky Wang             "@Singleton",
52*f585d8a3SJacky Wang             "class ScopedType {",
53*f585d8a3SJacky Wang             "  @Inject ScopedType(String s, long l, float f) {}",
54*f585d8a3SJacky Wang             "}");
55*f585d8a3SJacky Wang     Source moduleFile =
56*f585d8a3SJacky Wang         CompilerTests.javaSource(
57*f585d8a3SJacky Wang             "test.ScopedModule",
58*f585d8a3SJacky Wang             "package test;",
59*f585d8a3SJacky Wang             "",
60*f585d8a3SJacky Wang             "import dagger.Module;",
61*f585d8a3SJacky Wang             "import dagger.Provides;",
62*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
63*f585d8a3SJacky Wang             "",
64*f585d8a3SJacky Wang             "@Module",
65*f585d8a3SJacky Wang             "class ScopedModule {",
66*f585d8a3SJacky Wang             "  @Provides @Singleton String string() { return \"a string\"; }",
67*f585d8a3SJacky Wang             "  @Provides long integer() { return 0L; }",
68*f585d8a3SJacky Wang             "  @Provides float floatingPoint() { return 0.0f; }",
69*f585d8a3SJacky Wang             "}");
70*f585d8a3SJacky Wang 
71*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile, typeFile, moduleFile)
72*f585d8a3SJacky Wang         .compile(
73*f585d8a3SJacky Wang             subject -> {
74*f585d8a3SJacky Wang               subject.hasErrorCount(1);
75*f585d8a3SJacky Wang               subject.hasErrorContaining(
76*f585d8a3SJacky Wang                   String.join(
77*f585d8a3SJacky Wang                       "\n",
78*f585d8a3SJacky Wang                       "MyComponent (unscoped) may not reference scoped bindings:",
79*f585d8a3SJacky Wang                       "    @Singleton class ScopedType",
80*f585d8a3SJacky Wang                       "    ScopedType is requested at",
81*f585d8a3SJacky Wang                       "        MyComponent.string()",
82*f585d8a3SJacky Wang                       "",
83*f585d8a3SJacky Wang                       "    @Provides @Singleton String ScopedModule.string()"));
84*f585d8a3SJacky Wang             });
85*f585d8a3SJacky Wang   }
86*f585d8a3SJacky Wang 
87*f585d8a3SJacky Wang   @Test // b/79859714
bindsWithChildScope_inParentModule_notAllowed()88*f585d8a3SJacky Wang   public void bindsWithChildScope_inParentModule_notAllowed() {
89*f585d8a3SJacky Wang     Source childScope =
90*f585d8a3SJacky Wang         CompilerTests.javaSource(
91*f585d8a3SJacky Wang             "test.ChildScope",
92*f585d8a3SJacky Wang             "package test;",
93*f585d8a3SJacky Wang             "",
94*f585d8a3SJacky Wang             "import javax.inject.Scope;",
95*f585d8a3SJacky Wang             "",
96*f585d8a3SJacky Wang             "@Scope",
97*f585d8a3SJacky Wang             "@interface ChildScope {}");
98*f585d8a3SJacky Wang 
99*f585d8a3SJacky Wang     Source foo =
100*f585d8a3SJacky Wang         CompilerTests.javaSource(
101*f585d8a3SJacky Wang             "test.Foo",
102*f585d8a3SJacky Wang             "package test;",
103*f585d8a3SJacky Wang             "", //
104*f585d8a3SJacky Wang             "interface Foo {}");
105*f585d8a3SJacky Wang 
106*f585d8a3SJacky Wang     Source fooImpl =
107*f585d8a3SJacky Wang         CompilerTests.javaSource(
108*f585d8a3SJacky Wang             "test.FooImpl",
109*f585d8a3SJacky Wang             "package test;",
110*f585d8a3SJacky Wang             "",
111*f585d8a3SJacky Wang             "import javax.inject.Inject;",
112*f585d8a3SJacky Wang             "",
113*f585d8a3SJacky Wang             "class FooImpl implements Foo {",
114*f585d8a3SJacky Wang             "  @Inject FooImpl() {}",
115*f585d8a3SJacky Wang             "}");
116*f585d8a3SJacky Wang 
117*f585d8a3SJacky Wang     Source parentModule =
118*f585d8a3SJacky Wang         CompilerTests.javaSource(
119*f585d8a3SJacky Wang             "test.ParentModule",
120*f585d8a3SJacky Wang             "package test;",
121*f585d8a3SJacky Wang             "",
122*f585d8a3SJacky Wang             "import dagger.Binds;",
123*f585d8a3SJacky Wang             "import dagger.Module;",
124*f585d8a3SJacky Wang             "",
125*f585d8a3SJacky Wang             "@Module",
126*f585d8a3SJacky Wang             "interface ParentModule {",
127*f585d8a3SJacky Wang             "  @Binds @ChildScope Foo bind(FooImpl fooImpl);",
128*f585d8a3SJacky Wang             "}");
129*f585d8a3SJacky Wang 
130*f585d8a3SJacky Wang     Source parent =
131*f585d8a3SJacky Wang         CompilerTests.javaSource(
132*f585d8a3SJacky Wang             "test.Parent",
133*f585d8a3SJacky Wang             "package test;",
134*f585d8a3SJacky Wang             "",
135*f585d8a3SJacky Wang             "import dagger.Component;",
136*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
137*f585d8a3SJacky Wang             "",
138*f585d8a3SJacky Wang             "@Singleton",
139*f585d8a3SJacky Wang             "@Component(modules = ParentModule.class)",
140*f585d8a3SJacky Wang             "interface Parent {",
141*f585d8a3SJacky Wang             "  Child child();",
142*f585d8a3SJacky Wang             "}");
143*f585d8a3SJacky Wang 
144*f585d8a3SJacky Wang     Source child =
145*f585d8a3SJacky Wang         CompilerTests.javaSource(
146*f585d8a3SJacky Wang             "test.Child",
147*f585d8a3SJacky Wang             "package test;",
148*f585d8a3SJacky Wang             "",
149*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
150*f585d8a3SJacky Wang             "",
151*f585d8a3SJacky Wang             "@ChildScope",
152*f585d8a3SJacky Wang             "@Subcomponent",
153*f585d8a3SJacky Wang             "interface Child {",
154*f585d8a3SJacky Wang             "  Foo foo();",
155*f585d8a3SJacky Wang             "}");
156*f585d8a3SJacky Wang 
157*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(childScope, foo, fooImpl, parentModule, parent, child)
158*f585d8a3SJacky Wang         .compile(
159*f585d8a3SJacky Wang             subject -> {
160*f585d8a3SJacky Wang               subject.hasErrorCount(1);
161*f585d8a3SJacky Wang               subject.hasErrorContaining(
162*f585d8a3SJacky Wang                   String.join(
163*f585d8a3SJacky Wang                       "\n",
164*f585d8a3SJacky Wang                       "Parent scoped with @Singleton may not reference bindings with different "
165*f585d8a3SJacky Wang                           + "scopes:",
166*f585d8a3SJacky Wang                       "    @Binds @ChildScope Foo ParentModule.bind(FooImpl)"));
167*f585d8a3SJacky Wang             });
168*f585d8a3SJacky Wang   }
169*f585d8a3SJacky Wang 
170*f585d8a3SJacky Wang   @Test
componentWithScopeIncludesIncompatiblyScopedBindings_Fail()171*f585d8a3SJacky Wang   public void componentWithScopeIncludesIncompatiblyScopedBindings_Fail() {
172*f585d8a3SJacky Wang     Source componentFile =
173*f585d8a3SJacky Wang         CompilerTests.javaSource(
174*f585d8a3SJacky Wang             "test.MyComponent",
175*f585d8a3SJacky Wang             "package test;",
176*f585d8a3SJacky Wang             "",
177*f585d8a3SJacky Wang             "import dagger.Component;",
178*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
179*f585d8a3SJacky Wang             "",
180*f585d8a3SJacky Wang             "@Singleton",
181*f585d8a3SJacky Wang             "@Component(modules = ScopedModule.class)",
182*f585d8a3SJacky Wang             "interface MyComponent {",
183*f585d8a3SJacky Wang             "  ScopedType string();",
184*f585d8a3SJacky Wang             "}");
185*f585d8a3SJacky Wang     Source scopeFile =
186*f585d8a3SJacky Wang         CompilerTests.javaSource(
187*f585d8a3SJacky Wang             "test.PerTest",
188*f585d8a3SJacky Wang             "package test;",
189*f585d8a3SJacky Wang             "",
190*f585d8a3SJacky Wang             "import javax.inject.Scope;",
191*f585d8a3SJacky Wang             "",
192*f585d8a3SJacky Wang             "@Scope",
193*f585d8a3SJacky Wang             "@interface PerTest {}");
194*f585d8a3SJacky Wang     Source scopeWithAttribute =
195*f585d8a3SJacky Wang         CompilerTests.javaSource(
196*f585d8a3SJacky Wang             "test.Per",
197*f585d8a3SJacky Wang             "package test;",
198*f585d8a3SJacky Wang             "",
199*f585d8a3SJacky Wang             "import javax.inject.Scope;",
200*f585d8a3SJacky Wang             "",
201*f585d8a3SJacky Wang             "@Scope",
202*f585d8a3SJacky Wang             "@interface Per {",
203*f585d8a3SJacky Wang             "  Class<?> value();",
204*f585d8a3SJacky Wang             "}");
205*f585d8a3SJacky Wang     Source typeFile =
206*f585d8a3SJacky Wang         CompilerTests.javaSource(
207*f585d8a3SJacky Wang             "test.ScopedType",
208*f585d8a3SJacky Wang             "package test;",
209*f585d8a3SJacky Wang             "",
210*f585d8a3SJacky Wang             "import javax.inject.Inject;",
211*f585d8a3SJacky Wang             "",
212*f585d8a3SJacky Wang             "@PerTest", // incompatible scope
213*f585d8a3SJacky Wang             "class ScopedType {",
214*f585d8a3SJacky Wang             "  @Inject ScopedType(String s, long l, float f, boolean b) {}",
215*f585d8a3SJacky Wang             "}");
216*f585d8a3SJacky Wang     Source moduleFile =
217*f585d8a3SJacky Wang         CompilerTests.javaSource(
218*f585d8a3SJacky Wang             "test.ScopedModule",
219*f585d8a3SJacky Wang             "package test;",
220*f585d8a3SJacky Wang             "",
221*f585d8a3SJacky Wang             "import dagger.Module;",
222*f585d8a3SJacky Wang             "import dagger.Provides;",
223*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
224*f585d8a3SJacky Wang             "",
225*f585d8a3SJacky Wang             "@Module",
226*f585d8a3SJacky Wang             "class ScopedModule {",
227*f585d8a3SJacky Wang             "  @Provides @PerTest String string() { return \"a string\"; }", // incompatible scope
228*f585d8a3SJacky Wang             "  @Provides long integer() { return 0L; }", // unscoped - valid
229*f585d8a3SJacky Wang             "  @Provides @Singleton float floatingPoint() { return 0.0f; }", // same scope - valid
230*f585d8a3SJacky Wang             "  @Provides @Per(MyComponent.class) boolean bool() { return false; }", // incompatible
231*f585d8a3SJacky Wang             "}");
232*f585d8a3SJacky Wang 
233*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile, scopeFile, scopeWithAttribute, typeFile, moduleFile)
234*f585d8a3SJacky Wang         .compile(
235*f585d8a3SJacky Wang             subject -> {
236*f585d8a3SJacky Wang               subject.hasErrorCount(1);
237*f585d8a3SJacky Wang               subject
238*f585d8a3SJacky Wang                   .hasErrorContaining(
239*f585d8a3SJacky Wang                       String.join(
240*f585d8a3SJacky Wang                           "\n",
241*f585d8a3SJacky Wang                           "MyComponent scoped with @Singleton may not reference bindings with "
242*f585d8a3SJacky Wang                               + "different scopes:",
243*f585d8a3SJacky Wang                           "    @PerTest class ScopedType",
244*f585d8a3SJacky Wang                           "    ScopedType is requested at",
245*f585d8a3SJacky Wang                           "        MyComponent.string()",
246*f585d8a3SJacky Wang                           "",
247*f585d8a3SJacky Wang                           "    @Provides @PerTest String ScopedModule.string()",
248*f585d8a3SJacky Wang                           "",
249*f585d8a3SJacky Wang                           // TODO(b/241293838): Remove dependency on backend once this bug is fixed.
250*f585d8a3SJacky Wang                           CompilerTests.backend(subject).equals(XProcessingEnv.Backend.JAVAC)
251*f585d8a3SJacky Wang                               ? "    @Provides @Per(MyComponent.class) boolean ScopedModule.bool()"
252*f585d8a3SJacky Wang                               : "    @Provides @Per(MyComponent) boolean ScopedModule.bool()"))
253*f585d8a3SJacky Wang                   .onSource(componentFile)
254*f585d8a3SJacky Wang                   .onLineContaining("interface MyComponent");
255*f585d8a3SJacky Wang             });
256*f585d8a3SJacky Wang 
257*f585d8a3SJacky Wang     // The @Inject binding for ScopedType should not appear here, but the @Singleton binding should.
258*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile, scopeFile, scopeWithAttribute, typeFile, moduleFile)
259*f585d8a3SJacky Wang         .withProcessingOptions(ImmutableMap.of("dagger.fullBindingGraphValidation", "ERROR"))
260*f585d8a3SJacky Wang         .compile(
261*f585d8a3SJacky Wang             subject -> {
262*f585d8a3SJacky Wang               subject.hasErrorCount(2);
263*f585d8a3SJacky Wang               subject.hasErrorContaining(
264*f585d8a3SJacky Wang                       String.join(
265*f585d8a3SJacky Wang                           "\n",
266*f585d8a3SJacky Wang                           "ScopedModule contains bindings with different scopes:",
267*f585d8a3SJacky Wang                           "    @Provides @PerTest String ScopedModule.string()",
268*f585d8a3SJacky Wang                           "",
269*f585d8a3SJacky Wang                           "    @Provides @Singleton float ScopedModule.floatingPoint()",
270*f585d8a3SJacky Wang                           "",
271*f585d8a3SJacky Wang                           // TODO(b/241293838): Remove dependency on backend once this bug is fixed.
272*f585d8a3SJacky Wang                           CompilerTests.backend(subject).equals(XProcessingEnv.Backend.JAVAC)
273*f585d8a3SJacky Wang                               ? "    @Provides @Per(MyComponent.class) boolean ScopedModule.bool()"
274*f585d8a3SJacky Wang                               : "    @Provides @Per(MyComponent) boolean ScopedModule.bool()"))
275*f585d8a3SJacky Wang                   .onSource(moduleFile)
276*f585d8a3SJacky Wang                   .onLineContaining("class ScopedModule");
277*f585d8a3SJacky Wang             });
278*f585d8a3SJacky Wang   }
279*f585d8a3SJacky Wang 
280*f585d8a3SJacky Wang   @Test
fullBindingGraphValidationDoesNotReportForOneScope()281*f585d8a3SJacky Wang   public void fullBindingGraphValidationDoesNotReportForOneScope() {
282*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
283*f585d8a3SJacky Wang             CompilerTests.javaSource(
284*f585d8a3SJacky Wang                 "test.TestModule",
285*f585d8a3SJacky Wang                 "package test;",
286*f585d8a3SJacky Wang                 "",
287*f585d8a3SJacky Wang                 "import dagger.Module;",
288*f585d8a3SJacky Wang                 "import dagger.Provides;",
289*f585d8a3SJacky Wang                 "import javax.inject.Singleton;",
290*f585d8a3SJacky Wang                 "",
291*f585d8a3SJacky Wang                 "@Module",
292*f585d8a3SJacky Wang                 "interface TestModule {",
293*f585d8a3SJacky Wang                 "  @Provides @Singleton static Object object() { return \"object\"; }",
294*f585d8a3SJacky Wang                 "  @Provides @Singleton static String string() { return \"string\"; }",
295*f585d8a3SJacky Wang                 "  @Provides static int integer() { return 4; }",
296*f585d8a3SJacky Wang                 "}"))
297*f585d8a3SJacky Wang         .withProcessingOptions(
298*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
299*f585d8a3SJacky Wang                 .put("dagger.fullBindingGraphValidation", "ERROR")
300*f585d8a3SJacky Wang                 .put("dagger.moduleHasDifferentScopesValidation", "ERROR")
301*f585d8a3SJacky Wang                 .buildOrThrow())
302*f585d8a3SJacky Wang         .compile(
303*f585d8a3SJacky Wang             subject -> {
304*f585d8a3SJacky Wang               subject.hasErrorCount(0);
305*f585d8a3SJacky Wang               subject.hasWarningCount(0);
306*f585d8a3SJacky Wang             });
307*f585d8a3SJacky Wang   }
308*f585d8a3SJacky Wang 
309*f585d8a3SJacky Wang   @Test
fullBindingGraphValidationDoesNotReportInjectBindings()310*f585d8a3SJacky Wang   public void fullBindingGraphValidationDoesNotReportInjectBindings() {
311*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
312*f585d8a3SJacky Wang             CompilerTests.javaSource(
313*f585d8a3SJacky Wang                 "test.UsedInRootRedScoped",
314*f585d8a3SJacky Wang                 "package test;",
315*f585d8a3SJacky Wang                 "",
316*f585d8a3SJacky Wang                 "import javax.inject.Inject;",
317*f585d8a3SJacky Wang                 "",
318*f585d8a3SJacky Wang                 "@RedScope",
319*f585d8a3SJacky Wang                 "final class UsedInRootRedScoped {",
320*f585d8a3SJacky Wang                 "  @Inject UsedInRootRedScoped() {}",
321*f585d8a3SJacky Wang                 "}"),
322*f585d8a3SJacky Wang             CompilerTests.javaSource(
323*f585d8a3SJacky Wang                 "test.UsedInRootBlueScoped",
324*f585d8a3SJacky Wang                 "package test;",
325*f585d8a3SJacky Wang                 "",
326*f585d8a3SJacky Wang                 "import javax.inject.Inject;",
327*f585d8a3SJacky Wang                 "",
328*f585d8a3SJacky Wang                 "@BlueScope",
329*f585d8a3SJacky Wang                 "final class UsedInRootBlueScoped {",
330*f585d8a3SJacky Wang                 "  @Inject UsedInRootBlueScoped() {}",
331*f585d8a3SJacky Wang                 "}"),
332*f585d8a3SJacky Wang             CompilerTests.javaSource(
333*f585d8a3SJacky Wang                 "test.RedScope",
334*f585d8a3SJacky Wang                 "package test;",
335*f585d8a3SJacky Wang                 "",
336*f585d8a3SJacky Wang                 "import javax.inject.Scope;",
337*f585d8a3SJacky Wang                 "",
338*f585d8a3SJacky Wang                 "@Scope",
339*f585d8a3SJacky Wang                 "@interface RedScope {}"),
340*f585d8a3SJacky Wang             CompilerTests.javaSource(
341*f585d8a3SJacky Wang                 "test.BlueScope",
342*f585d8a3SJacky Wang                 "package test;",
343*f585d8a3SJacky Wang                 "",
344*f585d8a3SJacky Wang                 "import javax.inject.Scope;",
345*f585d8a3SJacky Wang                 "",
346*f585d8a3SJacky Wang                 "@Scope",
347*f585d8a3SJacky Wang                 "@interface BlueScope {}"),
348*f585d8a3SJacky Wang             CompilerTests.javaSource(
349*f585d8a3SJacky Wang                 "test.TestModule",
350*f585d8a3SJacky Wang                 "package test;",
351*f585d8a3SJacky Wang                 "",
352*f585d8a3SJacky Wang                 "import dagger.Module;",
353*f585d8a3SJacky Wang                 "import dagger.Provides;",
354*f585d8a3SJacky Wang                 "import javax.inject.Singleton;",
355*f585d8a3SJacky Wang                 "",
356*f585d8a3SJacky Wang                 "@Module(subcomponents = Child.class)",
357*f585d8a3SJacky Wang                 "interface TestModule {",
358*f585d8a3SJacky Wang                 "  @Provides @Singleton",
359*f585d8a3SJacky Wang                 "  static Object object(",
360*f585d8a3SJacky Wang                 "      UsedInRootRedScoped usedInRootRedScoped,",
361*f585d8a3SJacky Wang                 "      UsedInRootBlueScoped usedInRootBlueScoped) {",
362*f585d8a3SJacky Wang                 "    return \"object\";",
363*f585d8a3SJacky Wang                 "  }",
364*f585d8a3SJacky Wang                 "}"),
365*f585d8a3SJacky Wang             CompilerTests.javaSource(
366*f585d8a3SJacky Wang                 "test.Child",
367*f585d8a3SJacky Wang                 "package test;",
368*f585d8a3SJacky Wang                 "",
369*f585d8a3SJacky Wang                 "import dagger.Subcomponent;",
370*f585d8a3SJacky Wang                 "",
371*f585d8a3SJacky Wang                 "@Subcomponent",
372*f585d8a3SJacky Wang                 "interface Child {",
373*f585d8a3SJacky Wang                 "  UsedInChildRedScoped usedInChildRedScoped();",
374*f585d8a3SJacky Wang                 "  UsedInChildBlueScoped usedInChildBlueScoped();",
375*f585d8a3SJacky Wang                 "",
376*f585d8a3SJacky Wang                 "  @Subcomponent.Builder",
377*f585d8a3SJacky Wang                 "  interface Builder {",
378*f585d8a3SJacky Wang                 "    Child child();",
379*f585d8a3SJacky Wang                 "  }",
380*f585d8a3SJacky Wang                 "}"),
381*f585d8a3SJacky Wang             CompilerTests.javaSource(
382*f585d8a3SJacky Wang                 "test.UsedInChildRedScoped",
383*f585d8a3SJacky Wang                 "package test;",
384*f585d8a3SJacky Wang                 "",
385*f585d8a3SJacky Wang                 "import javax.inject.Inject;",
386*f585d8a3SJacky Wang                 "",
387*f585d8a3SJacky Wang                 "@RedScope",
388*f585d8a3SJacky Wang                 "final class UsedInChildRedScoped {",
389*f585d8a3SJacky Wang                 "  @Inject UsedInChildRedScoped() {}",
390*f585d8a3SJacky Wang                 "}"),
391*f585d8a3SJacky Wang             CompilerTests.javaSource(
392*f585d8a3SJacky Wang                 "test.UsedInChildBlueScoped",
393*f585d8a3SJacky Wang                 "package test;",
394*f585d8a3SJacky Wang                 "",
395*f585d8a3SJacky Wang                 "import javax.inject.Inject;",
396*f585d8a3SJacky Wang                 "",
397*f585d8a3SJacky Wang                 "@BlueScope",
398*f585d8a3SJacky Wang                 "final class UsedInChildBlueScoped {",
399*f585d8a3SJacky Wang                 "  @Inject UsedInChildBlueScoped() {}",
400*f585d8a3SJacky Wang                 "}"))
401*f585d8a3SJacky Wang         .withProcessingOptions(
402*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
403*f585d8a3SJacky Wang                 .put("dagger.fullBindingGraphValidation", "ERROR")
404*f585d8a3SJacky Wang                 .put("dagger.moduleHasDifferentScopesValidation", "ERROR")
405*f585d8a3SJacky Wang                 .buildOrThrow())
406*f585d8a3SJacky Wang         .compile(
407*f585d8a3SJacky Wang             subject -> {
408*f585d8a3SJacky Wang               subject.hasErrorCount(0);
409*f585d8a3SJacky Wang               subject.hasWarningCount(0);
410*f585d8a3SJacky Wang             });
411*f585d8a3SJacky Wang   }
412*f585d8a3SJacky Wang 
413*f585d8a3SJacky Wang   @Test
componentWithScopeCanDependOnMultipleScopedComponents()414*f585d8a3SJacky Wang   public void componentWithScopeCanDependOnMultipleScopedComponents() {
415*f585d8a3SJacky Wang     // If a scoped component will have dependencies, they can include multiple scoped component
416*f585d8a3SJacky Wang     Source type =
417*f585d8a3SJacky Wang         CompilerTests.javaSource(
418*f585d8a3SJacky Wang             "test.SimpleType",
419*f585d8a3SJacky Wang             "package test;",
420*f585d8a3SJacky Wang             "",
421*f585d8a3SJacky Wang             "import javax.inject.Inject;",
422*f585d8a3SJacky Wang             "",
423*f585d8a3SJacky Wang             "class SimpleType {",
424*f585d8a3SJacky Wang             "  @Inject SimpleType() {}",
425*f585d8a3SJacky Wang             "  static class A { @Inject A() {} }",
426*f585d8a3SJacky Wang             "  static class B { @Inject B() {} }",
427*f585d8a3SJacky Wang             "}");
428*f585d8a3SJacky Wang     Source simpleScope =
429*f585d8a3SJacky Wang         CompilerTests.javaSource(
430*f585d8a3SJacky Wang             "test.SimpleScope",
431*f585d8a3SJacky Wang             "package test;",
432*f585d8a3SJacky Wang             "",
433*f585d8a3SJacky Wang             "import javax.inject.Scope;",
434*f585d8a3SJacky Wang             "",
435*f585d8a3SJacky Wang             "@Scope @interface SimpleScope {}");
436*f585d8a3SJacky Wang     Source singletonScopedA =
437*f585d8a3SJacky Wang         CompilerTests.javaSource(
438*f585d8a3SJacky Wang             "test.SingletonComponentA",
439*f585d8a3SJacky Wang             "package test;",
440*f585d8a3SJacky Wang             "",
441*f585d8a3SJacky Wang             "import dagger.Component;",
442*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
443*f585d8a3SJacky Wang             "",
444*f585d8a3SJacky Wang             "@Singleton",
445*f585d8a3SJacky Wang             "@Component",
446*f585d8a3SJacky Wang             "interface SingletonComponentA {",
447*f585d8a3SJacky Wang             "  SimpleType.A type();",
448*f585d8a3SJacky Wang             "}");
449*f585d8a3SJacky Wang     Source singletonScopedB =
450*f585d8a3SJacky Wang         CompilerTests.javaSource(
451*f585d8a3SJacky Wang             "test.SingletonComponentB",
452*f585d8a3SJacky Wang             "package test;",
453*f585d8a3SJacky Wang             "",
454*f585d8a3SJacky Wang             "import dagger.Component;",
455*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
456*f585d8a3SJacky Wang             "",
457*f585d8a3SJacky Wang             "@Singleton",
458*f585d8a3SJacky Wang             "@Component",
459*f585d8a3SJacky Wang             "interface SingletonComponentB {",
460*f585d8a3SJacky Wang             "  SimpleType.B type();",
461*f585d8a3SJacky Wang             "}");
462*f585d8a3SJacky Wang     Source scopeless =
463*f585d8a3SJacky Wang         CompilerTests.javaSource(
464*f585d8a3SJacky Wang             "test.ScopelessComponent",
465*f585d8a3SJacky Wang             "package test;",
466*f585d8a3SJacky Wang             "",
467*f585d8a3SJacky Wang             "import dagger.Component;",
468*f585d8a3SJacky Wang             "",
469*f585d8a3SJacky Wang             "@Component",
470*f585d8a3SJacky Wang             "interface ScopelessComponent {",
471*f585d8a3SJacky Wang             "  SimpleType type();",
472*f585d8a3SJacky Wang             "}");
473*f585d8a3SJacky Wang     Source simpleScoped =
474*f585d8a3SJacky Wang         CompilerTests.javaSource(
475*f585d8a3SJacky Wang             "test.SimpleScopedComponent",
476*f585d8a3SJacky Wang             "package test;",
477*f585d8a3SJacky Wang             "",
478*f585d8a3SJacky Wang             "import dagger.Component;",
479*f585d8a3SJacky Wang             "",
480*f585d8a3SJacky Wang             "@SimpleScope",
481*f585d8a3SJacky Wang             "@Component(dependencies = {SingletonComponentA.class, SingletonComponentB.class})",
482*f585d8a3SJacky Wang             "interface SimpleScopedComponent {",
483*f585d8a3SJacky Wang             "  SimpleType.A type();",
484*f585d8a3SJacky Wang             "}");
485*f585d8a3SJacky Wang 
486*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
487*f585d8a3SJacky Wang             type, simpleScope, simpleScoped, singletonScopedA, singletonScopedB, scopeless)
488*f585d8a3SJacky Wang         .compile(
489*f585d8a3SJacky Wang             subject -> {
490*f585d8a3SJacky Wang               subject.hasErrorCount(0);
491*f585d8a3SJacky Wang               subject.hasWarningCount(0);
492*f585d8a3SJacky Wang             });
493*f585d8a3SJacky Wang   }
494*f585d8a3SJacky Wang 
495*f585d8a3SJacky Wang 
496*f585d8a3SJacky Wang 
497*f585d8a3SJacky Wang   // Tests the following component hierarchy:
498*f585d8a3SJacky Wang   //
499*f585d8a3SJacky Wang   //        @ScopeA
500*f585d8a3SJacky Wang   //        ComponentA
501*f585d8a3SJacky Wang   //        [SimpleType getSimpleType()]
502*f585d8a3SJacky Wang   //        /        \
503*f585d8a3SJacky Wang   //       /          \
504*f585d8a3SJacky Wang   //   @ScopeB         @ScopeB
505*f585d8a3SJacky Wang   //   ComponentB1     ComponentB2
506*f585d8a3SJacky Wang   //      \            [SimpleType getSimpleType()]
507*f585d8a3SJacky Wang   //       \          /
508*f585d8a3SJacky Wang   //        \        /
509*f585d8a3SJacky Wang   //         @ScopeC
510*f585d8a3SJacky Wang   //         ComponentC
511*f585d8a3SJacky Wang   //         [SimpleType getSimpleType()]
512*f585d8a3SJacky Wang   @Test
componentWithScopeCanDependOnMultipleScopedComponentsEvenDoingADiamond()513*f585d8a3SJacky Wang   public void componentWithScopeCanDependOnMultipleScopedComponentsEvenDoingADiamond() {
514*f585d8a3SJacky Wang     Source type =
515*f585d8a3SJacky Wang         CompilerTests.javaSource(
516*f585d8a3SJacky Wang             "test.SimpleType",
517*f585d8a3SJacky Wang             "package test;",
518*f585d8a3SJacky Wang             "",
519*f585d8a3SJacky Wang             "import javax.inject.Inject;",
520*f585d8a3SJacky Wang             "",
521*f585d8a3SJacky Wang             "class SimpleType {",
522*f585d8a3SJacky Wang             "  @Inject SimpleType() {}",
523*f585d8a3SJacky Wang             "}");
524*f585d8a3SJacky Wang     Source simpleScope =
525*f585d8a3SJacky Wang         CompilerTests.javaSource(
526*f585d8a3SJacky Wang             "test.SimpleScope",
527*f585d8a3SJacky Wang             "package test;",
528*f585d8a3SJacky Wang             "",
529*f585d8a3SJacky Wang             "import javax.inject.Scope;",
530*f585d8a3SJacky Wang             "",
531*f585d8a3SJacky Wang             "@Scope @interface SimpleScope {}");
532*f585d8a3SJacky Wang     Source scopeA =
533*f585d8a3SJacky Wang         CompilerTests.javaSource(
534*f585d8a3SJacky Wang             "test.ScopeA",
535*f585d8a3SJacky Wang             "package test;",
536*f585d8a3SJacky Wang             "",
537*f585d8a3SJacky Wang             "import javax.inject.Scope;",
538*f585d8a3SJacky Wang             "",
539*f585d8a3SJacky Wang             "@Scope @interface ScopeA {}");
540*f585d8a3SJacky Wang     Source scopeB =
541*f585d8a3SJacky Wang         CompilerTests.javaSource(
542*f585d8a3SJacky Wang             "test.ScopeB",
543*f585d8a3SJacky Wang             "package test;",
544*f585d8a3SJacky Wang             "",
545*f585d8a3SJacky Wang             "import javax.inject.Scope;",
546*f585d8a3SJacky Wang             "",
547*f585d8a3SJacky Wang             "@Scope @interface ScopeB {}");
548*f585d8a3SJacky Wang     Source componentA =
549*f585d8a3SJacky Wang         CompilerTests.javaSource(
550*f585d8a3SJacky Wang             "test.ComponentA",
551*f585d8a3SJacky Wang             "package test;",
552*f585d8a3SJacky Wang             "",
553*f585d8a3SJacky Wang             "import dagger.Component;",
554*f585d8a3SJacky Wang             "",
555*f585d8a3SJacky Wang             "@ScopeA",
556*f585d8a3SJacky Wang             "@Component",
557*f585d8a3SJacky Wang             "interface ComponentA {",
558*f585d8a3SJacky Wang             "  SimpleType type();",
559*f585d8a3SJacky Wang             "}");
560*f585d8a3SJacky Wang     Source componentB1 =
561*f585d8a3SJacky Wang         CompilerTests.javaSource(
562*f585d8a3SJacky Wang             "test.ComponentB1",
563*f585d8a3SJacky Wang             "package test;",
564*f585d8a3SJacky Wang             "",
565*f585d8a3SJacky Wang             "import dagger.Component;",
566*f585d8a3SJacky Wang             "",
567*f585d8a3SJacky Wang             "@ScopeB",
568*f585d8a3SJacky Wang             "@Component(dependencies = ComponentA.class)",
569*f585d8a3SJacky Wang             "interface ComponentB1 {",
570*f585d8a3SJacky Wang             "  SimpleType type();",
571*f585d8a3SJacky Wang             "}");
572*f585d8a3SJacky Wang     Source componentB2 =
573*f585d8a3SJacky Wang         CompilerTests.javaSource(
574*f585d8a3SJacky Wang             "test.ComponentB2",
575*f585d8a3SJacky Wang             "package test;",
576*f585d8a3SJacky Wang             "",
577*f585d8a3SJacky Wang             "import dagger.Component;",
578*f585d8a3SJacky Wang             "",
579*f585d8a3SJacky Wang             "@ScopeB",
580*f585d8a3SJacky Wang             "@Component(dependencies = ComponentA.class)",
581*f585d8a3SJacky Wang             "interface ComponentB2 {",
582*f585d8a3SJacky Wang             "}");
583*f585d8a3SJacky Wang     Source componentC =
584*f585d8a3SJacky Wang         CompilerTests.javaSource(
585*f585d8a3SJacky Wang             "test.ComponentC",
586*f585d8a3SJacky Wang             "package test;",
587*f585d8a3SJacky Wang             "",
588*f585d8a3SJacky Wang             "import dagger.Component;",
589*f585d8a3SJacky Wang             "",
590*f585d8a3SJacky Wang             "@SimpleScope",
591*f585d8a3SJacky Wang             "@Component(dependencies = {ComponentB1.class, ComponentB2.class})",
592*f585d8a3SJacky Wang             "interface ComponentC {",
593*f585d8a3SJacky Wang             "  SimpleType type();",
594*f585d8a3SJacky Wang             "}");
595*f585d8a3SJacky Wang 
596*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
597*f585d8a3SJacky Wang             type, simpleScope, scopeA, scopeB, componentA, componentB1, componentB2, componentC)
598*f585d8a3SJacky Wang         .compile(
599*f585d8a3SJacky Wang             subject -> {
600*f585d8a3SJacky Wang               subject.hasErrorCount(0);
601*f585d8a3SJacky Wang               subject.hasWarningCount(0);
602*f585d8a3SJacky Wang             });
603*f585d8a3SJacky Wang   }
604*f585d8a3SJacky Wang 
605*f585d8a3SJacky Wang   @Test
componentWithoutScopeCannotDependOnScopedComponent()606*f585d8a3SJacky Wang   public void componentWithoutScopeCannotDependOnScopedComponent() {
607*f585d8a3SJacky Wang     Source type =
608*f585d8a3SJacky Wang         CompilerTests.javaSource(
609*f585d8a3SJacky Wang             "test.SimpleType",
610*f585d8a3SJacky Wang             "package test;",
611*f585d8a3SJacky Wang             "",
612*f585d8a3SJacky Wang             "import javax.inject.Inject;",
613*f585d8a3SJacky Wang             "",
614*f585d8a3SJacky Wang             "class SimpleType {",
615*f585d8a3SJacky Wang             "  @Inject SimpleType() {}",
616*f585d8a3SJacky Wang             "}");
617*f585d8a3SJacky Wang     Source scopedComponent =
618*f585d8a3SJacky Wang         CompilerTests.javaSource(
619*f585d8a3SJacky Wang             "test.ScopedComponent",
620*f585d8a3SJacky Wang             "package test;",
621*f585d8a3SJacky Wang             "",
622*f585d8a3SJacky Wang             "import dagger.Component;",
623*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
624*f585d8a3SJacky Wang             "",
625*f585d8a3SJacky Wang             "@Singleton",
626*f585d8a3SJacky Wang             "@Component",
627*f585d8a3SJacky Wang             "interface ScopedComponent {",
628*f585d8a3SJacky Wang             "  SimpleType type();",
629*f585d8a3SJacky Wang             "}");
630*f585d8a3SJacky Wang     Source unscopedComponent =
631*f585d8a3SJacky Wang         CompilerTests.javaSource(
632*f585d8a3SJacky Wang             "test.UnscopedComponent",
633*f585d8a3SJacky Wang             "package test;",
634*f585d8a3SJacky Wang             "",
635*f585d8a3SJacky Wang             "import dagger.Component;",
636*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
637*f585d8a3SJacky Wang             "",
638*f585d8a3SJacky Wang             "@Component(dependencies = ScopedComponent.class)",
639*f585d8a3SJacky Wang             "interface UnscopedComponent {",
640*f585d8a3SJacky Wang             "  SimpleType type();",
641*f585d8a3SJacky Wang             "}");
642*f585d8a3SJacky Wang 
643*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(type, scopedComponent, unscopedComponent)
644*f585d8a3SJacky Wang         .compile(
645*f585d8a3SJacky Wang             subject -> {
646*f585d8a3SJacky Wang               subject.hasErrorCount(1);
647*f585d8a3SJacky Wang               subject.hasErrorContaining(
648*f585d8a3SJacky Wang                   String.join(
649*f585d8a3SJacky Wang                       "\n",
650*f585d8a3SJacky Wang                       "test.UnscopedComponent (unscoped) cannot depend on scoped components:",
651*f585d8a3SJacky Wang                       "    @Singleton test.ScopedComponent"));
652*f585d8a3SJacky Wang             });
653*f585d8a3SJacky Wang   }
654*f585d8a3SJacky Wang 
655*f585d8a3SJacky Wang   @Test
componentWithSingletonScopeMayNotDependOnOtherScope()656*f585d8a3SJacky Wang   public void componentWithSingletonScopeMayNotDependOnOtherScope() {
657*f585d8a3SJacky Wang     // Singleton must be the widest lifetime of present scopes.
658*f585d8a3SJacky Wang     Source type =
659*f585d8a3SJacky Wang         CompilerTests.javaSource(
660*f585d8a3SJacky Wang             "test.SimpleType",
661*f585d8a3SJacky Wang             "package test;",
662*f585d8a3SJacky Wang             "",
663*f585d8a3SJacky Wang             "import javax.inject.Inject;",
664*f585d8a3SJacky Wang             "",
665*f585d8a3SJacky Wang             "class SimpleType {",
666*f585d8a3SJacky Wang             "  @Inject SimpleType() {}",
667*f585d8a3SJacky Wang             "}");
668*f585d8a3SJacky Wang     Source simpleScope =
669*f585d8a3SJacky Wang         CompilerTests.javaSource(
670*f585d8a3SJacky Wang             "test.SimpleScope",
671*f585d8a3SJacky Wang             "package test;",
672*f585d8a3SJacky Wang             "",
673*f585d8a3SJacky Wang             "import javax.inject.Scope;",
674*f585d8a3SJacky Wang             "",
675*f585d8a3SJacky Wang             "@Scope @interface SimpleScope {}");
676*f585d8a3SJacky Wang     Source simpleScoped =
677*f585d8a3SJacky Wang         CompilerTests.javaSource(
678*f585d8a3SJacky Wang             "test.SimpleScopedComponent",
679*f585d8a3SJacky Wang             "package test;",
680*f585d8a3SJacky Wang             "",
681*f585d8a3SJacky Wang             "import dagger.Component;",
682*f585d8a3SJacky Wang             "",
683*f585d8a3SJacky Wang             "@SimpleScope",
684*f585d8a3SJacky Wang             "@Component",
685*f585d8a3SJacky Wang             "interface SimpleScopedComponent {",
686*f585d8a3SJacky Wang             "  SimpleType type();",
687*f585d8a3SJacky Wang             "}");
688*f585d8a3SJacky Wang     Source singletonScoped =
689*f585d8a3SJacky Wang         CompilerTests.javaSource(
690*f585d8a3SJacky Wang             "test.SingletonComponent",
691*f585d8a3SJacky Wang             "package test;",
692*f585d8a3SJacky Wang             "",
693*f585d8a3SJacky Wang             "import dagger.Component;",
694*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
695*f585d8a3SJacky Wang             "",
696*f585d8a3SJacky Wang             "@Singleton",
697*f585d8a3SJacky Wang             "@Component(dependencies = SimpleScopedComponent.class)",
698*f585d8a3SJacky Wang             "interface SingletonComponent {",
699*f585d8a3SJacky Wang             "  SimpleType type();",
700*f585d8a3SJacky Wang             "}");
701*f585d8a3SJacky Wang 
702*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(type, simpleScope, simpleScoped, singletonScoped)
703*f585d8a3SJacky Wang         .compile(
704*f585d8a3SJacky Wang             subject -> {
705*f585d8a3SJacky Wang               subject.hasErrorCount(1);
706*f585d8a3SJacky Wang               subject.hasErrorContaining(
707*f585d8a3SJacky Wang                   String.join(
708*f585d8a3SJacky Wang                       "\n",
709*f585d8a3SJacky Wang                       "This @Singleton component cannot depend on scoped components:",
710*f585d8a3SJacky Wang                       "    @test.SimpleScope test.SimpleScopedComponent"));
711*f585d8a3SJacky Wang             });
712*f585d8a3SJacky Wang   }
713*f585d8a3SJacky Wang 
714*f585d8a3SJacky Wang   @Test
componentScopeWithMultipleScopedDependenciesMustNotCycle()715*f585d8a3SJacky Wang   public void componentScopeWithMultipleScopedDependenciesMustNotCycle() {
716*f585d8a3SJacky Wang     Source type =
717*f585d8a3SJacky Wang         CompilerTests.javaSource(
718*f585d8a3SJacky Wang             "test.SimpleType",
719*f585d8a3SJacky Wang             "package test;",
720*f585d8a3SJacky Wang             "",
721*f585d8a3SJacky Wang             "import javax.inject.Inject;",
722*f585d8a3SJacky Wang             "",
723*f585d8a3SJacky Wang             "class SimpleType {",
724*f585d8a3SJacky Wang             "  @Inject SimpleType() {}",
725*f585d8a3SJacky Wang             "}");
726*f585d8a3SJacky Wang     Source scopeA =
727*f585d8a3SJacky Wang         CompilerTests.javaSource(
728*f585d8a3SJacky Wang             "test.ScopeA",
729*f585d8a3SJacky Wang             "package test;",
730*f585d8a3SJacky Wang             "",
731*f585d8a3SJacky Wang             "import javax.inject.Scope;",
732*f585d8a3SJacky Wang             "",
733*f585d8a3SJacky Wang             "@Scope @interface ScopeA {}");
734*f585d8a3SJacky Wang     Source scopeB =
735*f585d8a3SJacky Wang         CompilerTests.javaSource(
736*f585d8a3SJacky Wang             "test.ScopeB",
737*f585d8a3SJacky Wang             "package test;",
738*f585d8a3SJacky Wang             "",
739*f585d8a3SJacky Wang             "import javax.inject.Scope;",
740*f585d8a3SJacky Wang             "",
741*f585d8a3SJacky Wang             "@Scope @interface ScopeB {}");
742*f585d8a3SJacky Wang     Source longLifetime =
743*f585d8a3SJacky Wang         CompilerTests.javaSource(
744*f585d8a3SJacky Wang             "test.ComponentLong",
745*f585d8a3SJacky Wang             "package test;",
746*f585d8a3SJacky Wang             "",
747*f585d8a3SJacky Wang             "import dagger.Component;",
748*f585d8a3SJacky Wang             "",
749*f585d8a3SJacky Wang             "@ScopeA",
750*f585d8a3SJacky Wang             "@Component",
751*f585d8a3SJacky Wang             "interface ComponentLong {",
752*f585d8a3SJacky Wang             "  SimpleType type();",
753*f585d8a3SJacky Wang             "}");
754*f585d8a3SJacky Wang     Source mediumLifetime1 =
755*f585d8a3SJacky Wang         CompilerTests.javaSource(
756*f585d8a3SJacky Wang             "test.ComponentMedium1",
757*f585d8a3SJacky Wang             "package test;",
758*f585d8a3SJacky Wang             "",
759*f585d8a3SJacky Wang             "import dagger.Component;",
760*f585d8a3SJacky Wang             "",
761*f585d8a3SJacky Wang             "@ScopeB",
762*f585d8a3SJacky Wang             "@Component(dependencies = ComponentLong.class)",
763*f585d8a3SJacky Wang             "interface ComponentMedium1 {",
764*f585d8a3SJacky Wang             "  SimpleType type();",
765*f585d8a3SJacky Wang             "}");
766*f585d8a3SJacky Wang     Source mediumLifetime2 =
767*f585d8a3SJacky Wang         CompilerTests.javaSource(
768*f585d8a3SJacky Wang             "test.ComponentMedium2",
769*f585d8a3SJacky Wang             "package test;",
770*f585d8a3SJacky Wang             "",
771*f585d8a3SJacky Wang             "import dagger.Component;",
772*f585d8a3SJacky Wang             "",
773*f585d8a3SJacky Wang             "@ScopeB",
774*f585d8a3SJacky Wang             "@Component",
775*f585d8a3SJacky Wang             "interface ComponentMedium2 {",
776*f585d8a3SJacky Wang             "}");
777*f585d8a3SJacky Wang     Source shortLifetime =
778*f585d8a3SJacky Wang         CompilerTests.javaSource(
779*f585d8a3SJacky Wang             "test.ComponentShort",
780*f585d8a3SJacky Wang             "package test;",
781*f585d8a3SJacky Wang             "",
782*f585d8a3SJacky Wang             "import dagger.Component;",
783*f585d8a3SJacky Wang             "",
784*f585d8a3SJacky Wang             "@ScopeA",
785*f585d8a3SJacky Wang             "@Component(dependencies = {ComponentMedium1.class, ComponentMedium2.class})",
786*f585d8a3SJacky Wang             "interface ComponentShort {",
787*f585d8a3SJacky Wang             "  SimpleType type();",
788*f585d8a3SJacky Wang             "}");
789*f585d8a3SJacky Wang 
790*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
791*f585d8a3SJacky Wang             type, scopeA, scopeB, longLifetime, mediumLifetime1, mediumLifetime2, shortLifetime)
792*f585d8a3SJacky Wang         .compile(
793*f585d8a3SJacky Wang             subject -> {
794*f585d8a3SJacky Wang               subject.hasErrorCount(1);
795*f585d8a3SJacky Wang               subject.hasErrorContaining(
796*f585d8a3SJacky Wang                   String.join(
797*f585d8a3SJacky Wang                       "\n",
798*f585d8a3SJacky Wang                       "test.ComponentShort depends on scoped components in a non-hierarchical "
799*f585d8a3SJacky Wang                           + "scope ordering:",
800*f585d8a3SJacky Wang                       "    @test.ScopeA test.ComponentLong",
801*f585d8a3SJacky Wang                       "    @test.ScopeB test.ComponentMedium1",
802*f585d8a3SJacky Wang                       "    @test.ScopeA test.ComponentShort"));
803*f585d8a3SJacky Wang             });
804*f585d8a3SJacky Wang   }
805*f585d8a3SJacky Wang 
806*f585d8a3SJacky Wang   @Test
componentScopeAncestryMustNotCycle()807*f585d8a3SJacky Wang   public void componentScopeAncestryMustNotCycle() {
808*f585d8a3SJacky Wang     // The dependency relationship of components is necessarily from shorter lifetimes to
809*f585d8a3SJacky Wang     // longer lifetimes.  The scoping annotations must reflect this, and so one cannot declare
810*f585d8a3SJacky Wang     // scopes on components such that they cycle.
811*f585d8a3SJacky Wang     Source type =
812*f585d8a3SJacky Wang         CompilerTests.javaSource(
813*f585d8a3SJacky Wang             "test.SimpleType",
814*f585d8a3SJacky Wang             "package test;",
815*f585d8a3SJacky Wang             "",
816*f585d8a3SJacky Wang             "import javax.inject.Inject;",
817*f585d8a3SJacky Wang             "",
818*f585d8a3SJacky Wang             "class SimpleType {",
819*f585d8a3SJacky Wang             "  @Inject SimpleType() {}",
820*f585d8a3SJacky Wang             "}");
821*f585d8a3SJacky Wang     Source scopeA =
822*f585d8a3SJacky Wang         CompilerTests.javaSource(
823*f585d8a3SJacky Wang             "test.ScopeA",
824*f585d8a3SJacky Wang             "package test;",
825*f585d8a3SJacky Wang             "",
826*f585d8a3SJacky Wang             "import javax.inject.Scope;",
827*f585d8a3SJacky Wang             "",
828*f585d8a3SJacky Wang             "@Scope @interface ScopeA {}");
829*f585d8a3SJacky Wang     Source scopeB =
830*f585d8a3SJacky Wang         CompilerTests.javaSource(
831*f585d8a3SJacky Wang             "test.ScopeB",
832*f585d8a3SJacky Wang             "package test;",
833*f585d8a3SJacky Wang             "",
834*f585d8a3SJacky Wang             "import javax.inject.Scope;",
835*f585d8a3SJacky Wang             "",
836*f585d8a3SJacky Wang             "@Scope @interface ScopeB {}");
837*f585d8a3SJacky Wang     Source longLifetime =
838*f585d8a3SJacky Wang         CompilerTests.javaSource(
839*f585d8a3SJacky Wang             "test.ComponentLong",
840*f585d8a3SJacky Wang             "package test;",
841*f585d8a3SJacky Wang             "",
842*f585d8a3SJacky Wang             "import dagger.Component;",
843*f585d8a3SJacky Wang             "",
844*f585d8a3SJacky Wang             "@ScopeA",
845*f585d8a3SJacky Wang             "@Component",
846*f585d8a3SJacky Wang             "interface ComponentLong {",
847*f585d8a3SJacky Wang             "  SimpleType type();",
848*f585d8a3SJacky Wang             "}");
849*f585d8a3SJacky Wang     Source mediumLifetime =
850*f585d8a3SJacky Wang         CompilerTests.javaSource(
851*f585d8a3SJacky Wang             "test.ComponentMedium",
852*f585d8a3SJacky Wang             "package test;",
853*f585d8a3SJacky Wang             "",
854*f585d8a3SJacky Wang             "import dagger.Component;",
855*f585d8a3SJacky Wang             "",
856*f585d8a3SJacky Wang             "@ScopeB",
857*f585d8a3SJacky Wang             "@Component(dependencies = ComponentLong.class)",
858*f585d8a3SJacky Wang             "interface ComponentMedium {",
859*f585d8a3SJacky Wang             "  SimpleType type();",
860*f585d8a3SJacky Wang             "}");
861*f585d8a3SJacky Wang     Source shortLifetime =
862*f585d8a3SJacky Wang         CompilerTests.javaSource(
863*f585d8a3SJacky Wang             "test.ComponentShort",
864*f585d8a3SJacky Wang             "package test;",
865*f585d8a3SJacky Wang             "",
866*f585d8a3SJacky Wang             "import dagger.Component;",
867*f585d8a3SJacky Wang             "",
868*f585d8a3SJacky Wang             "@ScopeA",
869*f585d8a3SJacky Wang             "@Component(dependencies = ComponentMedium.class)",
870*f585d8a3SJacky Wang             "interface ComponentShort {",
871*f585d8a3SJacky Wang             "  SimpleType type();",
872*f585d8a3SJacky Wang             "}");
873*f585d8a3SJacky Wang 
874*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(type, scopeA, scopeB, longLifetime, mediumLifetime, shortLifetime)
875*f585d8a3SJacky Wang         .compile(
876*f585d8a3SJacky Wang             subject -> {
877*f585d8a3SJacky Wang               subject.hasErrorCount(1);
878*f585d8a3SJacky Wang               subject.hasErrorContaining(
879*f585d8a3SJacky Wang                   String.join(
880*f585d8a3SJacky Wang                       "\n",
881*f585d8a3SJacky Wang                       "test.ComponentShort depends on scoped components in a non-hierarchical "
882*f585d8a3SJacky Wang                           + "scope ordering:",
883*f585d8a3SJacky Wang                       "    @test.ScopeA test.ComponentLong",
884*f585d8a3SJacky Wang                       "    @test.ScopeB test.ComponentMedium",
885*f585d8a3SJacky Wang                       "    @test.ScopeA test.ComponentShort"));
886*f585d8a3SJacky Wang             });
887*f585d8a3SJacky Wang 
888*f585d8a3SJacky Wang     // Test that compilation succeeds when transitive validation is disabled because the scope cycle
889*f585d8a3SJacky Wang     // cannot be detected.
890*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(type, scopeA, scopeB, longLifetime, mediumLifetime, shortLifetime)
891*f585d8a3SJacky Wang         .withProcessingOptions(
892*f585d8a3SJacky Wang             ImmutableMap.of("dagger.validateTransitiveComponentDependencies", "DISABLED"))
893*f585d8a3SJacky Wang         .compile(subject -> subject.hasErrorCount(0));
894*f585d8a3SJacky Wang   }
895*f585d8a3SJacky Wang 
896*f585d8a3SJacky Wang   @Test
reusableNotAllowedOnComponent()897*f585d8a3SJacky Wang   public void reusableNotAllowedOnComponent() {
898*f585d8a3SJacky Wang     Source someComponent =
899*f585d8a3SJacky Wang         CompilerTests.javaSource(
900*f585d8a3SJacky Wang             "test.SomeComponent",
901*f585d8a3SJacky Wang             "package test;",
902*f585d8a3SJacky Wang             "",
903*f585d8a3SJacky Wang             "import dagger.Component;",
904*f585d8a3SJacky Wang             "import dagger.Reusable;",
905*f585d8a3SJacky Wang             "",
906*f585d8a3SJacky Wang             "@Reusable",
907*f585d8a3SJacky Wang             "@Component",
908*f585d8a3SJacky Wang             "interface SomeComponent {}");
909*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(someComponent)
910*f585d8a3SJacky Wang         .compile(
911*f585d8a3SJacky Wang             subject -> {
912*f585d8a3SJacky Wang               subject.hasErrorCount(1);
913*f585d8a3SJacky Wang               subject.hasErrorContaining(
914*f585d8a3SJacky Wang                       "@Reusable cannot be applied to components or subcomponents")
915*f585d8a3SJacky Wang                   .onSource(someComponent)
916*f585d8a3SJacky Wang                   .onLine(6);
917*f585d8a3SJacky Wang             });
918*f585d8a3SJacky Wang   }
919*f585d8a3SJacky Wang 
920*f585d8a3SJacky Wang   @Test
reusableNotAllowedOnSubcomponent()921*f585d8a3SJacky Wang   public void reusableNotAllowedOnSubcomponent() {
922*f585d8a3SJacky Wang     Source someSubcomponent =
923*f585d8a3SJacky Wang         CompilerTests.javaSource(
924*f585d8a3SJacky Wang             "test.SomeComponent",
925*f585d8a3SJacky Wang             "package test;",
926*f585d8a3SJacky Wang             "",
927*f585d8a3SJacky Wang             "import dagger.Reusable;",
928*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
929*f585d8a3SJacky Wang             "",
930*f585d8a3SJacky Wang             "@Reusable",
931*f585d8a3SJacky Wang             "@Subcomponent",
932*f585d8a3SJacky Wang             "interface SomeSubcomponent {}");
933*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(someSubcomponent)
934*f585d8a3SJacky Wang         .compile(
935*f585d8a3SJacky Wang             subject -> {
936*f585d8a3SJacky Wang               subject.hasErrorCount(1);
937*f585d8a3SJacky Wang               subject.hasErrorContaining(
938*f585d8a3SJacky Wang                       "@Reusable cannot be applied to components or subcomponents")
939*f585d8a3SJacky Wang                   .onSource(someSubcomponent)
940*f585d8a3SJacky Wang                   .onLine(6);
941*f585d8a3SJacky Wang             });
942*f585d8a3SJacky Wang   }
943*f585d8a3SJacky Wang }
944