xref: /aosp_15_r20/external/dagger2/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.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 dagger.internal.codegen.TestUtils.message;
20*f585d8a3SJacky Wang import static org.junit.Assume.assumeFalse;
21*f585d8a3SJacky Wang 
22*f585d8a3SJacky Wang import androidx.room.compiler.processing.XProcessingEnv;
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.common.collect.ImmutableMap;
26*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests;
27*f585d8a3SJacky Wang import org.junit.Test;
28*f585d8a3SJacky Wang import org.junit.runner.RunWith;
29*f585d8a3SJacky Wang import org.junit.runners.Parameterized;
30*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters;
31*f585d8a3SJacky Wang 
32*f585d8a3SJacky Wang @RunWith(Parameterized.class)
33*f585d8a3SJacky Wang public class DuplicateBindingsValidationTest {
34*f585d8a3SJacky Wang 
35*f585d8a3SJacky Wang   @Parameters(name = "fullBindingGraphValidation={0}")
parameters()36*f585d8a3SJacky Wang   public static ImmutableList<Object[]> parameters() {
37*f585d8a3SJacky Wang     return ImmutableList.copyOf(new Object[][] {{false}, {true}});
38*f585d8a3SJacky Wang   }
39*f585d8a3SJacky Wang 
40*f585d8a3SJacky Wang   private final boolean fullBindingGraphValidation;
41*f585d8a3SJacky Wang 
DuplicateBindingsValidationTest(boolean fullBindingGraphValidation)42*f585d8a3SJacky Wang   public DuplicateBindingsValidationTest(boolean fullBindingGraphValidation) {
43*f585d8a3SJacky Wang     this.fullBindingGraphValidation = fullBindingGraphValidation;
44*f585d8a3SJacky Wang   }
45*f585d8a3SJacky Wang 
duplicateExplicitBindings_ProvidesAndComponentProvision()46*f585d8a3SJacky Wang   @Test public void duplicateExplicitBindings_ProvidesAndComponentProvision() {
47*f585d8a3SJacky Wang     assumeFalse(fullBindingGraphValidation);
48*f585d8a3SJacky Wang 
49*f585d8a3SJacky Wang     Source component =
50*f585d8a3SJacky Wang         CompilerTests.javaSource(
51*f585d8a3SJacky Wang             "test.Outer",
52*f585d8a3SJacky Wang             "package test;",
53*f585d8a3SJacky Wang             "",
54*f585d8a3SJacky Wang             "import dagger.Component;",
55*f585d8a3SJacky Wang             "import dagger.Module;",
56*f585d8a3SJacky Wang             "import dagger.Provides;",
57*f585d8a3SJacky Wang             "",
58*f585d8a3SJacky Wang             "final class Outer {",
59*f585d8a3SJacky Wang             "  interface A {}",
60*f585d8a3SJacky Wang             "",
61*f585d8a3SJacky Wang             "  interface B {}",
62*f585d8a3SJacky Wang             "",
63*f585d8a3SJacky Wang             "  @Module",
64*f585d8a3SJacky Wang             "  static class AModule {",
65*f585d8a3SJacky Wang             "    @Provides String provideString() { return \"\"; }",
66*f585d8a3SJacky Wang             "    @Provides A provideA(String s) { return new A() {}; }",
67*f585d8a3SJacky Wang             "  }",
68*f585d8a3SJacky Wang             "",
69*f585d8a3SJacky Wang             "  @Component(modules = AModule.class)",
70*f585d8a3SJacky Wang             "  interface Parent {",
71*f585d8a3SJacky Wang             "    A getA();",
72*f585d8a3SJacky Wang             "  }",
73*f585d8a3SJacky Wang             "",
74*f585d8a3SJacky Wang             "  @Module",
75*f585d8a3SJacky Wang             "  static class BModule {",
76*f585d8a3SJacky Wang             "    @Provides B provideB(A a) { return new B() {}; }",
77*f585d8a3SJacky Wang             "  }",
78*f585d8a3SJacky Wang             "",
79*f585d8a3SJacky Wang             "  @Component(dependencies = Parent.class, modules = { BModule.class, AModule.class})",
80*f585d8a3SJacky Wang             "  interface Child {",
81*f585d8a3SJacky Wang             "    B getB();",
82*f585d8a3SJacky Wang             "  }",
83*f585d8a3SJacky Wang             "}");
84*f585d8a3SJacky Wang 
85*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
86*f585d8a3SJacky Wang         .withProcessingOptions(
87*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
88*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
89*f585d8a3SJacky Wang                 .buildOrThrow())
90*f585d8a3SJacky Wang         .compile(
91*f585d8a3SJacky Wang             subject -> {
92*f585d8a3SJacky Wang               subject.hasErrorCount(1);
93*f585d8a3SJacky Wang               subject.hasErrorContaining(
94*f585d8a3SJacky Wang                       message(
95*f585d8a3SJacky Wang                           "Outer.A is bound multiple times:",
96*f585d8a3SJacky Wang                           "    @Provides Outer.A Outer.AModule.provideA(String)",
97*f585d8a3SJacky Wang                           "    Outer.A Outer.Parent.getA()"))
98*f585d8a3SJacky Wang                   .onSource(component)
99*f585d8a3SJacky Wang                   .onLineContaining("interface Child");
100*f585d8a3SJacky Wang             });
101*f585d8a3SJacky Wang   }
102*f585d8a3SJacky Wang 
duplicateExplicitBindings_TwoProvidesMethods()103*f585d8a3SJacky Wang   @Test public void duplicateExplicitBindings_TwoProvidesMethods() {
104*f585d8a3SJacky Wang     Source component =
105*f585d8a3SJacky Wang         CompilerTests.javaSource(
106*f585d8a3SJacky Wang             "test.Outer",
107*f585d8a3SJacky Wang             "package test;",
108*f585d8a3SJacky Wang             "",
109*f585d8a3SJacky Wang             "import dagger.Component;",
110*f585d8a3SJacky Wang             "import dagger.Module;",
111*f585d8a3SJacky Wang             "import dagger.Provides;",
112*f585d8a3SJacky Wang             "import javax.inject.Inject;",
113*f585d8a3SJacky Wang             "",
114*f585d8a3SJacky Wang             "final class Outer {",
115*f585d8a3SJacky Wang             "  interface A {}",
116*f585d8a3SJacky Wang             "",
117*f585d8a3SJacky Wang             "  static class B {",
118*f585d8a3SJacky Wang             "    @Inject B(A a) {}",
119*f585d8a3SJacky Wang             "  }",
120*f585d8a3SJacky Wang             "",
121*f585d8a3SJacky Wang             "  @Module",
122*f585d8a3SJacky Wang             "  static class Module1 {",
123*f585d8a3SJacky Wang             "    @Provides A provideA1() { return new A() {}; }",
124*f585d8a3SJacky Wang             "  }",
125*f585d8a3SJacky Wang             "",
126*f585d8a3SJacky Wang             "  @Module",
127*f585d8a3SJacky Wang             "  static class Module2 {",
128*f585d8a3SJacky Wang             "    @Provides String provideString() { return \"\"; }",
129*f585d8a3SJacky Wang             "    @Provides A provideA2(String s) { return new A() {}; }",
130*f585d8a3SJacky Wang             "  }",
131*f585d8a3SJacky Wang             "",
132*f585d8a3SJacky Wang             "  @Module(includes = { Module1.class, Module2.class})",
133*f585d8a3SJacky Wang             "  abstract static class Module3 {}",
134*f585d8a3SJacky Wang             "",
135*f585d8a3SJacky Wang             "  @Component(modules = { Module1.class, Module2.class})",
136*f585d8a3SJacky Wang             "  interface TestComponent {",
137*f585d8a3SJacky Wang             "    A getA();",
138*f585d8a3SJacky Wang             "    B getB();",
139*f585d8a3SJacky Wang             "  }",
140*f585d8a3SJacky Wang             "}");
141*f585d8a3SJacky Wang 
142*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
143*f585d8a3SJacky Wang         .withProcessingOptions(
144*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
145*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
146*f585d8a3SJacky Wang                 .buildOrThrow())
147*f585d8a3SJacky Wang         .compile(
148*f585d8a3SJacky Wang             subject -> {
149*f585d8a3SJacky Wang               // The duplicate bindngs are also requested from B, but we don't want to report them
150*f585d8a3SJacky Wang               // again.
151*f585d8a3SJacky Wang               subject.hasErrorCount(fullBindingGraphValidation ? 2 : 1);
152*f585d8a3SJacky Wang 
153*f585d8a3SJacky Wang               subject.hasErrorContaining(
154*f585d8a3SJacky Wang                       message(
155*f585d8a3SJacky Wang                           "Outer.A is bound multiple times:",
156*f585d8a3SJacky Wang                           "    @Provides Outer.A Outer.Module1.provideA1()",
157*f585d8a3SJacky Wang                           "    @Provides Outer.A Outer.Module2.provideA2(String)"))
158*f585d8a3SJacky Wang                   .onSource(component)
159*f585d8a3SJacky Wang                   .onLineContaining("interface TestComponent");
160*f585d8a3SJacky Wang 
161*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
162*f585d8a3SJacky Wang                 subject.hasErrorContaining(
163*f585d8a3SJacky Wang                         message(
164*f585d8a3SJacky Wang                             "Outer.A is bound multiple times:",
165*f585d8a3SJacky Wang                             "    @Provides Outer.A Outer.Module1.provideA1()",
166*f585d8a3SJacky Wang                             "    @Provides Outer.A Outer.Module2.provideA2(String)"))
167*f585d8a3SJacky Wang                     .onSource(component)
168*f585d8a3SJacky Wang                     .onLineContaining("class Module3");
169*f585d8a3SJacky Wang               }
170*f585d8a3SJacky Wang             });
171*f585d8a3SJacky Wang   }
172*f585d8a3SJacky Wang 
173*f585d8a3SJacky Wang   @Test
duplicateExplicitBindings_ProvidesVsBinds()174*f585d8a3SJacky Wang   public void duplicateExplicitBindings_ProvidesVsBinds() {
175*f585d8a3SJacky Wang     Source component =
176*f585d8a3SJacky Wang         CompilerTests.javaSource(
177*f585d8a3SJacky Wang             "test.Outer",
178*f585d8a3SJacky Wang             "package test;",
179*f585d8a3SJacky Wang             "",
180*f585d8a3SJacky Wang             "import dagger.Binds;",
181*f585d8a3SJacky Wang             "import dagger.Component;",
182*f585d8a3SJacky Wang             "import dagger.Module;",
183*f585d8a3SJacky Wang             "import dagger.Provides;",
184*f585d8a3SJacky Wang             "import javax.inject.Inject;",
185*f585d8a3SJacky Wang             "",
186*f585d8a3SJacky Wang             "final class Outer {",
187*f585d8a3SJacky Wang             "  interface A {}",
188*f585d8a3SJacky Wang             "",
189*f585d8a3SJacky Wang             "  static final class B implements A {",
190*f585d8a3SJacky Wang             "    @Inject B() {}",
191*f585d8a3SJacky Wang             "  }",
192*f585d8a3SJacky Wang             "",
193*f585d8a3SJacky Wang             "  @Module",
194*f585d8a3SJacky Wang             "  static class Module1 {",
195*f585d8a3SJacky Wang             "    @Provides A provideA1() { return new A() {}; }",
196*f585d8a3SJacky Wang             "  }",
197*f585d8a3SJacky Wang             "",
198*f585d8a3SJacky Wang             "  @Module",
199*f585d8a3SJacky Wang             "  static abstract class Module2 {",
200*f585d8a3SJacky Wang             "    @Binds abstract A bindA2(B b);",
201*f585d8a3SJacky Wang             "  }",
202*f585d8a3SJacky Wang             "",
203*f585d8a3SJacky Wang             "  @Module(includes = { Module1.class, Module2.class})",
204*f585d8a3SJacky Wang             "  abstract static class Module3 {}",
205*f585d8a3SJacky Wang             "",
206*f585d8a3SJacky Wang             "  @Component(modules = { Module1.class, Module2.class})",
207*f585d8a3SJacky Wang             "  interface TestComponent {",
208*f585d8a3SJacky Wang             "    A getA();",
209*f585d8a3SJacky Wang             "  }",
210*f585d8a3SJacky Wang             "}");
211*f585d8a3SJacky Wang 
212*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
213*f585d8a3SJacky Wang         .withProcessingOptions(
214*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
215*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
216*f585d8a3SJacky Wang                 .buildOrThrow())
217*f585d8a3SJacky Wang         .compile(
218*f585d8a3SJacky Wang             subject -> {
219*f585d8a3SJacky Wang               String errorMessage =
220*f585d8a3SJacky Wang                   message(
221*f585d8a3SJacky Wang                       "Outer.A is bound multiple times:",
222*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module1.provideA1()",
223*f585d8a3SJacky Wang                       "    @Binds Outer.A Outer.Module2.bindA2(Outer.B)");
224*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
225*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
226*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
227*f585d8a3SJacky Wang                     .onSource(component)
228*f585d8a3SJacky Wang                     .onLineContaining("class Module3");
229*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
230*f585d8a3SJacky Wang                     .onSource(component)
231*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
232*f585d8a3SJacky Wang               } else {
233*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
234*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
235*f585d8a3SJacky Wang                     .onSource(component)
236*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
237*f585d8a3SJacky Wang               }
238*f585d8a3SJacky Wang             });
239*f585d8a3SJacky Wang   }
240*f585d8a3SJacky Wang 
241*f585d8a3SJacky Wang   @Test
duplicateExplicitBindings_multibindingsAndExplicitSets()242*f585d8a3SJacky Wang   public void duplicateExplicitBindings_multibindingsAndExplicitSets() {
243*f585d8a3SJacky Wang     Source component =
244*f585d8a3SJacky Wang         CompilerTests.javaSource(
245*f585d8a3SJacky Wang             "test.Outer",
246*f585d8a3SJacky Wang             "package test;",
247*f585d8a3SJacky Wang             "",
248*f585d8a3SJacky Wang             "import dagger.Binds;",
249*f585d8a3SJacky Wang             "import dagger.Component;",
250*f585d8a3SJacky Wang             "import dagger.Module;",
251*f585d8a3SJacky Wang             "import dagger.Provides;",
252*f585d8a3SJacky Wang             "import dagger.multibindings.IntoSet;",
253*f585d8a3SJacky Wang             "import java.util.HashSet;",
254*f585d8a3SJacky Wang             "import java.util.Set;",
255*f585d8a3SJacky Wang             "import javax.inject.Qualifier;",
256*f585d8a3SJacky Wang             "",
257*f585d8a3SJacky Wang             "final class Outer {",
258*f585d8a3SJacky Wang             "  @Qualifier @interface SomeQualifier {}",
259*f585d8a3SJacky Wang             "",
260*f585d8a3SJacky Wang             "  @Module",
261*f585d8a3SJacky Wang             "  abstract static class TestModule1 {",
262*f585d8a3SJacky Wang             "    @Provides @IntoSet static String stringSetElement() { return \"\"; }",
263*f585d8a3SJacky Wang             "",
264*f585d8a3SJacky Wang             "    @Binds",
265*f585d8a3SJacky Wang             "    @IntoSet abstract String bindStringSetElement(@SomeQualifier String value);",
266*f585d8a3SJacky Wang             "",
267*f585d8a3SJacky Wang             "    @Provides @SomeQualifier",
268*f585d8a3SJacky Wang             "    static String provideSomeQualifiedString() { return \"\"; }",
269*f585d8a3SJacky Wang             "  }",
270*f585d8a3SJacky Wang             "",
271*f585d8a3SJacky Wang             "  @Module",
272*f585d8a3SJacky Wang             "  static class TestModule2 {",
273*f585d8a3SJacky Wang             "    @Provides Set<String> stringSet() { return new HashSet<String>(); }",
274*f585d8a3SJacky Wang             "  }",
275*f585d8a3SJacky Wang             "",
276*f585d8a3SJacky Wang             "  @Module(includes = { TestModule1.class, TestModule2.class})",
277*f585d8a3SJacky Wang             "  abstract static class TestModule3 {}",
278*f585d8a3SJacky Wang             "",
279*f585d8a3SJacky Wang             "  @Component(modules = { TestModule1.class, TestModule2.class })",
280*f585d8a3SJacky Wang             "  interface TestComponent {",
281*f585d8a3SJacky Wang             "    Set<String> getStringSet();",
282*f585d8a3SJacky Wang             "  }",
283*f585d8a3SJacky Wang             "}");
284*f585d8a3SJacky Wang 
285*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
286*f585d8a3SJacky Wang         .withProcessingOptions(
287*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
288*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
289*f585d8a3SJacky Wang                 .buildOrThrow())
290*f585d8a3SJacky Wang         .compile(
291*f585d8a3SJacky Wang             subject -> {
292*f585d8a3SJacky Wang               String errorMessage =
293*f585d8a3SJacky Wang                   message(
294*f585d8a3SJacky Wang                       "Set<String> has incompatible bindings or declarations:",
295*f585d8a3SJacky Wang                       "    Set bindings and declarations:",
296*f585d8a3SJacky Wang                       "        @Binds @IntoSet String "
297*f585d8a3SJacky Wang                           + "Outer.TestModule1.bindStringSetElement(@Outer.SomeQualifier String)",
298*f585d8a3SJacky Wang                       "        @Provides @IntoSet String "
299*f585d8a3SJacky Wang                           + "Outer.TestModule1.stringSetElement()",
300*f585d8a3SJacky Wang                       "    Unique bindings and declarations:",
301*f585d8a3SJacky Wang                       "        @Provides Set<String> Outer.TestModule2.stringSet()");
302*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
303*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
304*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
305*f585d8a3SJacky Wang                     .onSource(component)
306*f585d8a3SJacky Wang                     .onLineContaining("class TestModule3");
307*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
308*f585d8a3SJacky Wang                     .onSource(component)
309*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
310*f585d8a3SJacky Wang               } else {
311*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
312*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
313*f585d8a3SJacky Wang                     .onSource(component)
314*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
315*f585d8a3SJacky Wang               }
316*f585d8a3SJacky Wang             });
317*f585d8a3SJacky Wang   }
318*f585d8a3SJacky Wang 
319*f585d8a3SJacky Wang   @Test
duplicateExplicitBindings_multibindingsAndExplicitMaps()320*f585d8a3SJacky Wang   public void duplicateExplicitBindings_multibindingsAndExplicitMaps() {
321*f585d8a3SJacky Wang     Source component =
322*f585d8a3SJacky Wang         CompilerTests.javaSource(
323*f585d8a3SJacky Wang             "test.Outer",
324*f585d8a3SJacky Wang             "package test;",
325*f585d8a3SJacky Wang             "",
326*f585d8a3SJacky Wang             "import dagger.Binds;",
327*f585d8a3SJacky Wang             "import dagger.Component;",
328*f585d8a3SJacky Wang             "import dagger.Module;",
329*f585d8a3SJacky Wang             "import dagger.Provides;",
330*f585d8a3SJacky Wang             "import dagger.multibindings.IntoMap;",
331*f585d8a3SJacky Wang             "import dagger.multibindings.StringKey;",
332*f585d8a3SJacky Wang             "import java.util.HashMap;",
333*f585d8a3SJacky Wang             "import java.util.Map;",
334*f585d8a3SJacky Wang             "import javax.inject.Qualifier;",
335*f585d8a3SJacky Wang             "",
336*f585d8a3SJacky Wang             "final class Outer {",
337*f585d8a3SJacky Wang             "  @Qualifier @interface SomeQualifier {}",
338*f585d8a3SJacky Wang             "",
339*f585d8a3SJacky Wang             "  @Module",
340*f585d8a3SJacky Wang             "  abstract static class TestModule1 {",
341*f585d8a3SJacky Wang             "    @Provides @IntoMap",
342*f585d8a3SJacky Wang             "    @StringKey(\"foo\")",
343*f585d8a3SJacky Wang             "    static String stringMapEntry() { return \"\"; }",
344*f585d8a3SJacky Wang             "",
345*f585d8a3SJacky Wang             "    @Binds @IntoMap @StringKey(\"bar\")",
346*f585d8a3SJacky Wang             "    abstract String bindStringMapEntry(@SomeQualifier String value);",
347*f585d8a3SJacky Wang             "",
348*f585d8a3SJacky Wang             "    @Provides @SomeQualifier",
349*f585d8a3SJacky Wang             "    static String provideSomeQualifiedString() { return \"\"; }",
350*f585d8a3SJacky Wang             "  }",
351*f585d8a3SJacky Wang             "",
352*f585d8a3SJacky Wang             "  @Module",
353*f585d8a3SJacky Wang             "  static class TestModule2 {",
354*f585d8a3SJacky Wang             "    @Provides Map<String, String> stringMap() {",
355*f585d8a3SJacky Wang             "      return new HashMap<String, String>();",
356*f585d8a3SJacky Wang             "    }",
357*f585d8a3SJacky Wang             "  }",
358*f585d8a3SJacky Wang             "",
359*f585d8a3SJacky Wang             "  @Module(includes = { TestModule1.class, TestModule2.class})",
360*f585d8a3SJacky Wang             "  abstract static class TestModule3 {}",
361*f585d8a3SJacky Wang             "",
362*f585d8a3SJacky Wang             "  @Component(modules = { TestModule1.class, TestModule2.class })",
363*f585d8a3SJacky Wang             "  interface TestComponent {",
364*f585d8a3SJacky Wang             "    Map<String, String> getStringMap();",
365*f585d8a3SJacky Wang             "  }",
366*f585d8a3SJacky Wang             "}");
367*f585d8a3SJacky Wang 
368*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
369*f585d8a3SJacky Wang         .withProcessingOptions(
370*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
371*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
372*f585d8a3SJacky Wang                 .buildOrThrow())
373*f585d8a3SJacky Wang         .compile(
374*f585d8a3SJacky Wang             subject -> {
375*f585d8a3SJacky Wang               String errorMessage =
376*f585d8a3SJacky Wang                   message(
377*f585d8a3SJacky Wang                       "Map<String,String> has incompatible bindings or declarations:",
378*f585d8a3SJacky Wang                       "    Map bindings and declarations:",
379*f585d8a3SJacky Wang                       "        @Binds @IntoMap @StringKey(\"bar\") String"
380*f585d8a3SJacky Wang                           + " Outer.TestModule1.bindStringMapEntry(@Outer.SomeQualifier String)",
381*f585d8a3SJacky Wang                       "        @Provides @IntoMap @StringKey(\"foo\") String"
382*f585d8a3SJacky Wang                           + " Outer.TestModule1.stringMapEntry()",
383*f585d8a3SJacky Wang                       "    Unique bindings and declarations:",
384*f585d8a3SJacky Wang                       "        @Provides Map<String,String> Outer.TestModule2.stringMap()");
385*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
386*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
387*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
388*f585d8a3SJacky Wang                     .onSource(component)
389*f585d8a3SJacky Wang                     .onLineContaining("class TestModule3");
390*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
391*f585d8a3SJacky Wang                     .onSource(component)
392*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
393*f585d8a3SJacky Wang               } else {
394*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
395*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
396*f585d8a3SJacky Wang                     .onSource(component)
397*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
398*f585d8a3SJacky Wang               }
399*f585d8a3SJacky Wang             });
400*f585d8a3SJacky Wang   }
401*f585d8a3SJacky Wang 
402*f585d8a3SJacky Wang   @Test
duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Set()403*f585d8a3SJacky Wang   public void duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Set() {
404*f585d8a3SJacky Wang     Source component =
405*f585d8a3SJacky Wang         CompilerTests.javaSource(
406*f585d8a3SJacky Wang             "test.Outer",
407*f585d8a3SJacky Wang             "package test;",
408*f585d8a3SJacky Wang             "",
409*f585d8a3SJacky Wang             "import dagger.Component;",
410*f585d8a3SJacky Wang             "import dagger.Module;",
411*f585d8a3SJacky Wang             "import dagger.Provides;",
412*f585d8a3SJacky Wang             "import dagger.multibindings.Multibinds;",
413*f585d8a3SJacky Wang             "import java.util.HashSet;",
414*f585d8a3SJacky Wang             "import java.util.Set;",
415*f585d8a3SJacky Wang             "",
416*f585d8a3SJacky Wang             "final class Outer {",
417*f585d8a3SJacky Wang             "  @Module",
418*f585d8a3SJacky Wang             "  abstract static class TestModule1 {",
419*f585d8a3SJacky Wang             "    @Multibinds abstract Set<String> stringSet();",
420*f585d8a3SJacky Wang             "  }",
421*f585d8a3SJacky Wang             "",
422*f585d8a3SJacky Wang             "  @Module",
423*f585d8a3SJacky Wang             "  static class TestModule2 {",
424*f585d8a3SJacky Wang             "    @Provides Set<String> stringSet() { return new HashSet<String>(); }",
425*f585d8a3SJacky Wang             "  }",
426*f585d8a3SJacky Wang             "",
427*f585d8a3SJacky Wang             "  @Module(includes = { TestModule1.class, TestModule2.class})",
428*f585d8a3SJacky Wang             "  abstract static class TestModule3 {}",
429*f585d8a3SJacky Wang             "",
430*f585d8a3SJacky Wang             "  @Component(modules = { TestModule1.class, TestModule2.class })",
431*f585d8a3SJacky Wang             "  interface TestComponent {",
432*f585d8a3SJacky Wang             "    Set<String> getStringSet();",
433*f585d8a3SJacky Wang             "  }",
434*f585d8a3SJacky Wang             "}");
435*f585d8a3SJacky Wang 
436*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
437*f585d8a3SJacky Wang         .withProcessingOptions(
438*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
439*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
440*f585d8a3SJacky Wang                 .buildOrThrow())
441*f585d8a3SJacky Wang         .compile(
442*f585d8a3SJacky Wang             subject -> {
443*f585d8a3SJacky Wang               String errorMessage =
444*f585d8a3SJacky Wang                   message(
445*f585d8a3SJacky Wang                       "Set<String> has incompatible bindings or declarations:",
446*f585d8a3SJacky Wang                       "    Set bindings and declarations:",
447*f585d8a3SJacky Wang                       "        @Multibinds Set<String> Outer.TestModule1.stringSet()",
448*f585d8a3SJacky Wang                       "    Unique bindings and declarations:",
449*f585d8a3SJacky Wang                       "        @Provides Set<String> Outer.TestModule2.stringSet()");
450*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
451*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
452*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
453*f585d8a3SJacky Wang                     .onSource(component)
454*f585d8a3SJacky Wang                     .onLineContaining("class TestModule3");
455*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
456*f585d8a3SJacky Wang                     .onSource(component)
457*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
458*f585d8a3SJacky Wang               } else {
459*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
460*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
461*f585d8a3SJacky Wang                     .onSource(component)
462*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
463*f585d8a3SJacky Wang               }
464*f585d8a3SJacky Wang             });
465*f585d8a3SJacky Wang   }
466*f585d8a3SJacky Wang 
467*f585d8a3SJacky Wang   @Test
duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Map()468*f585d8a3SJacky Wang   public void duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Map() {
469*f585d8a3SJacky Wang     Source component =
470*f585d8a3SJacky Wang         CompilerTests.javaSource(
471*f585d8a3SJacky Wang             "test.Outer",
472*f585d8a3SJacky Wang             "package test;",
473*f585d8a3SJacky Wang             "",
474*f585d8a3SJacky Wang             "import dagger.Component;",
475*f585d8a3SJacky Wang             "import dagger.Module;",
476*f585d8a3SJacky Wang             "import dagger.Provides;",
477*f585d8a3SJacky Wang             "import dagger.multibindings.Multibinds;",
478*f585d8a3SJacky Wang             "import java.util.HashMap;",
479*f585d8a3SJacky Wang             "import java.util.Map;",
480*f585d8a3SJacky Wang             "",
481*f585d8a3SJacky Wang             "final class Outer {",
482*f585d8a3SJacky Wang             "  @Module",
483*f585d8a3SJacky Wang             "  abstract static class TestModule1 {",
484*f585d8a3SJacky Wang             "    @Multibinds abstract Map<String, String> stringMap();",
485*f585d8a3SJacky Wang             "  }",
486*f585d8a3SJacky Wang             "",
487*f585d8a3SJacky Wang             "  @Module",
488*f585d8a3SJacky Wang             "  static class TestModule2 {",
489*f585d8a3SJacky Wang             "    @Provides Map<String, String> stringMap() {",
490*f585d8a3SJacky Wang             "      return new HashMap<String, String>();",
491*f585d8a3SJacky Wang             "    }",
492*f585d8a3SJacky Wang             "  }",
493*f585d8a3SJacky Wang             "",
494*f585d8a3SJacky Wang             "  @Module(includes = { TestModule1.class, TestModule2.class})",
495*f585d8a3SJacky Wang             "  abstract static class TestModule3 {}",
496*f585d8a3SJacky Wang             "",
497*f585d8a3SJacky Wang             "  @Component(modules = { TestModule1.class, TestModule2.class })",
498*f585d8a3SJacky Wang             "  interface TestComponent {",
499*f585d8a3SJacky Wang             "    Map<String, String> getStringMap();",
500*f585d8a3SJacky Wang             "  }",
501*f585d8a3SJacky Wang             "}");
502*f585d8a3SJacky Wang 
503*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
504*f585d8a3SJacky Wang         .withProcessingOptions(
505*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
506*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
507*f585d8a3SJacky Wang                 .buildOrThrow())
508*f585d8a3SJacky Wang         .compile(
509*f585d8a3SJacky Wang             subject -> {
510*f585d8a3SJacky Wang               String errorMessage =
511*f585d8a3SJacky Wang                   message(
512*f585d8a3SJacky Wang                       "Map<String,String> has incompatible bindings or declarations:",
513*f585d8a3SJacky Wang                       "    Map bindings and declarations:",
514*f585d8a3SJacky Wang                       "        @Multibinds Map<String,String> Outer.TestModule1.stringMap()",
515*f585d8a3SJacky Wang                       "    Unique bindings and declarations:",
516*f585d8a3SJacky Wang                       "        @Provides Map<String,String> Outer.TestModule2.stringMap()");
517*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
518*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
519*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
520*f585d8a3SJacky Wang                     .onSource(component)
521*f585d8a3SJacky Wang                     .onLineContaining("class TestModule3");
522*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
523*f585d8a3SJacky Wang                     .onSource(component)
524*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
525*f585d8a3SJacky Wang               } else {
526*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
527*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
528*f585d8a3SJacky Wang                     .onSource(component)
529*f585d8a3SJacky Wang                     .onLineContaining("interface TestComponent");
530*f585d8a3SJacky Wang               }
531*f585d8a3SJacky Wang             });
532*f585d8a3SJacky Wang   }
533*f585d8a3SJacky Wang 
duplicateBindings_TruncateAfterLimit()534*f585d8a3SJacky Wang   @Test public void duplicateBindings_TruncateAfterLimit() {
535*f585d8a3SJacky Wang     Source component =
536*f585d8a3SJacky Wang         CompilerTests.javaSource(
537*f585d8a3SJacky Wang             "test.Outer",
538*f585d8a3SJacky Wang             "package test;",
539*f585d8a3SJacky Wang             "",
540*f585d8a3SJacky Wang             "import dagger.Component;",
541*f585d8a3SJacky Wang             "import dagger.Module;",
542*f585d8a3SJacky Wang             "import dagger.Provides;",
543*f585d8a3SJacky Wang             "import javax.inject.Inject;",
544*f585d8a3SJacky Wang             "",
545*f585d8a3SJacky Wang             "final class Outer {",
546*f585d8a3SJacky Wang             "  interface A {}",
547*f585d8a3SJacky Wang             "",
548*f585d8a3SJacky Wang             "  @Module",
549*f585d8a3SJacky Wang             "  static class Module01 {",
550*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
551*f585d8a3SJacky Wang             "  }",
552*f585d8a3SJacky Wang             "",
553*f585d8a3SJacky Wang             "  @Module",
554*f585d8a3SJacky Wang             "  static class Module02 {",
555*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
556*f585d8a3SJacky Wang             "  }",
557*f585d8a3SJacky Wang             "",
558*f585d8a3SJacky Wang             "  @Module",
559*f585d8a3SJacky Wang             "  static class Module03 {",
560*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
561*f585d8a3SJacky Wang             "  }",
562*f585d8a3SJacky Wang             "",
563*f585d8a3SJacky Wang             "  @Module",
564*f585d8a3SJacky Wang             "  static class Module04 {",
565*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
566*f585d8a3SJacky Wang             "  }",
567*f585d8a3SJacky Wang             "",
568*f585d8a3SJacky Wang             "  @Module",
569*f585d8a3SJacky Wang             "  static class Module05 {",
570*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
571*f585d8a3SJacky Wang             "  }",
572*f585d8a3SJacky Wang             "",
573*f585d8a3SJacky Wang             "  @Module",
574*f585d8a3SJacky Wang             "  static class Module06 {",
575*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
576*f585d8a3SJacky Wang             "  }",
577*f585d8a3SJacky Wang             "",
578*f585d8a3SJacky Wang             "  @Module",
579*f585d8a3SJacky Wang             "  static class Module07 {",
580*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
581*f585d8a3SJacky Wang             "  }",
582*f585d8a3SJacky Wang             "",
583*f585d8a3SJacky Wang             "  @Module",
584*f585d8a3SJacky Wang             "  static class Module08 {",
585*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
586*f585d8a3SJacky Wang             "  }",
587*f585d8a3SJacky Wang             "",
588*f585d8a3SJacky Wang             "  @Module",
589*f585d8a3SJacky Wang             "  static class Module09 {",
590*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
591*f585d8a3SJacky Wang             "  }",
592*f585d8a3SJacky Wang             "",
593*f585d8a3SJacky Wang             "  @Module",
594*f585d8a3SJacky Wang             "  static class Module10 {",
595*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
596*f585d8a3SJacky Wang             "  }",
597*f585d8a3SJacky Wang             "",
598*f585d8a3SJacky Wang             "  @Module",
599*f585d8a3SJacky Wang             "  static class Module11 {",
600*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
601*f585d8a3SJacky Wang             "  }",
602*f585d8a3SJacky Wang             "",
603*f585d8a3SJacky Wang             "  @Module",
604*f585d8a3SJacky Wang             "  static class Module12 {",
605*f585d8a3SJacky Wang             "    @Provides A provideA() { return new A() {}; }",
606*f585d8a3SJacky Wang             "  }",
607*f585d8a3SJacky Wang             "",
608*f585d8a3SJacky Wang             "  @Module(includes = {",
609*f585d8a3SJacky Wang             "    Module01.class,",
610*f585d8a3SJacky Wang             "    Module02.class,",
611*f585d8a3SJacky Wang             "    Module03.class,",
612*f585d8a3SJacky Wang             "    Module04.class,",
613*f585d8a3SJacky Wang             "    Module05.class,",
614*f585d8a3SJacky Wang             "    Module06.class,",
615*f585d8a3SJacky Wang             "    Module07.class,",
616*f585d8a3SJacky Wang             "    Module08.class,",
617*f585d8a3SJacky Wang             "    Module09.class,",
618*f585d8a3SJacky Wang             "    Module10.class,",
619*f585d8a3SJacky Wang             "    Module11.class,",
620*f585d8a3SJacky Wang             "    Module12.class",
621*f585d8a3SJacky Wang             "  })",
622*f585d8a3SJacky Wang             "  abstract static class Modules {}",
623*f585d8a3SJacky Wang             "",
624*f585d8a3SJacky Wang             "  @Component(modules = {",
625*f585d8a3SJacky Wang             "    Module01.class,",
626*f585d8a3SJacky Wang             "    Module02.class,",
627*f585d8a3SJacky Wang             "    Module03.class,",
628*f585d8a3SJacky Wang             "    Module04.class,",
629*f585d8a3SJacky Wang             "    Module05.class,",
630*f585d8a3SJacky Wang             "    Module06.class,",
631*f585d8a3SJacky Wang             "    Module07.class,",
632*f585d8a3SJacky Wang             "    Module08.class,",
633*f585d8a3SJacky Wang             "    Module09.class,",
634*f585d8a3SJacky Wang             "    Module10.class,",
635*f585d8a3SJacky Wang             "    Module11.class,",
636*f585d8a3SJacky Wang             "    Module12.class",
637*f585d8a3SJacky Wang             "  })",
638*f585d8a3SJacky Wang             "  interface TestComponent {",
639*f585d8a3SJacky Wang             "    A getA();",
640*f585d8a3SJacky Wang             "  }",
641*f585d8a3SJacky Wang             "}");
642*f585d8a3SJacky Wang 
643*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(component)
644*f585d8a3SJacky Wang         .withProcessingOptions(
645*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
646*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
647*f585d8a3SJacky Wang                 .buildOrThrow())
648*f585d8a3SJacky Wang         .compile(
649*f585d8a3SJacky Wang             subject -> {
650*f585d8a3SJacky Wang               subject.hasErrorCount(fullBindingGraphValidation ? 2 : 1);
651*f585d8a3SJacky Wang               String errorMessage =
652*f585d8a3SJacky Wang                   message(
653*f585d8a3SJacky Wang                       "Outer.A is bound multiple times:",
654*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module01.provideA()",
655*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module02.provideA()",
656*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module03.provideA()",
657*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module04.provideA()",
658*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module05.provideA()",
659*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module06.provideA()",
660*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module07.provideA()",
661*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module08.provideA()",
662*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module09.provideA()",
663*f585d8a3SJacky Wang                       "    @Provides Outer.A Outer.Module10.provideA()",
664*f585d8a3SJacky Wang                       "    and 2 others");
665*f585d8a3SJacky Wang 
666*f585d8a3SJacky Wang               subject.hasErrorContaining(errorMessage)
667*f585d8a3SJacky Wang                   .onSource(component)
668*f585d8a3SJacky Wang                   .onLineContaining("interface TestComponent");
669*f585d8a3SJacky Wang 
670*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
671*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
672*f585d8a3SJacky Wang                     .onSource(component)
673*f585d8a3SJacky Wang                     .onLineContaining("class Modules");
674*f585d8a3SJacky Wang               }
675*f585d8a3SJacky Wang             });
676*f585d8a3SJacky Wang   }
677*f585d8a3SJacky Wang 
678*f585d8a3SJacky Wang   @Test
childBindingConflictsWithParent()679*f585d8a3SJacky Wang   public void childBindingConflictsWithParent() {
680*f585d8a3SJacky Wang     Source aComponent =
681*f585d8a3SJacky Wang         CompilerTests.javaSource(
682*f585d8a3SJacky Wang             "test.A",
683*f585d8a3SJacky Wang             "package test;",
684*f585d8a3SJacky Wang             "",
685*f585d8a3SJacky Wang             "import dagger.Component;",
686*f585d8a3SJacky Wang             "import dagger.Module;",
687*f585d8a3SJacky Wang             "import dagger.Provides;",
688*f585d8a3SJacky Wang             "",
689*f585d8a3SJacky Wang             "@Component(modules = A.AModule.class)",
690*f585d8a3SJacky Wang             "interface A {",
691*f585d8a3SJacky Wang             "  Object conflict();",
692*f585d8a3SJacky Wang             "",
693*f585d8a3SJacky Wang             "  B.Builder b();",
694*f585d8a3SJacky Wang             "",
695*f585d8a3SJacky Wang             "  @Module(subcomponents = B.class)",
696*f585d8a3SJacky Wang             "  static class AModule {",
697*f585d8a3SJacky Wang             "    @Provides static Object abConflict() {",
698*f585d8a3SJacky Wang             "      return \"a\";",
699*f585d8a3SJacky Wang             "    }",
700*f585d8a3SJacky Wang             "  }",
701*f585d8a3SJacky Wang             "}");
702*f585d8a3SJacky Wang     Source bComponent =
703*f585d8a3SJacky Wang         CompilerTests.javaSource(
704*f585d8a3SJacky Wang             "test.B",
705*f585d8a3SJacky Wang             "package test;",
706*f585d8a3SJacky Wang             "",
707*f585d8a3SJacky Wang             "import dagger.Module;",
708*f585d8a3SJacky Wang             "import dagger.Provides;",
709*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
710*f585d8a3SJacky Wang             "",
711*f585d8a3SJacky Wang             "@Subcomponent(modules = B.BModule.class)",
712*f585d8a3SJacky Wang             "interface B {",
713*f585d8a3SJacky Wang             "  Object conflict();",
714*f585d8a3SJacky Wang             "",
715*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
716*f585d8a3SJacky Wang             "  interface Builder {",
717*f585d8a3SJacky Wang             "    B build();",
718*f585d8a3SJacky Wang             "  }",
719*f585d8a3SJacky Wang             "",
720*f585d8a3SJacky Wang             "  @Module",
721*f585d8a3SJacky Wang             "  static class BModule {",
722*f585d8a3SJacky Wang             "    @Provides static Object abConflict() {",
723*f585d8a3SJacky Wang             "      return \"b\";",
724*f585d8a3SJacky Wang             "    }",
725*f585d8a3SJacky Wang             "  }",
726*f585d8a3SJacky Wang             "}");
727*f585d8a3SJacky Wang 
728*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(aComponent, bComponent)
729*f585d8a3SJacky Wang         .withProcessingOptions(
730*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
731*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
732*f585d8a3SJacky Wang                 .buildOrThrow())
733*f585d8a3SJacky Wang         .compile(
734*f585d8a3SJacky Wang             subject -> {
735*f585d8a3SJacky Wang               String errorMessage =
736*f585d8a3SJacky Wang                   message(
737*f585d8a3SJacky Wang                       "Object is bound multiple times:",
738*f585d8a3SJacky Wang                       "    @Provides Object test.A.AModule.abConflict()",
739*f585d8a3SJacky Wang                       "    @Provides Object test.B.BModule.abConflict()");
740*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
741*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
742*f585d8a3SJacky Wang                 subject.hasErrorContaining("test.A.AModule has errors")
743*f585d8a3SJacky Wang                     .onSource(aComponent)
744*f585d8a3SJacky Wang                     .onLineContaining("@Component(");
745*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
746*f585d8a3SJacky Wang                     .onSource(aComponent)
747*f585d8a3SJacky Wang                     .onLineContaining("class AModule");
748*f585d8a3SJacky Wang               } else {
749*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
750*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
751*f585d8a3SJacky Wang                     .onSource(aComponent)
752*f585d8a3SJacky Wang                     .onLineContaining("interface A {");
753*f585d8a3SJacky Wang               }
754*f585d8a3SJacky Wang             });
755*f585d8a3SJacky Wang   }
756*f585d8a3SJacky Wang 
757*f585d8a3SJacky Wang   @Test
grandchildBindingConflictsWithGrandparent()758*f585d8a3SJacky Wang   public void grandchildBindingConflictsWithGrandparent() {
759*f585d8a3SJacky Wang     Source aComponent =
760*f585d8a3SJacky Wang         CompilerTests.javaSource(
761*f585d8a3SJacky Wang             "test.A",
762*f585d8a3SJacky Wang             "package test;",
763*f585d8a3SJacky Wang             "",
764*f585d8a3SJacky Wang             "import dagger.Component;",
765*f585d8a3SJacky Wang             "import dagger.Module;",
766*f585d8a3SJacky Wang             "import dagger.Provides;",
767*f585d8a3SJacky Wang             "",
768*f585d8a3SJacky Wang             "@Component(modules = A.AModule.class)",
769*f585d8a3SJacky Wang             "interface A {",
770*f585d8a3SJacky Wang             "  Object conflict();",
771*f585d8a3SJacky Wang             "",
772*f585d8a3SJacky Wang             "  B.Builder b();",
773*f585d8a3SJacky Wang             "",
774*f585d8a3SJacky Wang             "  @Module(subcomponents = B.class)",
775*f585d8a3SJacky Wang             "  static class AModule {",
776*f585d8a3SJacky Wang             "    @Provides static Object acConflict() {",
777*f585d8a3SJacky Wang             "      return \"a\";",
778*f585d8a3SJacky Wang             "    }",
779*f585d8a3SJacky Wang             "  }",
780*f585d8a3SJacky Wang             "}");
781*f585d8a3SJacky Wang     Source bComponent =
782*f585d8a3SJacky Wang         CompilerTests.javaSource(
783*f585d8a3SJacky Wang             "test.B",
784*f585d8a3SJacky Wang             "package test;",
785*f585d8a3SJacky Wang             "",
786*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
787*f585d8a3SJacky Wang             "",
788*f585d8a3SJacky Wang             "@Subcomponent",
789*f585d8a3SJacky Wang             "interface B {",
790*f585d8a3SJacky Wang             "  C.Builder c();",
791*f585d8a3SJacky Wang             "",
792*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
793*f585d8a3SJacky Wang             "  interface Builder {",
794*f585d8a3SJacky Wang             "    B build();",
795*f585d8a3SJacky Wang             "  }",
796*f585d8a3SJacky Wang             "}");
797*f585d8a3SJacky Wang     Source cComponent =
798*f585d8a3SJacky Wang         CompilerTests.javaSource(
799*f585d8a3SJacky Wang             "test.C",
800*f585d8a3SJacky Wang             "package test;",
801*f585d8a3SJacky Wang             "",
802*f585d8a3SJacky Wang             "import dagger.Module;",
803*f585d8a3SJacky Wang             "import dagger.Provides;",
804*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
805*f585d8a3SJacky Wang             "",
806*f585d8a3SJacky Wang             "@Subcomponent(modules = C.CModule.class)",
807*f585d8a3SJacky Wang             "interface C {",
808*f585d8a3SJacky Wang             "  Object conflict();",
809*f585d8a3SJacky Wang             "",
810*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
811*f585d8a3SJacky Wang             "  interface Builder {",
812*f585d8a3SJacky Wang             "    C build();",
813*f585d8a3SJacky Wang             "  }",
814*f585d8a3SJacky Wang             "",
815*f585d8a3SJacky Wang             "  @Module",
816*f585d8a3SJacky Wang             "  static class CModule {",
817*f585d8a3SJacky Wang             "    @Provides static Object acConflict() {",
818*f585d8a3SJacky Wang             "      return \"c\";",
819*f585d8a3SJacky Wang             "    }",
820*f585d8a3SJacky Wang             "  }",
821*f585d8a3SJacky Wang             "}");
822*f585d8a3SJacky Wang 
823*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(aComponent, bComponent, cComponent)
824*f585d8a3SJacky Wang         .withProcessingOptions(
825*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
826*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
827*f585d8a3SJacky Wang                 .buildOrThrow())
828*f585d8a3SJacky Wang         .compile(
829*f585d8a3SJacky Wang             subject -> {
830*f585d8a3SJacky Wang               String errorMessage =
831*f585d8a3SJacky Wang                   message(
832*f585d8a3SJacky Wang                       "Object is bound multiple times:",
833*f585d8a3SJacky Wang                       "    @Provides Object test.A.AModule.acConflict()",
834*f585d8a3SJacky Wang                       "    @Provides Object test.C.CModule.acConflict()");
835*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
836*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
837*f585d8a3SJacky Wang                 subject.hasErrorContaining("test.A.AModule has errors")
838*f585d8a3SJacky Wang                     .onSource(aComponent)
839*f585d8a3SJacky Wang                     .onLineContaining("@Component(");
840*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
841*f585d8a3SJacky Wang                     .onSource(aComponent)
842*f585d8a3SJacky Wang                     .onLineContaining("class AModule");
843*f585d8a3SJacky Wang               } else {
844*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
845*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
846*f585d8a3SJacky Wang                     .onSource(aComponent)
847*f585d8a3SJacky Wang                     .onLineContaining("interface A {");
848*f585d8a3SJacky Wang               }
849*f585d8a3SJacky Wang             });
850*f585d8a3SJacky Wang   }
851*f585d8a3SJacky Wang 
852*f585d8a3SJacky Wang   @Test
grandchildBindingConflictsWithChild()853*f585d8a3SJacky Wang   public void grandchildBindingConflictsWithChild() {
854*f585d8a3SJacky Wang     Source aComponent =
855*f585d8a3SJacky Wang         CompilerTests.javaSource(
856*f585d8a3SJacky Wang             "test.A",
857*f585d8a3SJacky Wang             "package test;",
858*f585d8a3SJacky Wang             "",
859*f585d8a3SJacky Wang             "import dagger.Component;",
860*f585d8a3SJacky Wang             "",
861*f585d8a3SJacky Wang             "@Component",
862*f585d8a3SJacky Wang             "interface A {",
863*f585d8a3SJacky Wang             "  B b();",
864*f585d8a3SJacky Wang             "}");
865*f585d8a3SJacky Wang     Source bComponent =
866*f585d8a3SJacky Wang         CompilerTests.javaSource(
867*f585d8a3SJacky Wang             "test.B",
868*f585d8a3SJacky Wang             "package test;",
869*f585d8a3SJacky Wang             "",
870*f585d8a3SJacky Wang             "import dagger.Module;",
871*f585d8a3SJacky Wang             "import dagger.Provides;",
872*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
873*f585d8a3SJacky Wang             "",
874*f585d8a3SJacky Wang             "@Subcomponent(modules = B.BModule.class)",
875*f585d8a3SJacky Wang             "interface B {",
876*f585d8a3SJacky Wang             "  Object conflict();",
877*f585d8a3SJacky Wang             "",
878*f585d8a3SJacky Wang             "  C.Builder c();",
879*f585d8a3SJacky Wang             "",
880*f585d8a3SJacky Wang             "  @Module(subcomponents = C.class)",
881*f585d8a3SJacky Wang             "  static class BModule {",
882*f585d8a3SJacky Wang             "    @Provides static Object bcConflict() {",
883*f585d8a3SJacky Wang             "      return \"b\";",
884*f585d8a3SJacky Wang             "    }",
885*f585d8a3SJacky Wang             "  }",
886*f585d8a3SJacky Wang             "}");
887*f585d8a3SJacky Wang     Source cComponent =
888*f585d8a3SJacky Wang         CompilerTests.javaSource(
889*f585d8a3SJacky Wang             "test.C",
890*f585d8a3SJacky Wang             "package test;",
891*f585d8a3SJacky Wang             "",
892*f585d8a3SJacky Wang             "import dagger.Module;",
893*f585d8a3SJacky Wang             "import dagger.Provides;",
894*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
895*f585d8a3SJacky Wang             "",
896*f585d8a3SJacky Wang             "@Subcomponent(modules = C.CModule.class)",
897*f585d8a3SJacky Wang             "interface C {",
898*f585d8a3SJacky Wang             "  Object conflict();",
899*f585d8a3SJacky Wang             "",
900*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
901*f585d8a3SJacky Wang             "  interface Builder {",
902*f585d8a3SJacky Wang             "    C build();",
903*f585d8a3SJacky Wang             "  }",
904*f585d8a3SJacky Wang             "",
905*f585d8a3SJacky Wang             "  @Module",
906*f585d8a3SJacky Wang             "  static class CModule {",
907*f585d8a3SJacky Wang             "    @Provides static Object bcConflict() {",
908*f585d8a3SJacky Wang             "      return \"c\";",
909*f585d8a3SJacky Wang             "    }",
910*f585d8a3SJacky Wang             "  }",
911*f585d8a3SJacky Wang             "}");
912*f585d8a3SJacky Wang 
913*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(aComponent, bComponent, cComponent)
914*f585d8a3SJacky Wang         .withProcessingOptions(
915*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
916*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
917*f585d8a3SJacky Wang                 .buildOrThrow())
918*f585d8a3SJacky Wang         .compile(
919*f585d8a3SJacky Wang             subject -> {
920*f585d8a3SJacky Wang               String errorMessage =
921*f585d8a3SJacky Wang                   message(
922*f585d8a3SJacky Wang                       "Object is bound multiple times:",
923*f585d8a3SJacky Wang                       "    @Provides Object test.B.BModule.bcConflict()",
924*f585d8a3SJacky Wang                       "    @Provides Object test.C.CModule.bcConflict()");
925*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
926*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
927*f585d8a3SJacky Wang                 subject.hasErrorContaining("test.B.BModule has errors")
928*f585d8a3SJacky Wang                     .onSource(bComponent)
929*f585d8a3SJacky Wang                     .onLineContaining("@Subcomponent(modules = B.BModule.class)");
930*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
931*f585d8a3SJacky Wang                     .onSource(bComponent)
932*f585d8a3SJacky Wang                     .onLineContaining("class BModule");
933*f585d8a3SJacky Wang               } else {
934*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
935*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
936*f585d8a3SJacky Wang                     .onSource(aComponent)
937*f585d8a3SJacky Wang                     .onLineContaining("interface A {");
938*f585d8a3SJacky Wang               }
939*f585d8a3SJacky Wang             });
940*f585d8a3SJacky Wang   }
941*f585d8a3SJacky Wang 
942*f585d8a3SJacky Wang   @Test
childProvidesConflictsWithParentInjects()943*f585d8a3SJacky Wang   public void childProvidesConflictsWithParentInjects() {
944*f585d8a3SJacky Wang     assumeFalse(fullBindingGraphValidation);
945*f585d8a3SJacky Wang 
946*f585d8a3SJacky Wang     Source foo =
947*f585d8a3SJacky Wang         CompilerTests.javaSource(
948*f585d8a3SJacky Wang             "test.Foo",
949*f585d8a3SJacky Wang             "package test;",
950*f585d8a3SJacky Wang             "",
951*f585d8a3SJacky Wang             "import java.util.Set;",
952*f585d8a3SJacky Wang             "import javax.inject.Inject;",
953*f585d8a3SJacky Wang             "",
954*f585d8a3SJacky Wang             "final class Foo {",
955*f585d8a3SJacky Wang             "  @Inject Foo(Set<String> strings) {}",
956*f585d8a3SJacky Wang             "}");
957*f585d8a3SJacky Wang     Source injected1 =
958*f585d8a3SJacky Wang         CompilerTests.javaSource(
959*f585d8a3SJacky Wang             "test.Injected1",
960*f585d8a3SJacky Wang             "package test;",
961*f585d8a3SJacky Wang             "",
962*f585d8a3SJacky Wang             "import dagger.Component;",
963*f585d8a3SJacky Wang             "import dagger.Module;",
964*f585d8a3SJacky Wang             "import dagger.Provides;",
965*f585d8a3SJacky Wang             "import dagger.multibindings.IntoSet;",
966*f585d8a3SJacky Wang             "import java.util.Set;",
967*f585d8a3SJacky Wang             "",
968*f585d8a3SJacky Wang             "@Component(modules = Injected1.Injected1Module.class)",
969*f585d8a3SJacky Wang             "interface Injected1 {",
970*f585d8a3SJacky Wang             "  Foo foo();",
971*f585d8a3SJacky Wang             "  Injected2 injected2();",
972*f585d8a3SJacky Wang             "",
973*f585d8a3SJacky Wang             "  @Module",
974*f585d8a3SJacky Wang             "  interface Injected1Module {",
975*f585d8a3SJacky Wang             "    @Provides @IntoSet static String string() {",
976*f585d8a3SJacky Wang             "      return \"injected1\";",
977*f585d8a3SJacky Wang             "    }",
978*f585d8a3SJacky Wang             "  }",
979*f585d8a3SJacky Wang             "}");
980*f585d8a3SJacky Wang     Source injected2 =
981*f585d8a3SJacky Wang         CompilerTests.javaSource(
982*f585d8a3SJacky Wang             "test.Injected2",
983*f585d8a3SJacky Wang             "package test;",
984*f585d8a3SJacky Wang             "",
985*f585d8a3SJacky Wang             "import dagger.Module;",
986*f585d8a3SJacky Wang             "import dagger.Provides;",
987*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
988*f585d8a3SJacky Wang             "import dagger.multibindings.IntoSet;",
989*f585d8a3SJacky Wang             "import java.util.Set;",
990*f585d8a3SJacky Wang             "",
991*f585d8a3SJacky Wang             "@Subcomponent(modules = Injected2.Injected2Module.class)",
992*f585d8a3SJacky Wang             "interface Injected2 {",
993*f585d8a3SJacky Wang             "  Foo foo();",
994*f585d8a3SJacky Wang             "  Provided1 provided1();",
995*f585d8a3SJacky Wang             "",
996*f585d8a3SJacky Wang             "  @Module",
997*f585d8a3SJacky Wang             "  interface Injected2Module {",
998*f585d8a3SJacky Wang             "    @Provides @IntoSet static String string() {",
999*f585d8a3SJacky Wang             "      return \"injected2\";",
1000*f585d8a3SJacky Wang             "    }",
1001*f585d8a3SJacky Wang             "  }",
1002*f585d8a3SJacky Wang             "}");
1003*f585d8a3SJacky Wang     Source provided1 =
1004*f585d8a3SJacky Wang         CompilerTests.javaSource(
1005*f585d8a3SJacky Wang             "test.Provided1",
1006*f585d8a3SJacky Wang             "package test;",
1007*f585d8a3SJacky Wang             "",
1008*f585d8a3SJacky Wang             "import dagger.Module;",
1009*f585d8a3SJacky Wang             "import dagger.Provides;",
1010*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
1011*f585d8a3SJacky Wang             "import dagger.multibindings.IntoSet;",
1012*f585d8a3SJacky Wang             "import java.util.Set;",
1013*f585d8a3SJacky Wang             "",
1014*f585d8a3SJacky Wang             "@Subcomponent(modules = Provided1.Provided1Module.class)",
1015*f585d8a3SJacky Wang             "interface Provided1 {",
1016*f585d8a3SJacky Wang             "  Foo foo();",
1017*f585d8a3SJacky Wang             "  Provided2 provided2();",
1018*f585d8a3SJacky Wang             "",
1019*f585d8a3SJacky Wang             "  @Module",
1020*f585d8a3SJacky Wang             "  static class Provided1Module {",
1021*f585d8a3SJacky Wang             "    @Provides static Foo provideFoo(Set<String> strings) {",
1022*f585d8a3SJacky Wang             "      return new Foo(strings);",
1023*f585d8a3SJacky Wang             "    }",
1024*f585d8a3SJacky Wang             "",
1025*f585d8a3SJacky Wang             "    @Provides @IntoSet static String string() {",
1026*f585d8a3SJacky Wang             "      return \"provided1\";",
1027*f585d8a3SJacky Wang             "    }",
1028*f585d8a3SJacky Wang             "  }",
1029*f585d8a3SJacky Wang             "}");
1030*f585d8a3SJacky Wang     Source provided2 =
1031*f585d8a3SJacky Wang         CompilerTests.javaSource(
1032*f585d8a3SJacky Wang             "test.Provided2",
1033*f585d8a3SJacky Wang             "package test;",
1034*f585d8a3SJacky Wang             "",
1035*f585d8a3SJacky Wang             "import dagger.Module;",
1036*f585d8a3SJacky Wang             "import dagger.Provides;",
1037*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
1038*f585d8a3SJacky Wang             "import dagger.multibindings.IntoSet;",
1039*f585d8a3SJacky Wang             "",
1040*f585d8a3SJacky Wang             "@Subcomponent(modules = Provided2.Provided2Module.class)",
1041*f585d8a3SJacky Wang             "interface Provided2 {",
1042*f585d8a3SJacky Wang             "  Foo foo();",
1043*f585d8a3SJacky Wang             "",
1044*f585d8a3SJacky Wang             "  @Module",
1045*f585d8a3SJacky Wang             "  static class Provided2Module {",
1046*f585d8a3SJacky Wang             "    @Provides @IntoSet static String string() {",
1047*f585d8a3SJacky Wang             "      return \"provided2\";",
1048*f585d8a3SJacky Wang             "    }",
1049*f585d8a3SJacky Wang             "  }",
1050*f585d8a3SJacky Wang             "}");
1051*f585d8a3SJacky Wang 
1052*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(foo, injected1, injected2, provided1, provided2)
1053*f585d8a3SJacky Wang         .compile(
1054*f585d8a3SJacky Wang             subject -> {
1055*f585d8a3SJacky Wang               subject.hasErrorCount(1);
1056*f585d8a3SJacky Wang               subject.hasErrorContaining(
1057*f585d8a3SJacky Wang                       message(
1058*f585d8a3SJacky Wang                           "Foo is bound multiple times:",
1059*f585d8a3SJacky Wang                           "    @Inject Foo(Set<String>) [Injected1]",
1060*f585d8a3SJacky Wang                           "    @Provides Foo Provided1.Provided1Module.provideFoo(Set<String>) "
1061*f585d8a3SJacky Wang                               + "[Injected1 → Injected2 → Provided1]"))
1062*f585d8a3SJacky Wang                   .onSource(injected1)
1063*f585d8a3SJacky Wang                   .onLineContaining("interface Injected1 {");
1064*f585d8a3SJacky Wang             });
1065*f585d8a3SJacky Wang   }
1066*f585d8a3SJacky Wang 
1067*f585d8a3SJacky Wang   @Test
grandchildBindingConflictsWithParentWithNullableViolationAsWarning()1068*f585d8a3SJacky Wang   public void grandchildBindingConflictsWithParentWithNullableViolationAsWarning() {
1069*f585d8a3SJacky Wang     Source parentConflictsWithChild =
1070*f585d8a3SJacky Wang         CompilerTests.javaSource(
1071*f585d8a3SJacky Wang             "test.ParentConflictsWithChild",
1072*f585d8a3SJacky Wang             "package test;",
1073*f585d8a3SJacky Wang             "",
1074*f585d8a3SJacky Wang             "import dagger.Component;",
1075*f585d8a3SJacky Wang             "import dagger.Module;",
1076*f585d8a3SJacky Wang             "import dagger.Provides;",
1077*f585d8a3SJacky Wang             "import javax.annotation.Nullable;",
1078*f585d8a3SJacky Wang             "",
1079*f585d8a3SJacky Wang             "@Component(modules = ParentConflictsWithChild.ParentModule.class)",
1080*f585d8a3SJacky Wang             "interface ParentConflictsWithChild {",
1081*f585d8a3SJacky Wang             "  Child.Builder child();",
1082*f585d8a3SJacky Wang             "",
1083*f585d8a3SJacky Wang             "  @Module(subcomponents = Child.class)",
1084*f585d8a3SJacky Wang             "  static class ParentModule {",
1085*f585d8a3SJacky Wang             "    @Provides @Nullable static Object nullableParentChildConflict() {",
1086*f585d8a3SJacky Wang             "      return \"parent\";",
1087*f585d8a3SJacky Wang             "    }",
1088*f585d8a3SJacky Wang             "  }",
1089*f585d8a3SJacky Wang             "}");
1090*f585d8a3SJacky Wang     Source child =
1091*f585d8a3SJacky Wang         CompilerTests.javaSource(
1092*f585d8a3SJacky Wang             "test.Child",
1093*f585d8a3SJacky Wang             "package test;",
1094*f585d8a3SJacky Wang             "",
1095*f585d8a3SJacky Wang             "import dagger.Module;",
1096*f585d8a3SJacky Wang             "import dagger.Provides;",
1097*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
1098*f585d8a3SJacky Wang             "",
1099*f585d8a3SJacky Wang             "@Subcomponent(modules = Child.ChildModule.class)",
1100*f585d8a3SJacky Wang             "interface Child {",
1101*f585d8a3SJacky Wang             "  Object parentChildConflictThatViolatesNullability();",
1102*f585d8a3SJacky Wang             "",
1103*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
1104*f585d8a3SJacky Wang             "  interface Builder {",
1105*f585d8a3SJacky Wang             "    Child build();",
1106*f585d8a3SJacky Wang             "  }",
1107*f585d8a3SJacky Wang             "",
1108*f585d8a3SJacky Wang             "  @Module",
1109*f585d8a3SJacky Wang             "  static class ChildModule {",
1110*f585d8a3SJacky Wang             "    @Provides static Object nonNullableParentChildConflict() {",
1111*f585d8a3SJacky Wang             "      return \"child\";",
1112*f585d8a3SJacky Wang             "    }",
1113*f585d8a3SJacky Wang             "  }",
1114*f585d8a3SJacky Wang             "}");
1115*f585d8a3SJacky Wang 
1116*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(parentConflictsWithChild, child)
1117*f585d8a3SJacky Wang         .withProcessingOptions(
1118*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
1119*f585d8a3SJacky Wang                 .put("dagger.nullableValidation", "WARNING")
1120*f585d8a3SJacky Wang                 .putAll(fullBindingGraphValidationOption())
1121*f585d8a3SJacky Wang                 .buildOrThrow())
1122*f585d8a3SJacky Wang         .compile(
1123*f585d8a3SJacky Wang             subject -> {
1124*f585d8a3SJacky Wang               String errorMessage =
1125*f585d8a3SJacky Wang                   message(
1126*f585d8a3SJacky Wang                       "Object is bound multiple times:",
1127*f585d8a3SJacky Wang                       "    @Provides Object Child.ChildModule.nonNullableParentChildConflict()",
1128*f585d8a3SJacky Wang                       "    @Provides @Nullable Object"
1129*f585d8a3SJacky Wang                           + " ParentConflictsWithChild.ParentModule.nullableParentChildConflict()");
1130*f585d8a3SJacky Wang               if (fullBindingGraphValidation) {
1131*f585d8a3SJacky Wang                 subject.hasErrorCount(2);
1132*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
1133*f585d8a3SJacky Wang                     .onSource(parentConflictsWithChild)
1134*f585d8a3SJacky Wang                     .onLineContaining("class ParentModule");
1135*f585d8a3SJacky Wang                 subject.hasErrorContaining(
1136*f585d8a3SJacky Wang                         "Object is not nullable, but is being provided by @Provides @Nullable "
1137*f585d8a3SJacky Wang                             + "Object")
1138*f585d8a3SJacky Wang                     .onSource(parentConflictsWithChild)
1139*f585d8a3SJacky Wang                     .onLineContaining("class ParentModule");
1140*f585d8a3SJacky Wang               } else {
1141*f585d8a3SJacky Wang                 subject.hasErrorCount(1);
1142*f585d8a3SJacky Wang                 subject.hasErrorContaining(errorMessage)
1143*f585d8a3SJacky Wang                     .onSource(parentConflictsWithChild)
1144*f585d8a3SJacky Wang                     .onLineContaining("interface ParentConflictsWithChild");
1145*f585d8a3SJacky Wang               }
1146*f585d8a3SJacky Wang             });
1147*f585d8a3SJacky Wang   }
1148*f585d8a3SJacky Wang 
fullBindingGraphValidationOption()1149*f585d8a3SJacky Wang   private ImmutableMap<String, String> fullBindingGraphValidationOption() {
1150*f585d8a3SJacky Wang     return ImmutableMap.of(
1151*f585d8a3SJacky Wang         "dagger.fullBindingGraphValidation",
1152*f585d8a3SJacky Wang         fullBindingGraphValidation ? "ERROR" : "NONE");
1153*f585d8a3SJacky Wang   }
1154*f585d8a3SJacky Wang 
1155*f585d8a3SJacky Wang   @Test
reportedInParentAndChild()1156*f585d8a3SJacky Wang   public void reportedInParentAndChild() {
1157*f585d8a3SJacky Wang     Source parent =
1158*f585d8a3SJacky Wang         CompilerTests.javaSource(
1159*f585d8a3SJacky Wang             "test.Parent",
1160*f585d8a3SJacky Wang             "package test;",
1161*f585d8a3SJacky Wang             "",
1162*f585d8a3SJacky Wang             "import dagger.Component;",
1163*f585d8a3SJacky Wang             "",
1164*f585d8a3SJacky Wang             "@Component(modules = ParentModule.class)",
1165*f585d8a3SJacky Wang             "interface Parent {",
1166*f585d8a3SJacky Wang             "  Child.Builder childBuilder();",
1167*f585d8a3SJacky Wang             "  String duplicated();",
1168*f585d8a3SJacky Wang             "}");
1169*f585d8a3SJacky Wang     Source parentModule =
1170*f585d8a3SJacky Wang         CompilerTests.javaSource(
1171*f585d8a3SJacky Wang             "test.ParentModule",
1172*f585d8a3SJacky Wang             "package test;",
1173*f585d8a3SJacky Wang             "",
1174*f585d8a3SJacky Wang             "import dagger.BindsOptionalOf;",
1175*f585d8a3SJacky Wang             "import dagger.Module;",
1176*f585d8a3SJacky Wang             "import dagger.Provides;",
1177*f585d8a3SJacky Wang             "import java.util.Optional;",
1178*f585d8a3SJacky Wang             "",
1179*f585d8a3SJacky Wang             "@Module",
1180*f585d8a3SJacky Wang             "interface ParentModule {",
1181*f585d8a3SJacky Wang             "  @Provides static String one(Optional<Object> optional) { return \"one\"; }",
1182*f585d8a3SJacky Wang             "  @Provides static String two() { return \"two\"; }",
1183*f585d8a3SJacky Wang             "  @BindsOptionalOf Object optional();",
1184*f585d8a3SJacky Wang             "}");
1185*f585d8a3SJacky Wang     Source child =
1186*f585d8a3SJacky Wang         CompilerTests.javaSource(
1187*f585d8a3SJacky Wang             "test.Child",
1188*f585d8a3SJacky Wang             "package test;",
1189*f585d8a3SJacky Wang             "",
1190*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
1191*f585d8a3SJacky Wang             "",
1192*f585d8a3SJacky Wang             "@Subcomponent(modules = ChildModule.class)",
1193*f585d8a3SJacky Wang             "interface Child {",
1194*f585d8a3SJacky Wang             "  String duplicated();",
1195*f585d8a3SJacky Wang             "",
1196*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
1197*f585d8a3SJacky Wang             "  interface Builder {",
1198*f585d8a3SJacky Wang             "    Child build();",
1199*f585d8a3SJacky Wang             "  }",
1200*f585d8a3SJacky Wang             "}");
1201*f585d8a3SJacky Wang     Source childModule =
1202*f585d8a3SJacky Wang         CompilerTests.javaSource(
1203*f585d8a3SJacky Wang             "test.ChildModule",
1204*f585d8a3SJacky Wang             "package test;",
1205*f585d8a3SJacky Wang             "",
1206*f585d8a3SJacky Wang             "import dagger.Module;",
1207*f585d8a3SJacky Wang             "import dagger.Provides;",
1208*f585d8a3SJacky Wang             "import java.util.Optional;",
1209*f585d8a3SJacky Wang             "",
1210*f585d8a3SJacky Wang             "@Module",
1211*f585d8a3SJacky Wang             "interface ChildModule {",
1212*f585d8a3SJacky Wang             "  @Provides static Object object() { return \"object\"; }",
1213*f585d8a3SJacky Wang             "}");
1214*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(parent, parentModule, child, childModule)
1215*f585d8a3SJacky Wang         .compile(
1216*f585d8a3SJacky Wang             subject -> {
1217*f585d8a3SJacky Wang               subject.hasErrorCount(1);
1218*f585d8a3SJacky Wang               subject.hasErrorContaining("String is bound multiple times")
1219*f585d8a3SJacky Wang                   .onSource(parent)
1220*f585d8a3SJacky Wang                   .onLineContaining("interface Parent");
1221*f585d8a3SJacky Wang             });
1222*f585d8a3SJacky Wang   }
1223*f585d8a3SJacky Wang 
1224*f585d8a3SJacky Wang   // Tests the format of the error for a somewhat complex binding method.
1225*f585d8a3SJacky Wang   @Test
formatTest()1226*f585d8a3SJacky Wang   public void formatTest() {
1227*f585d8a3SJacky Wang     Source modules =
1228*f585d8a3SJacky Wang         CompilerTests.javaSource(
1229*f585d8a3SJacky Wang             "test.Modules",
1230*f585d8a3SJacky Wang             "package test;",
1231*f585d8a3SJacky Wang             "",
1232*f585d8a3SJacky Wang             "import com.google.common.collect.ImmutableList;",
1233*f585d8a3SJacky Wang             "import dagger.Module;",
1234*f585d8a3SJacky Wang             "import dagger.Provides;",
1235*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
1236*f585d8a3SJacky Wang             "",
1237*f585d8a3SJacky Wang             "interface Modules {",
1238*f585d8a3SJacky Wang             "  @interface Foo {",
1239*f585d8a3SJacky Wang             "    Class<?> bar();",
1240*f585d8a3SJacky Wang             "  }",
1241*f585d8a3SJacky Wang             "",
1242*f585d8a3SJacky Wang             "  @Module",
1243*f585d8a3SJacky Wang             "  interface Module1 {",
1244*f585d8a3SJacky Wang             "    @Provides",
1245*f585d8a3SJacky Wang             "    @Singleton",
1246*f585d8a3SJacky Wang             "    @Foo(bar = String.class)",
1247*f585d8a3SJacky Wang             "    static String foo(",
1248*f585d8a3SJacky Wang             "        @SuppressWarnings(\"unused\") int a,",
1249*f585d8a3SJacky Wang             "        @SuppressWarnings(\"unused\") ImmutableList<Boolean> blah) {",
1250*f585d8a3SJacky Wang             "      return \"\";",
1251*f585d8a3SJacky Wang             "    }",
1252*f585d8a3SJacky Wang             "  }",
1253*f585d8a3SJacky Wang             "",
1254*f585d8a3SJacky Wang             "  @Module",
1255*f585d8a3SJacky Wang             "  interface Module2 {",
1256*f585d8a3SJacky Wang             "    @Provides",
1257*f585d8a3SJacky Wang             "    @Singleton",
1258*f585d8a3SJacky Wang             "    @Foo(bar = String.class)",
1259*f585d8a3SJacky Wang             "    static String foo(",
1260*f585d8a3SJacky Wang             "        @SuppressWarnings(\"unused\") int a,",
1261*f585d8a3SJacky Wang             "        @SuppressWarnings(\"unused\") ImmutableList<Boolean> blah) {",
1262*f585d8a3SJacky Wang             "      return \"\";",
1263*f585d8a3SJacky Wang             "    }",
1264*f585d8a3SJacky Wang             "  }",
1265*f585d8a3SJacky Wang             "}");
1266*f585d8a3SJacky Wang     Source component =
1267*f585d8a3SJacky Wang         CompilerTests.javaSource(
1268*f585d8a3SJacky Wang             "test.TestComponent",
1269*f585d8a3SJacky Wang             "package test;",
1270*f585d8a3SJacky Wang             "",
1271*f585d8a3SJacky Wang             "import dagger.BindsInstance;",
1272*f585d8a3SJacky Wang             "import dagger.Component;",
1273*f585d8a3SJacky Wang             "import javax.inject.Singleton;",
1274*f585d8a3SJacky Wang             "",
1275*f585d8a3SJacky Wang             "@Singleton",
1276*f585d8a3SJacky Wang             "@Component(modules = {Modules.Module1.class, Modules.Module2.class})",
1277*f585d8a3SJacky Wang             "interface TestComponent {",
1278*f585d8a3SJacky Wang             "  @Modules.Foo(bar = String.class) String foo();",
1279*f585d8a3SJacky Wang             "}");
1280*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(modules, component)
1281*f585d8a3SJacky Wang         .compile(
1282*f585d8a3SJacky Wang             subject -> {
1283*f585d8a3SJacky Wang               subject.hasErrorCount(1);
1284*f585d8a3SJacky Wang               subject.hasErrorContaining(
1285*f585d8a3SJacky Wang                   String.format(
1286*f585d8a3SJacky Wang                       String.join(
1287*f585d8a3SJacky Wang                           "\n",
1288*f585d8a3SJacky Wang                           "String is bound multiple times:",
1289*f585d8a3SJacky Wang                           "    @Provides @Singleton @Modules.Foo(%1$s) String "
1290*f585d8a3SJacky Wang                               + "Modules.Module1.foo(int, ImmutableList<Boolean>)",
1291*f585d8a3SJacky Wang                           "    @Provides @Singleton @Modules.Foo(%1$s) String "
1292*f585d8a3SJacky Wang                               + "Modules.Module2.foo(int, ImmutableList<Boolean>)"),
1293*f585d8a3SJacky Wang                       // TODO(b/241293838): KSP and java should match after this is fixed.
1294*f585d8a3SJacky Wang                       CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP
1295*f585d8a3SJacky Wang                           ? "bar=String"
1296*f585d8a3SJacky Wang                           : "bar = String.class"));
1297*f585d8a3SJacky Wang             });
1298*f585d8a3SJacky Wang   }
1299*f585d8a3SJacky Wang }
1300