1*f585d8a3SJacky Wang /*
2*f585d8a3SJacky Wang  * Copyright (C) 2020 The Dagger Authors.
3*f585d8a3SJacky Wang  *
4*f585d8a3SJacky Wang  * Licensed under the Apache License, Version 2.0 (the "License");
5*f585d8a3SJacky Wang  * you may not use this file except in compliance with the License.
6*f585d8a3SJacky Wang  * You may obtain a copy of the License at
7*f585d8a3SJacky Wang  *
8*f585d8a3SJacky Wang  * http://www.apache.org/licenses/LICENSE-2.0
9*f585d8a3SJacky Wang  *
10*f585d8a3SJacky Wang  * Unless required by applicable law or agreed to in writing, software
11*f585d8a3SJacky Wang  * distributed under the License is distributed on an "AS IS" BASIS,
12*f585d8a3SJacky Wang  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f585d8a3SJacky Wang  * See the License for the specific language governing permissions and
14*f585d8a3SJacky Wang  * limitations under the License.
15*f585d8a3SJacky Wang  */
16*f585d8a3SJacky Wang 
17*f585d8a3SJacky Wang package dagger.internal.codegen;
18*f585d8a3SJacky Wang 
19*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source;
20*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList;
21*f585d8a3SJacky Wang import com.google.common.collect.ImmutableMap;
22*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests;
23*f585d8a3SJacky Wang import org.junit.Test;
24*f585d8a3SJacky Wang import org.junit.runner.RunWith;
25*f585d8a3SJacky Wang import org.junit.runners.Parameterized;
26*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters;
27*f585d8a3SJacky Wang 
28*f585d8a3SJacky Wang /**
29*f585d8a3SJacky Wang  * Tests to make sure that delegate bindings where the impl depends on a binding in a subcomponent
30*f585d8a3SJacky Wang  * properly fail. These are regression tests for b/147020838.
31*f585d8a3SJacky Wang  */
32*f585d8a3SJacky Wang @RunWith(Parameterized.class)
33*f585d8a3SJacky Wang public class BindsDependsOnSubcomponentValidationTest {
34*f585d8a3SJacky Wang   @Parameters(name = "{0}")
parameters()35*f585d8a3SJacky Wang   public static ImmutableList<Object[]> parameters() {
36*f585d8a3SJacky Wang     return CompilerMode.TEST_PARAMETERS;
37*f585d8a3SJacky Wang   }
38*f585d8a3SJacky Wang 
39*f585d8a3SJacky Wang   private final CompilerMode compilerMode;
40*f585d8a3SJacky Wang 
BindsDependsOnSubcomponentValidationTest(CompilerMode compilerMode)41*f585d8a3SJacky Wang   public BindsDependsOnSubcomponentValidationTest(CompilerMode compilerMode) {
42*f585d8a3SJacky Wang     this.compilerMode = compilerMode;
43*f585d8a3SJacky Wang   }
44*f585d8a3SJacky Wang 
45*f585d8a3SJacky Wang   @Test
testBinds()46*f585d8a3SJacky Wang   public void testBinds() {
47*f585d8a3SJacky Wang     Source parentComponent =
48*f585d8a3SJacky Wang         CompilerTests.javaSource(
49*f585d8a3SJacky Wang             "test.ParentComponent",
50*f585d8a3SJacky Wang             "package test;",
51*f585d8a3SJacky Wang             "",
52*f585d8a3SJacky Wang             "import dagger.Component;",
53*f585d8a3SJacky Wang             "",
54*f585d8a3SJacky Wang             "@Component(modules = ParentModule.class)",
55*f585d8a3SJacky Wang             "interface ParentComponent {",
56*f585d8a3SJacky Wang             "  ChildComponent getChild();",
57*f585d8a3SJacky Wang             "}");
58*f585d8a3SJacky Wang     Source parentModule =
59*f585d8a3SJacky Wang         CompilerTests.javaSource(
60*f585d8a3SJacky Wang             "test.ParentModule",
61*f585d8a3SJacky Wang             "package test;",
62*f585d8a3SJacky Wang             "",
63*f585d8a3SJacky Wang             "import dagger.Binds;",
64*f585d8a3SJacky Wang             "import dagger.Module;",
65*f585d8a3SJacky Wang             "",
66*f585d8a3SJacky Wang             "@Module",
67*f585d8a3SJacky Wang             "interface ParentModule {",
68*f585d8a3SJacky Wang             "  @Binds Foo bindFoo(FooImpl impl);",
69*f585d8a3SJacky Wang             "}");
70*f585d8a3SJacky Wang     Source childComponent =
71*f585d8a3SJacky Wang         CompilerTests.javaSource(
72*f585d8a3SJacky Wang             "test.ChildComponent",
73*f585d8a3SJacky Wang             "package test;",
74*f585d8a3SJacky Wang             "",
75*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
76*f585d8a3SJacky Wang             "",
77*f585d8a3SJacky Wang             "@Subcomponent(modules = ChildModule.class)",
78*f585d8a3SJacky Wang             "interface ChildComponent {",
79*f585d8a3SJacky Wang             "  Foo getFoo();",
80*f585d8a3SJacky Wang             "}");
81*f585d8a3SJacky Wang     Source childModule =
82*f585d8a3SJacky Wang         CompilerTests.javaSource(
83*f585d8a3SJacky Wang             "test.ChildModule",
84*f585d8a3SJacky Wang             "package test;",
85*f585d8a3SJacky Wang             "",
86*f585d8a3SJacky Wang             "import dagger.Module;",
87*f585d8a3SJacky Wang             "import dagger.Provides;",
88*f585d8a3SJacky Wang             "",
89*f585d8a3SJacky Wang             "@Module",
90*f585d8a3SJacky Wang             "interface ChildModule {",
91*f585d8a3SJacky Wang             "  @Provides static Long providLong() {",
92*f585d8a3SJacky Wang             "    return 0L;",
93*f585d8a3SJacky Wang             "  }",
94*f585d8a3SJacky Wang             "}");
95*f585d8a3SJacky Wang     Source iface =
96*f585d8a3SJacky Wang         CompilerTests.javaSource(
97*f585d8a3SJacky Wang             "test.Foo",
98*f585d8a3SJacky Wang             "package test;",
99*f585d8a3SJacky Wang             "",
100*f585d8a3SJacky Wang             "interface Foo {}");
101*f585d8a3SJacky Wang     Source impl =
102*f585d8a3SJacky Wang         CompilerTests.javaSource(
103*f585d8a3SJacky Wang             "test.FooImpl",
104*f585d8a3SJacky Wang             "package test;",
105*f585d8a3SJacky Wang             "",
106*f585d8a3SJacky Wang             "import javax.inject.Inject;",
107*f585d8a3SJacky Wang             "",
108*f585d8a3SJacky Wang             "class FooImpl implements Foo {",
109*f585d8a3SJacky Wang             "  @Inject FooImpl(Long l) {}",
110*f585d8a3SJacky Wang             "}");
111*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
112*f585d8a3SJacky Wang             parentComponent, parentModule, childComponent, childModule, iface, impl)
113*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
114*f585d8a3SJacky Wang         .compile(
115*f585d8a3SJacky Wang             subject -> {
116*f585d8a3SJacky Wang               subject.hasErrorCount(1);
117*f585d8a3SJacky Wang               subject.hasErrorContaining("Long cannot be provided without an @Inject constructor")
118*f585d8a3SJacky Wang                   .onSource(parentComponent)
119*f585d8a3SJacky Wang                   .onLineContaining("interface ParentComponent");
120*f585d8a3SJacky Wang             });
121*f585d8a3SJacky Wang   }
122*f585d8a3SJacky Wang 
123*f585d8a3SJacky Wang   @Test
testSetBindings()124*f585d8a3SJacky Wang   public void testSetBindings() {
125*f585d8a3SJacky Wang     Source parentComponent =
126*f585d8a3SJacky Wang         CompilerTests.javaSource(
127*f585d8a3SJacky Wang             "test.ParentComponent",
128*f585d8a3SJacky Wang             "package test;",
129*f585d8a3SJacky Wang             "",
130*f585d8a3SJacky Wang             "import dagger.Component;",
131*f585d8a3SJacky Wang             "",
132*f585d8a3SJacky Wang             "@Component(modules = ParentModule.class)",
133*f585d8a3SJacky Wang             "interface ParentComponent {",
134*f585d8a3SJacky Wang             "  ChildComponent getChild();",
135*f585d8a3SJacky Wang             "}");
136*f585d8a3SJacky Wang     Source parentModule =
137*f585d8a3SJacky Wang         CompilerTests.javaSource(
138*f585d8a3SJacky Wang             "test.ParentModule",
139*f585d8a3SJacky Wang             "package test;",
140*f585d8a3SJacky Wang             "",
141*f585d8a3SJacky Wang             "import dagger.Binds;",
142*f585d8a3SJacky Wang             "import dagger.Module;",
143*f585d8a3SJacky Wang             "import dagger.multibindings.IntoSet;",
144*f585d8a3SJacky Wang             "",
145*f585d8a3SJacky Wang             "@Module",
146*f585d8a3SJacky Wang             "interface ParentModule {",
147*f585d8a3SJacky Wang             "  @Binds @IntoSet Foo bindFoo(FooImpl impl);",
148*f585d8a3SJacky Wang             "}");
149*f585d8a3SJacky Wang     Source childComponent =
150*f585d8a3SJacky Wang         CompilerTests.javaSource(
151*f585d8a3SJacky Wang             "test.ChildComponent",
152*f585d8a3SJacky Wang             "package test;",
153*f585d8a3SJacky Wang             "",
154*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
155*f585d8a3SJacky Wang             "import java.util.Set;",
156*f585d8a3SJacky Wang             "",
157*f585d8a3SJacky Wang             "@Subcomponent(modules = ChildModule.class)",
158*f585d8a3SJacky Wang             "interface ChildComponent {",
159*f585d8a3SJacky Wang             "  Set<Foo> getFooSet();",
160*f585d8a3SJacky Wang             "}");
161*f585d8a3SJacky Wang     Source childModule =
162*f585d8a3SJacky Wang         CompilerTests.javaSource(
163*f585d8a3SJacky Wang             "test.ChildModule",
164*f585d8a3SJacky Wang             "package test;",
165*f585d8a3SJacky Wang             "",
166*f585d8a3SJacky Wang             "import dagger.Module;",
167*f585d8a3SJacky Wang             "import dagger.Provides;",
168*f585d8a3SJacky Wang             "",
169*f585d8a3SJacky Wang             "@Module",
170*f585d8a3SJacky Wang             "interface ChildModule {",
171*f585d8a3SJacky Wang             "  @Provides static Long providLong() {",
172*f585d8a3SJacky Wang             "    return 0L;",
173*f585d8a3SJacky Wang             "  }",
174*f585d8a3SJacky Wang             "}");
175*f585d8a3SJacky Wang     Source iface =
176*f585d8a3SJacky Wang         CompilerTests.javaSource(
177*f585d8a3SJacky Wang             "test.Foo",
178*f585d8a3SJacky Wang             "package test;",
179*f585d8a3SJacky Wang             "",
180*f585d8a3SJacky Wang             "interface Foo {}");
181*f585d8a3SJacky Wang     Source impl =
182*f585d8a3SJacky Wang         CompilerTests.javaSource(
183*f585d8a3SJacky Wang             "test.FooImpl",
184*f585d8a3SJacky Wang             "package test;",
185*f585d8a3SJacky Wang             "",
186*f585d8a3SJacky Wang             "import javax.inject.Inject;",
187*f585d8a3SJacky Wang             "",
188*f585d8a3SJacky Wang             "class FooImpl implements Foo {",
189*f585d8a3SJacky Wang             "  @Inject FooImpl(Long l) {}",
190*f585d8a3SJacky Wang             "}");
191*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
192*f585d8a3SJacky Wang             parentComponent, parentModule, childComponent, childModule, iface, impl)
193*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
194*f585d8a3SJacky Wang         .compile(
195*f585d8a3SJacky Wang             subject -> {
196*f585d8a3SJacky Wang               subject.hasErrorCount(1);
197*f585d8a3SJacky Wang               subject.hasErrorContaining("Long cannot be provided without an @Inject constructor")
198*f585d8a3SJacky Wang                   .onSource(parentComponent)
199*f585d8a3SJacky Wang                   .onLineContaining("interface ParentComponent");
200*f585d8a3SJacky Wang             });
201*f585d8a3SJacky Wang   }
202*f585d8a3SJacky Wang 
203*f585d8a3SJacky Wang   @Test
testSetValueBindings()204*f585d8a3SJacky Wang   public void testSetValueBindings() {
205*f585d8a3SJacky Wang     Source parentComponent =
206*f585d8a3SJacky Wang         CompilerTests.javaSource(
207*f585d8a3SJacky Wang             "test.ParentComponent",
208*f585d8a3SJacky Wang             "package test;",
209*f585d8a3SJacky Wang             "",
210*f585d8a3SJacky Wang             "import dagger.Component;",
211*f585d8a3SJacky Wang             "",
212*f585d8a3SJacky Wang             "@Component(modules = ParentModule.class)",
213*f585d8a3SJacky Wang             "interface ParentComponent {",
214*f585d8a3SJacky Wang             "  ChildComponent getChild();",
215*f585d8a3SJacky Wang             "}");
216*f585d8a3SJacky Wang     Source parentModule =
217*f585d8a3SJacky Wang         CompilerTests.javaSource(
218*f585d8a3SJacky Wang             "test.ParentModule",
219*f585d8a3SJacky Wang             "package test;",
220*f585d8a3SJacky Wang             "",
221*f585d8a3SJacky Wang             "import dagger.Module;",
222*f585d8a3SJacky Wang             "import dagger.Provides;",
223*f585d8a3SJacky Wang             "import dagger.multibindings.ElementsIntoSet;",
224*f585d8a3SJacky Wang             "import java.util.Collections;",
225*f585d8a3SJacky Wang             "import java.util.Set;",
226*f585d8a3SJacky Wang             "",
227*f585d8a3SJacky Wang             "@Module",
228*f585d8a3SJacky Wang             "interface ParentModule {",
229*f585d8a3SJacky Wang             "  @Provides @ElementsIntoSet",
230*f585d8a3SJacky Wang             "  static Set<Foo> provideFoo(FooImpl impl) {",
231*f585d8a3SJacky Wang             "    return Collections.singleton(impl);",
232*f585d8a3SJacky Wang             "  }",
233*f585d8a3SJacky Wang             "}");
234*f585d8a3SJacky Wang     Source childComponent =
235*f585d8a3SJacky Wang         CompilerTests.javaSource(
236*f585d8a3SJacky Wang             "test.ChildComponent",
237*f585d8a3SJacky Wang             "package test;",
238*f585d8a3SJacky Wang             "",
239*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
240*f585d8a3SJacky Wang             "import java.util.Set;",
241*f585d8a3SJacky Wang             "",
242*f585d8a3SJacky Wang             "@Subcomponent(modules = ChildModule.class)",
243*f585d8a3SJacky Wang             "interface ChildComponent {",
244*f585d8a3SJacky Wang             "  Set<Foo> getFooSet();",
245*f585d8a3SJacky Wang             "}");
246*f585d8a3SJacky Wang     Source childModule =
247*f585d8a3SJacky Wang         CompilerTests.javaSource(
248*f585d8a3SJacky Wang             "test.ChildModule",
249*f585d8a3SJacky Wang             "package test;",
250*f585d8a3SJacky Wang             "",
251*f585d8a3SJacky Wang             "import dagger.Module;",
252*f585d8a3SJacky Wang             "import dagger.Provides;",
253*f585d8a3SJacky Wang             "",
254*f585d8a3SJacky Wang             "@Module",
255*f585d8a3SJacky Wang             "interface ChildModule {",
256*f585d8a3SJacky Wang             "  @Provides static Long providLong() {",
257*f585d8a3SJacky Wang             "    return 0L;",
258*f585d8a3SJacky Wang             "  }",
259*f585d8a3SJacky Wang             "}");
260*f585d8a3SJacky Wang     Source iface =
261*f585d8a3SJacky Wang         CompilerTests.javaSource(
262*f585d8a3SJacky Wang             "test.Foo",
263*f585d8a3SJacky Wang             "package test;",
264*f585d8a3SJacky Wang             "",
265*f585d8a3SJacky Wang             "interface Foo {}");
266*f585d8a3SJacky Wang     Source impl =
267*f585d8a3SJacky Wang         CompilerTests.javaSource(
268*f585d8a3SJacky Wang             "test.FooImpl",
269*f585d8a3SJacky Wang             "package test;",
270*f585d8a3SJacky Wang             "",
271*f585d8a3SJacky Wang             "import javax.inject.Inject;",
272*f585d8a3SJacky Wang             "",
273*f585d8a3SJacky Wang             "class FooImpl implements Foo {",
274*f585d8a3SJacky Wang             "  @Inject FooImpl(Long l) {}",
275*f585d8a3SJacky Wang             "}");
276*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
277*f585d8a3SJacky Wang             parentComponent, parentModule, childComponent, childModule, iface, impl)
278*f585d8a3SJacky Wang         .withProcessingOptions(compilerMode.processorOptions())
279*f585d8a3SJacky Wang         .compile(
280*f585d8a3SJacky Wang             subject -> {
281*f585d8a3SJacky Wang               subject.hasErrorCount(1);
282*f585d8a3SJacky Wang               subject.hasErrorContaining("Long cannot be provided without an @Inject constructor")
283*f585d8a3SJacky Wang                   .onSource(parentComponent)
284*f585d8a3SJacky Wang                   .onLineContaining("interface ParentComponent");
285*f585d8a3SJacky Wang             });
286*f585d8a3SJacky Wang   }
287*f585d8a3SJacky Wang 
288*f585d8a3SJacky Wang   @Test
testMapBindings()289*f585d8a3SJacky Wang   public void testMapBindings() {
290*f585d8a3SJacky Wang     Source parentComponent =
291*f585d8a3SJacky Wang         CompilerTests.javaSource(
292*f585d8a3SJacky Wang             "test.ParentComponent",
293*f585d8a3SJacky Wang             "package test;",
294*f585d8a3SJacky Wang             "",
295*f585d8a3SJacky Wang             "import dagger.Component;",
296*f585d8a3SJacky Wang             "",
297*f585d8a3SJacky Wang             "@Component(modules = ParentModule.class)",
298*f585d8a3SJacky Wang             "interface ParentComponent {",
299*f585d8a3SJacky Wang             "  ChildComponent getChild();",
300*f585d8a3SJacky Wang             "}");
301*f585d8a3SJacky Wang     Source parentModule =
302*f585d8a3SJacky Wang         CompilerTests.javaSource(
303*f585d8a3SJacky Wang             "test.ParentModule",
304*f585d8a3SJacky Wang             "package test;",
305*f585d8a3SJacky Wang             "",
306*f585d8a3SJacky Wang             "import dagger.Binds;",
307*f585d8a3SJacky Wang             "import dagger.Module;",
308*f585d8a3SJacky Wang             "import dagger.multibindings.IntoMap;",
309*f585d8a3SJacky Wang             "import dagger.multibindings.StringKey;",
310*f585d8a3SJacky Wang             "",
311*f585d8a3SJacky Wang             "@Module",
312*f585d8a3SJacky Wang             "interface ParentModule {",
313*f585d8a3SJacky Wang             "  @Binds @IntoMap @StringKey(\"foo\") Foo bindFoo(FooImpl impl);",
314*f585d8a3SJacky Wang             "}");
315*f585d8a3SJacky Wang     Source childComponent =
316*f585d8a3SJacky Wang         CompilerTests.javaSource(
317*f585d8a3SJacky Wang             "test.ChildComponent",
318*f585d8a3SJacky Wang             "package test;",
319*f585d8a3SJacky Wang             "",
320*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
321*f585d8a3SJacky Wang             "import java.util.Map;",
322*f585d8a3SJacky Wang             "",
323*f585d8a3SJacky Wang             "@Subcomponent(modules = ChildModule.class)",
324*f585d8a3SJacky Wang             "interface ChildComponent {",
325*f585d8a3SJacky Wang             "  Map<String, Foo> getFooSet();",
326*f585d8a3SJacky Wang             "}");
327*f585d8a3SJacky Wang     Source childModule =
328*f585d8a3SJacky Wang         CompilerTests.javaSource(
329*f585d8a3SJacky Wang             "test.ChildModule",
330*f585d8a3SJacky Wang             "package test;",
331*f585d8a3SJacky Wang             "",
332*f585d8a3SJacky Wang             "import dagger.Module;",
333*f585d8a3SJacky Wang             "import dagger.Provides;",
334*f585d8a3SJacky Wang             "",
335*f585d8a3SJacky Wang             "@Module",
336*f585d8a3SJacky Wang             "interface ChildModule {",
337*f585d8a3SJacky Wang             "  @Provides static Long providLong() {",
338*f585d8a3SJacky Wang             "    return 0L;",
339*f585d8a3SJacky Wang             "  }",
340*f585d8a3SJacky Wang             "}");
341*f585d8a3SJacky Wang     Source iface =
342*f585d8a3SJacky Wang         CompilerTests.javaSource(
343*f585d8a3SJacky Wang             "test.Foo",
344*f585d8a3SJacky Wang             "package test;",
345*f585d8a3SJacky Wang             "",
346*f585d8a3SJacky Wang             "interface Foo {}");
347*f585d8a3SJacky Wang     Source impl =
348*f585d8a3SJacky Wang         CompilerTests.javaSource(
349*f585d8a3SJacky Wang             "test.FooImpl",
350*f585d8a3SJacky Wang             "package test;",
351*f585d8a3SJacky Wang             "",
352*f585d8a3SJacky Wang             "import javax.inject.Inject;",
353*f585d8a3SJacky Wang             "",
354*f585d8a3SJacky Wang             "class FooImpl implements Foo {",
355*f585d8a3SJacky Wang             "  @Inject FooImpl(Long l) {}",
356*f585d8a3SJacky Wang             "}");
357*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
358*f585d8a3SJacky Wang             parentComponent, parentModule, childComponent, childModule, iface, impl)
359*f585d8a3SJacky Wang         .withProcessingOptions(
360*f585d8a3SJacky Wang             ImmutableMap.<String, String>builder()
361*f585d8a3SJacky Wang                 .putAll(compilerMode.processorOptions())
362*f585d8a3SJacky Wang                 // TODO(erichang): make this flag the default and remove this
363*f585d8a3SJacky Wang                 .put("dagger.strictMultibindingValidation", "enabled")
364*f585d8a3SJacky Wang                 .build())
365*f585d8a3SJacky Wang         .compile(
366*f585d8a3SJacky Wang             subject -> {
367*f585d8a3SJacky Wang               subject.hasErrorCount(1);
368*f585d8a3SJacky Wang               subject.hasErrorContaining("Long cannot be provided without an @Inject constructor")
369*f585d8a3SJacky Wang                   .onSource(parentComponent)
370*f585d8a3SJacky Wang                   .onLineContaining("interface ParentComponent");
371*f585d8a3SJacky Wang             });
372*f585d8a3SJacky Wang   }
373*f585d8a3SJacky Wang }
374