xref: /aosp_15_r20/external/dagger2/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1*f585d8a3SJacky Wang /*
2*f585d8a3SJacky Wang  * Copyright (C) 2018 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 static com.google.testing.compile.CompilationSubject.assertThat;
20*f585d8a3SJacky Wang import static dagger.internal.codegen.Compilers.compilerWithOptions;
21*f585d8a3SJacky Wang import static dagger.internal.codegen.TestUtils.endsWithMessage;
22*f585d8a3SJacky Wang 
23*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source;
24*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList;
25*f585d8a3SJacky Wang import com.google.testing.compile.Compilation;
26*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests;
27*f585d8a3SJacky Wang import java.util.regex.Pattern;
28*f585d8a3SJacky Wang import org.junit.Test;
29*f585d8a3SJacky Wang import org.junit.runner.RunWith;
30*f585d8a3SJacky Wang import org.junit.runners.Parameterized;
31*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters;
32*f585d8a3SJacky Wang 
33*f585d8a3SJacky Wang @RunWith(Parameterized.class)
34*f585d8a3SJacky Wang public class DependencyCycleValidationTest {
35*f585d8a3SJacky Wang   @Parameters(name = "{0}")
parameters()36*f585d8a3SJacky Wang   public static ImmutableList<Object[]> parameters() {
37*f585d8a3SJacky Wang     return CompilerMode.TEST_PARAMETERS;
38*f585d8a3SJacky Wang   }
39*f585d8a3SJacky Wang 
40*f585d8a3SJacky Wang   private final CompilerMode compilerMode;
41*f585d8a3SJacky Wang 
DependencyCycleValidationTest(CompilerMode compilerMode)42*f585d8a3SJacky Wang   public DependencyCycleValidationTest(CompilerMode compilerMode) {
43*f585d8a3SJacky Wang     this.compilerMode = compilerMode;
44*f585d8a3SJacky Wang   }
45*f585d8a3SJacky Wang 
46*f585d8a3SJacky Wang   private static final Source SIMPLE_CYCLIC_DEPENDENCY =
47*f585d8a3SJacky Wang         CompilerTests.javaSource(
48*f585d8a3SJacky Wang           "test.Outer",
49*f585d8a3SJacky Wang           "package test;",
50*f585d8a3SJacky Wang           "",
51*f585d8a3SJacky Wang           "import dagger.Binds;",
52*f585d8a3SJacky Wang           "import dagger.Component;",
53*f585d8a3SJacky Wang           "import dagger.Module;",
54*f585d8a3SJacky Wang           "import dagger.Provides;",
55*f585d8a3SJacky Wang           "import javax.inject.Inject;",
56*f585d8a3SJacky Wang           "",
57*f585d8a3SJacky Wang           "final class Outer {",
58*f585d8a3SJacky Wang           "  static class A {",
59*f585d8a3SJacky Wang           "    @Inject A(C cParam) {}",
60*f585d8a3SJacky Wang           "  }",
61*f585d8a3SJacky Wang           "",
62*f585d8a3SJacky Wang           "  static class B {",
63*f585d8a3SJacky Wang           "    @Inject B(A aParam) {}",
64*f585d8a3SJacky Wang           "  }",
65*f585d8a3SJacky Wang           "",
66*f585d8a3SJacky Wang           "  static class C {",
67*f585d8a3SJacky Wang           "    @Inject C(B bParam) {}",
68*f585d8a3SJacky Wang           "  }",
69*f585d8a3SJacky Wang           "",
70*f585d8a3SJacky Wang           "  @Module",
71*f585d8a3SJacky Wang           "  interface MModule {",
72*f585d8a3SJacky Wang           "    @Binds Object object(C c);",
73*f585d8a3SJacky Wang           "  }",
74*f585d8a3SJacky Wang           "",
75*f585d8a3SJacky Wang           "  @Component",
76*f585d8a3SJacky Wang           "  interface CComponent {",
77*f585d8a3SJacky Wang           "    C getC();",
78*f585d8a3SJacky Wang           "  }",
79*f585d8a3SJacky Wang           "}");
80*f585d8a3SJacky Wang 
81*f585d8a3SJacky Wang   @Test
cyclicDependency()82*f585d8a3SJacky Wang   public void cyclicDependency() {
83*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(SIMPLE_CYCLIC_DEPENDENCY)
84*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
85*f585d8a3SJacky Wang         .compile(
86*f585d8a3SJacky Wang             subject -> {
87*f585d8a3SJacky Wang               subject.hasErrorCount(1);
88*f585d8a3SJacky Wang               subject.hasErrorContaining(
89*f585d8a3SJacky Wang                       String.join(
90*f585d8a3SJacky Wang                           "\n",
91*f585d8a3SJacky Wang                           "Found a dependency cycle:",
92*f585d8a3SJacky Wang                           "    Outer.C is injected at",
93*f585d8a3SJacky Wang                           "        Outer.A(cParam)",
94*f585d8a3SJacky Wang                           "    Outer.A is injected at",
95*f585d8a3SJacky Wang                           "        Outer.B(aParam)",
96*f585d8a3SJacky Wang                           "    Outer.B is injected at",
97*f585d8a3SJacky Wang                           "        Outer.C(bParam)",
98*f585d8a3SJacky Wang                           "    Outer.C is injected at",
99*f585d8a3SJacky Wang                           "        Outer.A(cParam)",
100*f585d8a3SJacky Wang                           "    ...",
101*f585d8a3SJacky Wang                           "",
102*f585d8a3SJacky Wang                           "The cycle is requested via:",
103*f585d8a3SJacky Wang                           "    Outer.C is requested at",
104*f585d8a3SJacky Wang                           "        Outer.CComponent.getC()"))
105*f585d8a3SJacky Wang                   .onSource(SIMPLE_CYCLIC_DEPENDENCY)
106*f585d8a3SJacky Wang                   .onLineContaining("interface CComponent");
107*f585d8a3SJacky Wang             });
108*f585d8a3SJacky Wang   }
109*f585d8a3SJacky Wang 
110*f585d8a3SJacky Wang   // TODO(b/243720787): Requires CompilationResultSubject#hasErrorContainingMatch()
111*f585d8a3SJacky Wang   @Test
cyclicDependencyWithModuleBindingValidation()112*f585d8a3SJacky Wang   public void cyclicDependencyWithModuleBindingValidation() {
113*f585d8a3SJacky Wang     // Cycle errors should not show a dependency trace to an entry point when doing full binding
114*f585d8a3SJacky Wang     // graph validation. So ensure that the message doesn't end with "test.Outer.C is requested at
115*f585d8a3SJacky Wang     // test.Outer.CComponent.getC()", as the previous test's message does.
116*f585d8a3SJacky Wang     Pattern moduleBindingValidationError =
117*f585d8a3SJacky Wang         endsWithMessage(
118*f585d8a3SJacky Wang             "Found a dependency cycle:",
119*f585d8a3SJacky Wang             "    Outer.C is injected at",
120*f585d8a3SJacky Wang             "        Outer.A(cParam)",
121*f585d8a3SJacky Wang             "    Outer.A is injected at",
122*f585d8a3SJacky Wang             "        Outer.B(aParam)",
123*f585d8a3SJacky Wang             "    Outer.B is injected at",
124*f585d8a3SJacky Wang             "        Outer.C(bParam)",
125*f585d8a3SJacky Wang             "    Outer.C is injected at",
126*f585d8a3SJacky Wang             "        Outer.A(cParam)",
127*f585d8a3SJacky Wang             "    ...",
128*f585d8a3SJacky Wang             "",
129*f585d8a3SJacky Wang             "======================",
130*f585d8a3SJacky Wang             "Full classname legend:",
131*f585d8a3SJacky Wang             "======================",
132*f585d8a3SJacky Wang             "Outer: test.Outer",
133*f585d8a3SJacky Wang             "========================",
134*f585d8a3SJacky Wang             "End of classname legend:",
135*f585d8a3SJacky Wang             "========================");
136*f585d8a3SJacky Wang 
137*f585d8a3SJacky Wang     Compilation compilation =
138*f585d8a3SJacky Wang         compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
139*f585d8a3SJacky Wang             .compile(SIMPLE_CYCLIC_DEPENDENCY.toJFO());
140*f585d8a3SJacky Wang     assertThat(compilation).failed();
141*f585d8a3SJacky Wang 
142*f585d8a3SJacky Wang     assertThat(compilation)
143*f585d8a3SJacky Wang         .hadErrorContainingMatch(moduleBindingValidationError)
144*f585d8a3SJacky Wang         .inFile(SIMPLE_CYCLIC_DEPENDENCY.toJFO())
145*f585d8a3SJacky Wang         .onLineContaining("interface MModule");
146*f585d8a3SJacky Wang 
147*f585d8a3SJacky Wang     assertThat(compilation)
148*f585d8a3SJacky Wang         .hadErrorContainingMatch(moduleBindingValidationError)
149*f585d8a3SJacky Wang         .inFile(SIMPLE_CYCLIC_DEPENDENCY.toJFO())
150*f585d8a3SJacky Wang         .onLineContaining("interface CComponent");
151*f585d8a3SJacky Wang 
152*f585d8a3SJacky Wang     assertThat(compilation).hadErrorCount(2);
153*f585d8a3SJacky Wang   }
154*f585d8a3SJacky Wang 
cyclicDependencyNotIncludingEntryPoint()155*f585d8a3SJacky Wang   @Test public void cyclicDependencyNotIncludingEntryPoint() {
156*f585d8a3SJacky Wang     Source component =
157*f585d8a3SJacky Wang         CompilerTests.javaSource(
158*f585d8a3SJacky Wang             "test.Outer",
159*f585d8a3SJacky Wang             "package test;",
160*f585d8a3SJacky Wang             "",
161*f585d8a3SJacky Wang             "import dagger.Component;",
162*f585d8a3SJacky Wang             "import dagger.Module;",
163*f585d8a3SJacky Wang             "import dagger.Provides;",
164*f585d8a3SJacky Wang             "import javax.inject.Inject;",
165*f585d8a3SJacky Wang             "",
166*f585d8a3SJacky Wang             "final class Outer {",
167*f585d8a3SJacky Wang             "  static class A {",
168*f585d8a3SJacky Wang             "    @Inject A(C cParam) {}",
169*f585d8a3SJacky Wang             "  }",
170*f585d8a3SJacky Wang             "",
171*f585d8a3SJacky Wang             "  static class B {",
172*f585d8a3SJacky Wang             "    @Inject B(A aParam) {}",
173*f585d8a3SJacky Wang             "  }",
174*f585d8a3SJacky Wang             "",
175*f585d8a3SJacky Wang             "  static class C {",
176*f585d8a3SJacky Wang             "    @Inject C(B bParam) {}",
177*f585d8a3SJacky Wang             "  }",
178*f585d8a3SJacky Wang             "",
179*f585d8a3SJacky Wang             "  static class D {",
180*f585d8a3SJacky Wang             "    @Inject D(C cParam) {}",
181*f585d8a3SJacky Wang             "  }",
182*f585d8a3SJacky Wang             "",
183*f585d8a3SJacky Wang             "  @Component",
184*f585d8a3SJacky Wang             "  interface DComponent {",
185*f585d8a3SJacky Wang             "    D getD();",
186*f585d8a3SJacky Wang             "  }",
187*f585d8a3SJacky Wang             "}");
188*f585d8a3SJacky Wang 
189*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
190*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
191*f585d8a3SJacky Wang         .compile(
192*f585d8a3SJacky Wang             subject -> {
193*f585d8a3SJacky Wang               subject.hasErrorCount(1);
194*f585d8a3SJacky Wang               subject.hasErrorContaining(
195*f585d8a3SJacky Wang                       String.join(
196*f585d8a3SJacky Wang                           "\n",
197*f585d8a3SJacky Wang                           "Found a dependency cycle:",
198*f585d8a3SJacky Wang                           "    Outer.C is injected at",
199*f585d8a3SJacky Wang                           "        Outer.A(cParam)",
200*f585d8a3SJacky Wang                           "    Outer.A is injected at",
201*f585d8a3SJacky Wang                           "        Outer.B(aParam)",
202*f585d8a3SJacky Wang                           "    Outer.B is injected at",
203*f585d8a3SJacky Wang                           "        Outer.C(bParam)",
204*f585d8a3SJacky Wang                           "    Outer.C is injected at",
205*f585d8a3SJacky Wang                           "        Outer.A(cParam)",
206*f585d8a3SJacky Wang                           "   ...",
207*f585d8a3SJacky Wang                           "",
208*f585d8a3SJacky Wang                           "The cycle is requested via:",
209*f585d8a3SJacky Wang                           "    Outer.C is injected at",
210*f585d8a3SJacky Wang                           "        Outer.D(cParam)",
211*f585d8a3SJacky Wang                           "    Outer.D is requested at",
212*f585d8a3SJacky Wang                           "        Outer.DComponent.getD()"))
213*f585d8a3SJacky Wang                   .onSource(component)
214*f585d8a3SJacky Wang                   .onLineContaining("interface DComponent");
215*f585d8a3SJacky Wang             });
216*f585d8a3SJacky Wang   }
217*f585d8a3SJacky Wang 
218*f585d8a3SJacky Wang   @Test
cyclicDependencyNotBrokenByMapBinding()219*f585d8a3SJacky Wang   public void cyclicDependencyNotBrokenByMapBinding() {
220*f585d8a3SJacky Wang     Source component =
221*f585d8a3SJacky Wang         CompilerTests.javaSource(
222*f585d8a3SJacky Wang             "test.Outer",
223*f585d8a3SJacky Wang             "package test;",
224*f585d8a3SJacky Wang             "",
225*f585d8a3SJacky Wang             "import dagger.Component;",
226*f585d8a3SJacky Wang             "import dagger.Module;",
227*f585d8a3SJacky Wang             "import dagger.Provides;",
228*f585d8a3SJacky Wang             "import dagger.multibindings.IntoMap;",
229*f585d8a3SJacky Wang             "import dagger.multibindings.StringKey;",
230*f585d8a3SJacky Wang             "import java.util.Map;",
231*f585d8a3SJacky Wang             "import javax.inject.Inject;",
232*f585d8a3SJacky Wang             "",
233*f585d8a3SJacky Wang             "final class Outer {",
234*f585d8a3SJacky Wang             "  static class A {",
235*f585d8a3SJacky Wang             "    @Inject A(Map<String, C> cMap) {}",
236*f585d8a3SJacky Wang             "  }",
237*f585d8a3SJacky Wang             "",
238*f585d8a3SJacky Wang             "  static class B {",
239*f585d8a3SJacky Wang             "    @Inject B(A aParam) {}",
240*f585d8a3SJacky Wang             "  }",
241*f585d8a3SJacky Wang             "",
242*f585d8a3SJacky Wang             "  static class C {",
243*f585d8a3SJacky Wang             "    @Inject C(B bParam) {}",
244*f585d8a3SJacky Wang             "  }",
245*f585d8a3SJacky Wang             "",
246*f585d8a3SJacky Wang             "  @Component(modules = CModule.class)",
247*f585d8a3SJacky Wang             "  interface CComponent {",
248*f585d8a3SJacky Wang             "    C getC();",
249*f585d8a3SJacky Wang             "  }",
250*f585d8a3SJacky Wang             "",
251*f585d8a3SJacky Wang             "  @Module",
252*f585d8a3SJacky Wang             "  static class CModule {",
253*f585d8a3SJacky Wang             "    @Provides @IntoMap",
254*f585d8a3SJacky Wang             "    @StringKey(\"C\")",
255*f585d8a3SJacky Wang             "    static C c(C c) {",
256*f585d8a3SJacky Wang             "      return c;",
257*f585d8a3SJacky Wang             "    }",
258*f585d8a3SJacky Wang             "  }",
259*f585d8a3SJacky Wang             "}");
260*f585d8a3SJacky Wang 
261*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
262*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
263*f585d8a3SJacky Wang         .compile(
264*f585d8a3SJacky Wang             subject -> {
265*f585d8a3SJacky Wang               subject.hasErrorCount(1);
266*f585d8a3SJacky Wang               subject.hasErrorContaining(
267*f585d8a3SJacky Wang                       String.join(
268*f585d8a3SJacky Wang                           "\n",
269*f585d8a3SJacky Wang                           "Found a dependency cycle:",
270*f585d8a3SJacky Wang                           "    Outer.C is injected at",
271*f585d8a3SJacky Wang                           "        Outer.CModule.c(c)",
272*f585d8a3SJacky Wang                           "    Map<String,Outer.C> is injected at",
273*f585d8a3SJacky Wang                           "        Outer.A(cMap)",
274*f585d8a3SJacky Wang                           "    Outer.A is injected at",
275*f585d8a3SJacky Wang                           "        Outer.B(aParam)",
276*f585d8a3SJacky Wang                           "    Outer.B is injected at",
277*f585d8a3SJacky Wang                           "        Outer.C(bParam)",
278*f585d8a3SJacky Wang                           "    Outer.C is injected at",
279*f585d8a3SJacky Wang                           "        Outer.CModule.c(c)",
280*f585d8a3SJacky Wang                           "   ...",
281*f585d8a3SJacky Wang                           "",
282*f585d8a3SJacky Wang                           "The cycle is requested via:",
283*f585d8a3SJacky Wang                           "    Outer.C is requested at",
284*f585d8a3SJacky Wang                           "        Outer.CComponent.getC()"))
285*f585d8a3SJacky Wang                   .onSource(component)
286*f585d8a3SJacky Wang                   .onLineContaining("interface CComponent");
287*f585d8a3SJacky Wang             });
288*f585d8a3SJacky Wang   }
289*f585d8a3SJacky Wang 
290*f585d8a3SJacky Wang   @Test
cyclicDependencyWithSetBinding()291*f585d8a3SJacky Wang   public void cyclicDependencyWithSetBinding() {
292*f585d8a3SJacky Wang     Source component =
293*f585d8a3SJacky Wang         CompilerTests.javaSource(
294*f585d8a3SJacky Wang             "test.Outer",
295*f585d8a3SJacky Wang             "package test;",
296*f585d8a3SJacky Wang             "",
297*f585d8a3SJacky Wang             "import dagger.Component;",
298*f585d8a3SJacky Wang             "import dagger.Module;",
299*f585d8a3SJacky Wang             "import dagger.Provides;",
300*f585d8a3SJacky Wang             "import dagger.multibindings.IntoSet;",
301*f585d8a3SJacky Wang             "import java.util.Set;",
302*f585d8a3SJacky Wang             "import javax.inject.Inject;",
303*f585d8a3SJacky Wang             "",
304*f585d8a3SJacky Wang             "final class Outer {",
305*f585d8a3SJacky Wang             "  static class A {",
306*f585d8a3SJacky Wang             "    @Inject A(Set<C> cSet) {}",
307*f585d8a3SJacky Wang             "  }",
308*f585d8a3SJacky Wang             "",
309*f585d8a3SJacky Wang             "  static class B {",
310*f585d8a3SJacky Wang             "    @Inject B(A aParam) {}",
311*f585d8a3SJacky Wang             "  }",
312*f585d8a3SJacky Wang             "",
313*f585d8a3SJacky Wang             "  static class C {",
314*f585d8a3SJacky Wang             "    @Inject C(B bParam) {}",
315*f585d8a3SJacky Wang             "  }",
316*f585d8a3SJacky Wang             "",
317*f585d8a3SJacky Wang             "  @Component(modules = CModule.class)",
318*f585d8a3SJacky Wang             "  interface CComponent {",
319*f585d8a3SJacky Wang             "    C getC();",
320*f585d8a3SJacky Wang             "  }",
321*f585d8a3SJacky Wang             "",
322*f585d8a3SJacky Wang             "  @Module",
323*f585d8a3SJacky Wang             "  static class CModule {",
324*f585d8a3SJacky Wang             "    @Provides @IntoSet",
325*f585d8a3SJacky Wang             "    static C c(C c) {",
326*f585d8a3SJacky Wang             "      return c;",
327*f585d8a3SJacky Wang             "    }",
328*f585d8a3SJacky Wang             "  }",
329*f585d8a3SJacky Wang             "}");
330*f585d8a3SJacky Wang 
331*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
332*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
333*f585d8a3SJacky Wang         .compile(
334*f585d8a3SJacky Wang             subject -> {
335*f585d8a3SJacky Wang               subject.hasErrorCount(1);
336*f585d8a3SJacky Wang               subject.hasErrorContaining(
337*f585d8a3SJacky Wang                       String.join(
338*f585d8a3SJacky Wang                           "\n",
339*f585d8a3SJacky Wang                           "Found a dependency cycle:",
340*f585d8a3SJacky Wang                           "    Outer.C is injected at",
341*f585d8a3SJacky Wang                           "        Outer.CModule.c(c)",
342*f585d8a3SJacky Wang                           "    Set<Outer.C> is injected at",
343*f585d8a3SJacky Wang                           "        Outer.A(cSet)",
344*f585d8a3SJacky Wang                           "    Outer.A is injected at",
345*f585d8a3SJacky Wang                           "        Outer.B(aParam)",
346*f585d8a3SJacky Wang                           "    Outer.B is injected at",
347*f585d8a3SJacky Wang                           "        Outer.C(bParam)",
348*f585d8a3SJacky Wang                           "    Outer.C is injected at",
349*f585d8a3SJacky Wang                           "        Outer.CModule.c(c)",
350*f585d8a3SJacky Wang                           "   ...",
351*f585d8a3SJacky Wang                           "",
352*f585d8a3SJacky Wang                           "The cycle is requested via:",
353*f585d8a3SJacky Wang                           "    Outer.C is requested at",
354*f585d8a3SJacky Wang                           "        Outer.CComponent.getC()"))
355*f585d8a3SJacky Wang                   .onSource(component)
356*f585d8a3SJacky Wang                   .onLineContaining("interface CComponent");
357*f585d8a3SJacky Wang             });
358*f585d8a3SJacky Wang   }
359*f585d8a3SJacky Wang 
360*f585d8a3SJacky Wang   @Test
falsePositiveCyclicDependencyIndirectionDetected()361*f585d8a3SJacky Wang   public void falsePositiveCyclicDependencyIndirectionDetected() {
362*f585d8a3SJacky Wang     Source component =
363*f585d8a3SJacky Wang         CompilerTests.javaSource(
364*f585d8a3SJacky Wang             "test.Outer",
365*f585d8a3SJacky Wang             "package test;",
366*f585d8a3SJacky Wang             "",
367*f585d8a3SJacky Wang             "import dagger.Component;",
368*f585d8a3SJacky Wang             "import dagger.Module;",
369*f585d8a3SJacky Wang             "import dagger.Provides;",
370*f585d8a3SJacky Wang             "import javax.inject.Inject;",
371*f585d8a3SJacky Wang             "import javax.inject.Provider;",
372*f585d8a3SJacky Wang             "",
373*f585d8a3SJacky Wang             "final class Outer {",
374*f585d8a3SJacky Wang             "  static class A {",
375*f585d8a3SJacky Wang             "    @Inject A(C cParam) {}",
376*f585d8a3SJacky Wang             "  }",
377*f585d8a3SJacky Wang             "",
378*f585d8a3SJacky Wang             "  static class B {",
379*f585d8a3SJacky Wang             "    @Inject B(A aParam) {}",
380*f585d8a3SJacky Wang             "  }",
381*f585d8a3SJacky Wang             "",
382*f585d8a3SJacky Wang             "  static class C {",
383*f585d8a3SJacky Wang             "    @Inject C(B bParam) {}",
384*f585d8a3SJacky Wang             "  }",
385*f585d8a3SJacky Wang             "",
386*f585d8a3SJacky Wang             "  static class D {",
387*f585d8a3SJacky Wang             "    @Inject D(Provider<C> cParam) {}",
388*f585d8a3SJacky Wang             "  }",
389*f585d8a3SJacky Wang             "",
390*f585d8a3SJacky Wang             "  @Component",
391*f585d8a3SJacky Wang             "  interface DComponent {",
392*f585d8a3SJacky Wang             "    D getD();",
393*f585d8a3SJacky Wang             "  }",
394*f585d8a3SJacky Wang             "}");
395*f585d8a3SJacky Wang 
396*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
397*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
398*f585d8a3SJacky Wang         .compile(
399*f585d8a3SJacky Wang             subject -> {
400*f585d8a3SJacky Wang               subject.hasErrorCount(1);
401*f585d8a3SJacky Wang               subject.hasErrorContaining(
402*f585d8a3SJacky Wang                       String.join(
403*f585d8a3SJacky Wang                           "\n",
404*f585d8a3SJacky Wang                           "Found a dependency cycle:",
405*f585d8a3SJacky Wang                           "    Outer.C is injected at",
406*f585d8a3SJacky Wang                           "        Outer.A(cParam)",
407*f585d8a3SJacky Wang                           "    Outer.A is injected at",
408*f585d8a3SJacky Wang                           "        Outer.B(aParam)",
409*f585d8a3SJacky Wang                           "    Outer.B is injected at",
410*f585d8a3SJacky Wang                           "        Outer.C(bParam)",
411*f585d8a3SJacky Wang                           "    Outer.C is injected at",
412*f585d8a3SJacky Wang                           "        Outer.A(cParam)",
413*f585d8a3SJacky Wang                           "   ...",
414*f585d8a3SJacky Wang                           "",
415*f585d8a3SJacky Wang                           "The cycle is requested via:",
416*f585d8a3SJacky Wang                           "    Provider<Outer.C> is injected at",
417*f585d8a3SJacky Wang                           "        Outer.D(cParam)",
418*f585d8a3SJacky Wang                           "    Outer.D is requested at",
419*f585d8a3SJacky Wang                           "        Outer.DComponent.getD()"))
420*f585d8a3SJacky Wang                   .onSource(component)
421*f585d8a3SJacky Wang                   .onLineContaining("interface DComponent");
422*f585d8a3SJacky Wang             });
423*f585d8a3SJacky Wang   }
424*f585d8a3SJacky Wang 
425*f585d8a3SJacky Wang   @Test
cyclicDependencyInSubcomponents()426*f585d8a3SJacky Wang   public void cyclicDependencyInSubcomponents() {
427*f585d8a3SJacky Wang     Source parent =
428*f585d8a3SJacky Wang         CompilerTests.javaSource(
429*f585d8a3SJacky Wang             "test.Parent",
430*f585d8a3SJacky Wang             "package test;",
431*f585d8a3SJacky Wang             "",
432*f585d8a3SJacky Wang             "import dagger.Component;",
433*f585d8a3SJacky Wang             "",
434*f585d8a3SJacky Wang             "@Component",
435*f585d8a3SJacky Wang             "interface Parent {",
436*f585d8a3SJacky Wang             "  Child.Builder child();",
437*f585d8a3SJacky Wang             "}");
438*f585d8a3SJacky Wang     Source child =
439*f585d8a3SJacky Wang         CompilerTests.javaSource(
440*f585d8a3SJacky Wang             "test.Child",
441*f585d8a3SJacky Wang             "package test;",
442*f585d8a3SJacky Wang             "",
443*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
444*f585d8a3SJacky Wang             "",
445*f585d8a3SJacky Wang             "@Subcomponent(modules = CycleModule.class)",
446*f585d8a3SJacky Wang             "interface Child {",
447*f585d8a3SJacky Wang             "  Grandchild.Builder grandchild();",
448*f585d8a3SJacky Wang             "",
449*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
450*f585d8a3SJacky Wang             "  interface Builder {",
451*f585d8a3SJacky Wang             "    Child build();",
452*f585d8a3SJacky Wang             "  }",
453*f585d8a3SJacky Wang             "}");
454*f585d8a3SJacky Wang     Source grandchild =
455*f585d8a3SJacky Wang         CompilerTests.javaSource(
456*f585d8a3SJacky Wang             "test.Grandchild",
457*f585d8a3SJacky Wang             "package test;",
458*f585d8a3SJacky Wang             "",
459*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
460*f585d8a3SJacky Wang             "",
461*f585d8a3SJacky Wang             "@Subcomponent",
462*f585d8a3SJacky Wang             "interface Grandchild {",
463*f585d8a3SJacky Wang             "  String entry();",
464*f585d8a3SJacky Wang             "",
465*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
466*f585d8a3SJacky Wang             "  interface Builder {",
467*f585d8a3SJacky Wang             "    Grandchild build();",
468*f585d8a3SJacky Wang             "  }",
469*f585d8a3SJacky Wang             "}");
470*f585d8a3SJacky Wang     Source cycleModule =
471*f585d8a3SJacky Wang         CompilerTests.javaSource(
472*f585d8a3SJacky Wang             "test.CycleModule",
473*f585d8a3SJacky Wang             "package test;",
474*f585d8a3SJacky Wang             "",
475*f585d8a3SJacky Wang             "import dagger.Module;",
476*f585d8a3SJacky Wang             "import dagger.Provides;",
477*f585d8a3SJacky Wang             "",
478*f585d8a3SJacky Wang             "@Module",
479*f585d8a3SJacky Wang             "abstract class CycleModule {",
480*f585d8a3SJacky Wang             "  @Provides static Object object(String string) {",
481*f585d8a3SJacky Wang             "    return string;",
482*f585d8a3SJacky Wang             "  }",
483*f585d8a3SJacky Wang             "",
484*f585d8a3SJacky Wang             "  @Provides static String string(Object object) {",
485*f585d8a3SJacky Wang             "    return object.toString();",
486*f585d8a3SJacky Wang             "  }",
487*f585d8a3SJacky Wang             "}");
488*f585d8a3SJacky Wang 
489*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(parent, child, grandchild, cycleModule)
490*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
491*f585d8a3SJacky Wang         .compile(
492*f585d8a3SJacky Wang             subject -> {
493*f585d8a3SJacky Wang               subject.hasErrorCount(1);
494*f585d8a3SJacky Wang               subject.hasErrorContaining(
495*f585d8a3SJacky Wang                       String.join(
496*f585d8a3SJacky Wang                           "\n",
497*f585d8a3SJacky Wang                           "Found a dependency cycle:",
498*f585d8a3SJacky Wang                           "    String is injected at",
499*f585d8a3SJacky Wang                           "        CycleModule.object(string)",
500*f585d8a3SJacky Wang                           "    Object is injected at",
501*f585d8a3SJacky Wang                           "        CycleModule.string(object)",
502*f585d8a3SJacky Wang                           "    String is injected at",
503*f585d8a3SJacky Wang                           "        CycleModule.object(string)",
504*f585d8a3SJacky Wang                           "    ...",
505*f585d8a3SJacky Wang                           "",
506*f585d8a3SJacky Wang                           "The cycle is requested via:",
507*f585d8a3SJacky Wang                           "    String is requested at",
508*f585d8a3SJacky Wang                           "        Grandchild.entry()"))
509*f585d8a3SJacky Wang                   .onSource(parent)
510*f585d8a3SJacky Wang                   .onLineContaining("interface Parent");
511*f585d8a3SJacky Wang             });
512*f585d8a3SJacky Wang   }
513*f585d8a3SJacky Wang 
514*f585d8a3SJacky Wang   @Test
cyclicDependencyInSubcomponentsWithChildren()515*f585d8a3SJacky Wang   public void cyclicDependencyInSubcomponentsWithChildren() {
516*f585d8a3SJacky Wang     Source parent =
517*f585d8a3SJacky Wang         CompilerTests.javaSource(
518*f585d8a3SJacky Wang             "test.Parent",
519*f585d8a3SJacky Wang             "package test;",
520*f585d8a3SJacky Wang             "",
521*f585d8a3SJacky Wang             "import dagger.Component;",
522*f585d8a3SJacky Wang             "",
523*f585d8a3SJacky Wang             "@Component",
524*f585d8a3SJacky Wang             "interface Parent {",
525*f585d8a3SJacky Wang             "  Child.Builder child();",
526*f585d8a3SJacky Wang             "}");
527*f585d8a3SJacky Wang     Source child =
528*f585d8a3SJacky Wang         CompilerTests.javaSource(
529*f585d8a3SJacky Wang             "test.Child",
530*f585d8a3SJacky Wang             "package test;",
531*f585d8a3SJacky Wang             "",
532*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
533*f585d8a3SJacky Wang             "",
534*f585d8a3SJacky Wang             "@Subcomponent(modules = CycleModule.class)",
535*f585d8a3SJacky Wang             "interface Child {",
536*f585d8a3SJacky Wang             "  String entry();",
537*f585d8a3SJacky Wang             "",
538*f585d8a3SJacky Wang             "  Grandchild.Builder grandchild();",
539*f585d8a3SJacky Wang             "",
540*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
541*f585d8a3SJacky Wang             "  interface Builder {",
542*f585d8a3SJacky Wang             "    Child build();",
543*f585d8a3SJacky Wang             "  }",
544*f585d8a3SJacky Wang             "}");
545*f585d8a3SJacky Wang     // Grandchild has no entry point that depends on the cycle. http://b/111317986
546*f585d8a3SJacky Wang     Source grandchild =
547*f585d8a3SJacky Wang         CompilerTests.javaSource(
548*f585d8a3SJacky Wang             "test.Grandchild",
549*f585d8a3SJacky Wang             "package test;",
550*f585d8a3SJacky Wang             "",
551*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
552*f585d8a3SJacky Wang             "",
553*f585d8a3SJacky Wang             "@Subcomponent",
554*f585d8a3SJacky Wang             "interface Grandchild {",
555*f585d8a3SJacky Wang             "",
556*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
557*f585d8a3SJacky Wang             "  interface Builder {",
558*f585d8a3SJacky Wang             "    Grandchild build();",
559*f585d8a3SJacky Wang             "  }",
560*f585d8a3SJacky Wang             "}");
561*f585d8a3SJacky Wang     Source cycleModule =
562*f585d8a3SJacky Wang         CompilerTests.javaSource(
563*f585d8a3SJacky Wang             "test.CycleModule",
564*f585d8a3SJacky Wang             "package test;",
565*f585d8a3SJacky Wang             "",
566*f585d8a3SJacky Wang             "import dagger.Module;",
567*f585d8a3SJacky Wang             "import dagger.Provides;",
568*f585d8a3SJacky Wang             "",
569*f585d8a3SJacky Wang             "@Module",
570*f585d8a3SJacky Wang             "abstract class CycleModule {",
571*f585d8a3SJacky Wang             "  @Provides static Object object(String string) {",
572*f585d8a3SJacky Wang             "    return string;",
573*f585d8a3SJacky Wang             "  }",
574*f585d8a3SJacky Wang             "",
575*f585d8a3SJacky Wang             "  @Provides static String string(Object object) {",
576*f585d8a3SJacky Wang             "    return object.toString();",
577*f585d8a3SJacky Wang             "  }",
578*f585d8a3SJacky Wang             "}");
579*f585d8a3SJacky Wang 
580*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(parent, child, grandchild, cycleModule)
581*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
582*f585d8a3SJacky Wang         .compile(
583*f585d8a3SJacky Wang             subject -> {
584*f585d8a3SJacky Wang               subject.hasErrorCount(1);
585*f585d8a3SJacky Wang               subject.hasErrorContaining(
586*f585d8a3SJacky Wang                       String.join(
587*f585d8a3SJacky Wang                           "\n",
588*f585d8a3SJacky Wang                           "Found a dependency cycle:",
589*f585d8a3SJacky Wang                           "    String is injected at",
590*f585d8a3SJacky Wang                           "        CycleModule.object(string)",
591*f585d8a3SJacky Wang                           "    Object is injected at",
592*f585d8a3SJacky Wang                           "        CycleModule.string(object)",
593*f585d8a3SJacky Wang                           "    String is injected at",
594*f585d8a3SJacky Wang                           "        CycleModule.object(string)",
595*f585d8a3SJacky Wang                           "    ...",
596*f585d8a3SJacky Wang                           "",
597*f585d8a3SJacky Wang                           "The cycle is requested via:",
598*f585d8a3SJacky Wang                           "    String is requested at",
599*f585d8a3SJacky Wang                           "        Child.entry() [Parent → Child]"))
600*f585d8a3SJacky Wang                   .onSource(parent)
601*f585d8a3SJacky Wang                   .onLineContaining("interface Parent");
602*f585d8a3SJacky Wang             });
603*f585d8a3SJacky Wang   }
604*f585d8a3SJacky Wang 
605*f585d8a3SJacky Wang   @Test
circularBindsMethods()606*f585d8a3SJacky Wang   public void circularBindsMethods() {
607*f585d8a3SJacky Wang     Source qualifier =
608*f585d8a3SJacky Wang         CompilerTests.javaSource(
609*f585d8a3SJacky Wang             "test.SomeQualifier",
610*f585d8a3SJacky Wang             "package test;",
611*f585d8a3SJacky Wang             "",
612*f585d8a3SJacky Wang             "import javax.inject.Qualifier;",
613*f585d8a3SJacky Wang             "",
614*f585d8a3SJacky Wang             "@Qualifier @interface SomeQualifier {}");
615*f585d8a3SJacky Wang     Source module =
616*f585d8a3SJacky Wang         CompilerTests.javaSource(
617*f585d8a3SJacky Wang             "test.TestModule",
618*f585d8a3SJacky Wang             "package test;",
619*f585d8a3SJacky Wang             "",
620*f585d8a3SJacky Wang             "import dagger.Binds;",
621*f585d8a3SJacky Wang             "import dagger.Module;",
622*f585d8a3SJacky Wang             "",
623*f585d8a3SJacky Wang             "@Module",
624*f585d8a3SJacky Wang             "abstract class TestModule {",
625*f585d8a3SJacky Wang             "  @Binds abstract Object bindUnqualified(@SomeQualifier Object qualified);",
626*f585d8a3SJacky Wang             "  @Binds @SomeQualifier abstract Object bindQualified(Object unqualified);",
627*f585d8a3SJacky Wang             "}");
628*f585d8a3SJacky Wang     Source component =
629*f585d8a3SJacky Wang         CompilerTests.javaSource(
630*f585d8a3SJacky Wang             "test.TestComponent",
631*f585d8a3SJacky Wang             "package test;",
632*f585d8a3SJacky Wang             "",
633*f585d8a3SJacky Wang             "import dagger.Component;",
634*f585d8a3SJacky Wang             "",
635*f585d8a3SJacky Wang             "@Component(modules = TestModule.class)",
636*f585d8a3SJacky Wang             "interface TestComponent {",
637*f585d8a3SJacky Wang             "  Object unqualified();",
638*f585d8a3SJacky Wang             "}");
639*f585d8a3SJacky Wang 
640*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(qualifier, module, component)
641*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
642*f585d8a3SJacky Wang         .compile(
643*f585d8a3SJacky Wang             subject -> {
644*f585d8a3SJacky Wang               subject.hasErrorCount(1);
645*f585d8a3SJacky Wang               subject.hasErrorContaining(
646*f585d8a3SJacky Wang                       String.join(
647*f585d8a3SJacky Wang                           "\n",
648*f585d8a3SJacky Wang                           "Found a dependency cycle:",
649*f585d8a3SJacky Wang                           "    Object is injected at",
650*f585d8a3SJacky Wang                           "        TestModule.bindQualified(unqualified)",
651*f585d8a3SJacky Wang                           "    @SomeQualifier Object is injected at",
652*f585d8a3SJacky Wang                           "        TestModule.bindUnqualified(qualified)",
653*f585d8a3SJacky Wang                           "    Object is injected at",
654*f585d8a3SJacky Wang                           "        TestModule.bindQualified(unqualified)",
655*f585d8a3SJacky Wang                           "    ...",
656*f585d8a3SJacky Wang                           "",
657*f585d8a3SJacky Wang                           "The cycle is requested via:",
658*f585d8a3SJacky Wang                           "    Object is requested at",
659*f585d8a3SJacky Wang                           "        TestComponent.unqualified()"))
660*f585d8a3SJacky Wang                   .onSource(component)
661*f585d8a3SJacky Wang                   .onLineContaining("interface TestComponent");
662*f585d8a3SJacky Wang             });
663*f585d8a3SJacky Wang   }
664*f585d8a3SJacky Wang 
665*f585d8a3SJacky Wang   @Test
selfReferentialBinds()666*f585d8a3SJacky Wang   public void selfReferentialBinds() {
667*f585d8a3SJacky Wang     Source module =
668*f585d8a3SJacky Wang         CompilerTests.javaSource(
669*f585d8a3SJacky Wang             "test.TestModule",
670*f585d8a3SJacky Wang             "package test;",
671*f585d8a3SJacky Wang             "",
672*f585d8a3SJacky Wang             "import dagger.Binds;",
673*f585d8a3SJacky Wang             "import dagger.Module;",
674*f585d8a3SJacky Wang             "",
675*f585d8a3SJacky Wang             "@Module",
676*f585d8a3SJacky Wang             "abstract class TestModule {",
677*f585d8a3SJacky Wang             "  @Binds abstract Object bindToSelf(Object sameKey);",
678*f585d8a3SJacky Wang             "}");
679*f585d8a3SJacky Wang     Source component =
680*f585d8a3SJacky Wang         CompilerTests.javaSource(
681*f585d8a3SJacky Wang             "test.TestComponent",
682*f585d8a3SJacky Wang             "package test;",
683*f585d8a3SJacky Wang             "",
684*f585d8a3SJacky Wang             "import dagger.Component;",
685*f585d8a3SJacky Wang             "",
686*f585d8a3SJacky Wang             "@Component(modules = TestModule.class)",
687*f585d8a3SJacky Wang             "interface TestComponent {",
688*f585d8a3SJacky Wang             "  Object selfReferential();",
689*f585d8a3SJacky Wang             "}");
690*f585d8a3SJacky Wang 
691*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(module, component)
692*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
693*f585d8a3SJacky Wang         .compile(
694*f585d8a3SJacky Wang             subject -> {
695*f585d8a3SJacky Wang               subject.hasErrorCount(1);
696*f585d8a3SJacky Wang               subject.hasErrorContaining(
697*f585d8a3SJacky Wang                       String.join(
698*f585d8a3SJacky Wang                           "\n",
699*f585d8a3SJacky Wang                           "Found a dependency cycle:",
700*f585d8a3SJacky Wang                           "    Object is injected at",
701*f585d8a3SJacky Wang                           "        TestModule.bindToSelf(sameKey)",
702*f585d8a3SJacky Wang                           "    Object is injected at",
703*f585d8a3SJacky Wang                           "        TestModule.bindToSelf(sameKey)",
704*f585d8a3SJacky Wang                           "    ...",
705*f585d8a3SJacky Wang                           "",
706*f585d8a3SJacky Wang                           "The cycle is requested via:",
707*f585d8a3SJacky Wang                           "    Object is requested at",
708*f585d8a3SJacky Wang                           "        TestComponent.selfReferential()"))
709*f585d8a3SJacky Wang                   .onSource(component)
710*f585d8a3SJacky Wang                   .onLineContaining("interface TestComponent");
711*f585d8a3SJacky Wang             });
712*f585d8a3SJacky Wang   }
713*f585d8a3SJacky Wang 
714*f585d8a3SJacky Wang   @Test
cycleFromMembersInjectionMethod_WithSameKeyAsMembersInjectionMethod()715*f585d8a3SJacky Wang   public void cycleFromMembersInjectionMethod_WithSameKeyAsMembersInjectionMethod() {
716*f585d8a3SJacky Wang     Source a =
717*f585d8a3SJacky Wang         CompilerTests.javaSource(
718*f585d8a3SJacky Wang             "test.A",
719*f585d8a3SJacky Wang             "package test;",
720*f585d8a3SJacky Wang             "",
721*f585d8a3SJacky Wang             "import javax.inject.Inject;",
722*f585d8a3SJacky Wang             "",
723*f585d8a3SJacky Wang             "class A {",
724*f585d8a3SJacky Wang             "  @Inject A() {}",
725*f585d8a3SJacky Wang             "  @Inject B b;",
726*f585d8a3SJacky Wang             "}");
727*f585d8a3SJacky Wang     Source b =
728*f585d8a3SJacky Wang         CompilerTests.javaSource(
729*f585d8a3SJacky Wang             "test.B",
730*f585d8a3SJacky Wang             "package test;",
731*f585d8a3SJacky Wang             "",
732*f585d8a3SJacky Wang             "import javax.inject.Inject;",
733*f585d8a3SJacky Wang             "",
734*f585d8a3SJacky Wang             "class B {",
735*f585d8a3SJacky Wang             "  @Inject B() {}",
736*f585d8a3SJacky Wang             "  @Inject A a;",
737*f585d8a3SJacky Wang             "}");
738*f585d8a3SJacky Wang     Source component =
739*f585d8a3SJacky Wang         CompilerTests.javaSource(
740*f585d8a3SJacky Wang             "test.CycleComponent",
741*f585d8a3SJacky Wang             "package test;",
742*f585d8a3SJacky Wang             "",
743*f585d8a3SJacky Wang             "import dagger.Component;",
744*f585d8a3SJacky Wang             "",
745*f585d8a3SJacky Wang             "@Component",
746*f585d8a3SJacky Wang             "interface CycleComponent {",
747*f585d8a3SJacky Wang             "  void inject(A a);",
748*f585d8a3SJacky Wang             "}");
749*f585d8a3SJacky Wang 
750*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(a, b, component)
751*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
752*f585d8a3SJacky Wang         .compile(
753*f585d8a3SJacky Wang             subject -> {
754*f585d8a3SJacky Wang               subject.hasErrorCount(1);
755*f585d8a3SJacky Wang               subject.hasErrorContaining(
756*f585d8a3SJacky Wang                       String.join(
757*f585d8a3SJacky Wang                           "\n",
758*f585d8a3SJacky Wang                           "Found a dependency cycle:",
759*f585d8a3SJacky Wang                           "    test.B is injected at",
760*f585d8a3SJacky Wang                           "        test.A.b",
761*f585d8a3SJacky Wang                           "    test.A is injected at",
762*f585d8a3SJacky Wang                           "        test.B.a",
763*f585d8a3SJacky Wang                           "    test.B is injected at",
764*f585d8a3SJacky Wang                           "        test.A.b",
765*f585d8a3SJacky Wang                           "    ...",
766*f585d8a3SJacky Wang                           "",
767*f585d8a3SJacky Wang                           "The cycle is requested via:",
768*f585d8a3SJacky Wang                           "    test.B is injected at",
769*f585d8a3SJacky Wang                           "        test.A.b",
770*f585d8a3SJacky Wang                           "    test.A is injected at",
771*f585d8a3SJacky Wang                           "        CycleComponent.inject(test.A)"))
772*f585d8a3SJacky Wang                   .onSource(component)
773*f585d8a3SJacky Wang                   .onLineContaining("interface CycleComponent");
774*f585d8a3SJacky Wang             });
775*f585d8a3SJacky Wang   }
776*f585d8a3SJacky Wang 
777*f585d8a3SJacky Wang   @Test
longCycleMaskedByShortBrokenCycles()778*f585d8a3SJacky Wang   public void longCycleMaskedByShortBrokenCycles() {
779*f585d8a3SJacky Wang     Source cycles =
780*f585d8a3SJacky Wang         CompilerTests.javaSource(
781*f585d8a3SJacky Wang             "test.Cycles",
782*f585d8a3SJacky Wang             "package test;",
783*f585d8a3SJacky Wang             "",
784*f585d8a3SJacky Wang             "import javax.inject.Inject;",
785*f585d8a3SJacky Wang             "import javax.inject.Provider;",
786*f585d8a3SJacky Wang             "import dagger.Component;",
787*f585d8a3SJacky Wang             "",
788*f585d8a3SJacky Wang             "final class Cycles {",
789*f585d8a3SJacky Wang             "  static class A {",
790*f585d8a3SJacky Wang             "    @Inject A(Provider<A> aProvider, B b) {}",
791*f585d8a3SJacky Wang             "  }",
792*f585d8a3SJacky Wang             "",
793*f585d8a3SJacky Wang             "  static class B {",
794*f585d8a3SJacky Wang             "    @Inject B(Provider<B> bProvider, A a) {}",
795*f585d8a3SJacky Wang             "  }",
796*f585d8a3SJacky Wang             "",
797*f585d8a3SJacky Wang             "  @Component",
798*f585d8a3SJacky Wang             "  interface C {",
799*f585d8a3SJacky Wang             "    A a();",
800*f585d8a3SJacky Wang             "  }",
801*f585d8a3SJacky Wang             "}");
802*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(cycles)
803*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
804*f585d8a3SJacky Wang         .compile(
805*f585d8a3SJacky Wang             subject -> {
806*f585d8a3SJacky Wang               subject.hasErrorCount(1);
807*f585d8a3SJacky Wang               subject.hasErrorContaining("Found a dependency cycle:")
808*f585d8a3SJacky Wang                   .onSource(cycles)
809*f585d8a3SJacky Wang                   .onLineContaining("interface C");
810*f585d8a3SJacky Wang             });
811*f585d8a3SJacky Wang   }
812*f585d8a3SJacky Wang }
813