1 /*
2  * Copyright (C) 2020 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.functional.assisted;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import dagger.Component;
22 import dagger.assisted.Assisted;
23 import dagger.assisted.AssistedFactory;
24 import dagger.assisted.AssistedInject;
25 import javax.inject.Inject;
26 import javax.inject.Provider;
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 import org.junit.runners.JUnit4;
30 
31 @RunWith(JUnit4.class)
32 public final class AssistedFactoryTest {
33   @Component
34   interface ParentComponent {
35     // Simple factory using a nested factory.
nestedSimpleFooFactory()36     SimpleFoo.Factory nestedSimpleFooFactory();
37 
38     // Simple factory using a non-nested factory.
nonNestedSimpleFooFactory()39     SimpleFooFactory nonNestedSimpleFooFactory();
40 
41     // Simple factory using a factory that extends a supertype.
extendedSimpleFooFactory()42     ExtendedSimpleFooFactory extendedSimpleFooFactory();
43 
44     // Factory as interface
fooFactory()45     FooFactory fooFactory();
46 
47     // Factory as abstract class
abstractFooFactory()48     AbstractFooFactory abstractFooFactory();
49 
50     // Factory without any assisted parameters
noAssistedParametersFooFactory()51     NoAssistedParametersFooFactory noAssistedParametersFooFactory();
52 
53     // Test injecting the factories from another class
someEntryPoint()54     SomeEntryPoint someEntryPoint();
55   }
56 
57   // This class tests the request of factories from another binding.
58   static class SomeEntryPoint {
59     private final SimpleFoo.Factory nestedSimpleFooFactory;
60     private final SimpleFooFactory nonNestedSimpleFooFactory;
61     private final ExtendedSimpleFooFactory extendedSimpleFooFactory;
62     private final FooFactory fooFactory;
63     private final AbstractFooFactory abstractFooFactory;
64     private final NoAssistedParametersFooFactory noAssistedParametersFooFactory;
65 
66     @Inject
SomeEntryPoint( SimpleFoo.Factory nestedSimpleFooFactory, SimpleFooFactory nonNestedSimpleFooFactory, ExtendedSimpleFooFactory extendedSimpleFooFactory, FooFactory fooFactory, AbstractFooFactory abstractFooFactory, NoAssistedParametersFooFactory noAssistedParametersFooFactory)67     SomeEntryPoint(
68         SimpleFoo.Factory nestedSimpleFooFactory,
69         SimpleFooFactory nonNestedSimpleFooFactory,
70         ExtendedSimpleFooFactory extendedSimpleFooFactory,
71         FooFactory fooFactory,
72         AbstractFooFactory abstractFooFactory,
73         NoAssistedParametersFooFactory noAssistedParametersFooFactory) {
74       this.nestedSimpleFooFactory = nestedSimpleFooFactory;
75       this.nonNestedSimpleFooFactory = nonNestedSimpleFooFactory;
76       this.extendedSimpleFooFactory = extendedSimpleFooFactory;
77       this.fooFactory = fooFactory;
78       this.abstractFooFactory = abstractFooFactory;
79       this.noAssistedParametersFooFactory = noAssistedParametersFooFactory;
80     }
81   }
82 
83   static final class Dep1 {
84     @Inject
Dep1(Dep2 dep2, Dep3 dep3)85     Dep1(Dep2 dep2, Dep3 dep3) {}
86   }
87 
88   static final class Dep2 {
89     @Inject
Dep2(Dep3 dep3)90     Dep2(Dep3 dep3) {}
91   }
92 
93   static final class Dep3 {
94     @Inject
Dep3(Dep4 dep4)95     Dep3(Dep4 dep4) {}
96   }
97 
98   static final class Dep4 {
99     @Inject
Dep4()100     Dep4() {}
101   }
102 
103   // A base interface to test that factories can reference subclasses of the assisted parameter.
104   interface AssistedDep {}
105 
106   static final class AssistedDep1 implements AssistedDep {}
107 
108   static final class AssistedDep2 implements AssistedDep {}
109 
110   static final class SimpleFoo {
111     private final AssistedDep assistedDep;
112 
113     @AssistedInject
SimpleFoo(@ssisted AssistedDep assistedDep)114     SimpleFoo(@Assisted AssistedDep assistedDep) {
115       this.assistedDep = assistedDep;
116     }
117 
118     @AssistedFactory
119     interface Factory {
120       // Use different parameter names than Foo to make sure we're not assuming they're the same.
createSimpleFoo(AssistedDep factoryAssistedDep)121       SimpleFoo createSimpleFoo(AssistedDep factoryAssistedDep);
122 
123       // A no-op method to test static methods in assisted factories
staticMethod()124       static void staticMethod() {
125         return;
126       }
127 
128       // A no-op method to test default methods in assisted factories
defaultMethod()129       default void defaultMethod() {
130         return;
131       }
132     }
133   }
134 
135   @AssistedFactory
136   interface SimpleFooFactory {
137     // Use different parameter names than Foo to make sure we're not assuming they're the same.
createSimpleFoo(AssistedDep factoryAssistedDep1)138     SimpleFoo createSimpleFoo(AssistedDep factoryAssistedDep1);
139 
140     // A no-op method to test static methods are allowed
staticMethod()141     static void staticMethod() {
142       return;
143     }
144 
145     // A no-op method to test static methods that return assisted type are allowed
staticSimpleFooMethod()146     static SimpleFoo staticSimpleFooMethod() {
147       return null;
148     }
149 
150     // A no-op method to test default methods are allowed
defaultMethod()151     default void defaultMethod() {
152       return;
153     }
154 
155     // A no-op method to test default methods that return assisted type are allowed
defaultSimpleFooMethod()156     default SimpleFoo defaultSimpleFooMethod() {
157       return null;
158     }
159   }
160 
161   @AssistedFactory
162   interface ExtendedSimpleFooFactory extends SimpleFooFactory {}
163 
164   abstract static class BaseFoo {
165     @Inject Dep4 dep4;
166   }
167 
168   static final class Foo extends BaseFoo {
169     private final Dep1 dep1;
170     private final Provider<Dep2> dep2Provider;
171     private final AssistedDep1 assistedDep1;
172     private final AssistedDep2 assistedDep2;
173     private final int assistedInt;
174     private final FooFactory factory;
175 
176     @Inject Dep3 dep3;
177 
178     @AssistedInject
Foo( Dep1 dep1, @Assisted AssistedDep1 assistedDep1, Provider<Dep2> dep2Provider, @Assisted AssistedDep2 assistedDep2, @Assisted int assistedInt, FooFactory factory)179     Foo(
180         Dep1 dep1,
181         @Assisted AssistedDep1 assistedDep1,
182         Provider<Dep2> dep2Provider,
183         @Assisted AssistedDep2 assistedDep2,
184         @Assisted int assistedInt,
185         FooFactory factory) {
186       this.dep1 = dep1;
187       this.dep2Provider = dep2Provider;
188       this.assistedDep1 = assistedDep1;
189       this.assistedDep2 = assistedDep2;
190       this.assistedInt = assistedInt;
191       this.factory = factory;
192     }
193   }
194 
195   @AssistedFactory
196   interface FooFactory {
197     // Use different parameter names than Foo to make sure we're not assuming they're the same.
createFoo( AssistedDep1 factoryAssistedDep1, AssistedDep2 factoryAssistedDep2, int factoryAssistedInt)198     Foo createFoo(
199         AssistedDep1 factoryAssistedDep1, AssistedDep2 factoryAssistedDep2, int factoryAssistedInt);
200   }
201 
202   @AssistedFactory
203   abstract static class AbstractFooFactory {
204     // Use different parameter names than Foo to make sure we're not assuming they're the same.
createFoo( AssistedDep1 factoryAssistedDep1, AssistedDep2 factoryAssistedDep2, int factoryAssistedInt)205     abstract Foo createFoo(
206         AssistedDep1 factoryAssistedDep1, AssistedDep2 factoryAssistedDep2, int factoryAssistedInt);
207 
208     // A no-op method to test static methods are allowed
staticMethod()209     static void staticMethod() {
210       return;
211     }
212 
213     // A no-op method to test static methods that return assisted type are allowed
staticFooMethod()214     static Foo staticFooMethod() {
215       return null;
216     }
217 
218     // A no-op method to test concrete methods are allowed
concreteMethod()219     void concreteMethod() {
220       return;
221     }
222 
223     // A no-op method to test concrete methods that return assisted type are allowed
concreteFooMethod()224     Foo concreteFooMethod() {
225       return null;
226     }
227   }
228 
229   static final class NoAssistedParametersFoo extends BaseFoo {
230     private final Dep1 dep1;
231     private final Provider<Dep2> dep2Provider;
232     private final NoAssistedParametersFooFactory factory;
233 
234     @Inject Dep3 dep3;
235 
236     @AssistedInject
NoAssistedParametersFoo( Dep1 dep1, Provider<Dep2> dep2Provider, NoAssistedParametersFooFactory factory)237     NoAssistedParametersFoo(
238         Dep1 dep1, Provider<Dep2> dep2Provider, NoAssistedParametersFooFactory factory) {
239       this.dep1 = dep1;
240       this.dep2Provider = dep2Provider;
241       this.factory = factory;
242     }
243   }
244 
245   @AssistedFactory
246   interface NoAssistedParametersFooFactory {
createNoAssistedParametersFoo()247     NoAssistedParametersFoo createNoAssistedParametersFoo();
248   }
249 
250   @Test
testNestedSimpleFooFactory()251   public void testNestedSimpleFooFactory() {
252     AssistedDep1 assistedDep1 = new AssistedDep1();
253     SimpleFoo simpleFoo1 =
254         DaggerAssistedFactoryTest_ParentComponent.create()
255             .nestedSimpleFooFactory()
256             .createSimpleFoo(assistedDep1);
257     assertThat(simpleFoo1.assistedDep).isEqualTo(assistedDep1);
258 
259     AssistedDep2 assistedDep2 = new AssistedDep2();
260     SimpleFoo simpleFoo2 =
261         DaggerAssistedFactoryTest_ParentComponent.create()
262             .nestedSimpleFooFactory()
263             .createSimpleFoo(assistedDep2);
264     assertThat(simpleFoo2.assistedDep).isEqualTo(assistedDep2);
265   }
266 
267   @Test
testNonNestedSimpleFooFactory()268   public void testNonNestedSimpleFooFactory() {
269     AssistedDep1 assistedDep1 = new AssistedDep1();
270     SimpleFoo simpleFoo =
271         DaggerAssistedFactoryTest_ParentComponent.create()
272             .nonNestedSimpleFooFactory()
273             .createSimpleFoo(assistedDep1);
274     assertThat(simpleFoo.assistedDep).isEqualTo(assistedDep1);
275   }
276 
277   @Test
testExtendedSimpleFooFactory()278   public void testExtendedSimpleFooFactory() {
279     AssistedDep1 assistedDep1 = new AssistedDep1();
280     SimpleFoo simpleFoo =
281         DaggerAssistedFactoryTest_ParentComponent.create()
282             .extendedSimpleFooFactory()
283             .createSimpleFoo(assistedDep1);
284     assertThat(simpleFoo.assistedDep).isEqualTo(assistedDep1);
285   }
286 
287   @Test
testFooFactory()288   public void testFooFactory() {
289     AssistedDep1 assistedDep1 = new AssistedDep1();
290     AssistedDep2 assistedDep2 = new AssistedDep2();
291     int assistedInt = 7;
292     Foo foo =
293         DaggerAssistedFactoryTest_ParentComponent.create()
294             .fooFactory()
295             .createFoo(assistedDep1, assistedDep2, assistedInt);
296     assertThat(foo.dep1).isNotNull();
297     assertThat(foo.dep2Provider).isNotNull();
298     assertThat(foo.dep2Provider.get()).isNotNull();
299     assertThat(foo.dep3).isNotNull();
300     assertThat(foo.dep4).isNotNull();
301     assertThat(foo.assistedDep1).isEqualTo(assistedDep1);
302     assertThat(foo.assistedDep2).isEqualTo(assistedDep2);
303     assertThat(foo.assistedInt).isEqualTo(assistedInt);
304     assertThat(foo.factory).isNotNull();
305   }
306 
307   @Test
testNoAssistedParametersFooFactory()308   public void testNoAssistedParametersFooFactory() {
309     NoAssistedParametersFoo foo =
310         DaggerAssistedFactoryTest_ParentComponent.create()
311             .noAssistedParametersFooFactory()
312             .createNoAssistedParametersFoo();
313     assertThat(foo.dep1).isNotNull();
314     assertThat(foo.dep2Provider).isNotNull();
315     assertThat(foo.dep2Provider.get()).isNotNull();
316     assertThat(foo.dep3).isNotNull();
317     assertThat(foo.dep4).isNotNull();
318     assertThat(foo.factory).isNotNull();
319   }
320 
321   @Test
testAssistedFactoryFromSomeEntryPoint()322   public void testAssistedFactoryFromSomeEntryPoint() {
323     SomeEntryPoint someEntryPoint =
324         DaggerAssistedFactoryTest_ParentComponent.create().someEntryPoint();
325     assertThat(someEntryPoint.nestedSimpleFooFactory).isNotNull();
326     assertThat(someEntryPoint.nonNestedSimpleFooFactory).isNotNull();
327     assertThat(someEntryPoint.extendedSimpleFooFactory).isNotNull();
328     assertThat(someEntryPoint.fooFactory).isNotNull();
329     assertThat(someEntryPoint.abstractFooFactory).isNotNull();
330     assertThat(someEntryPoint.noAssistedParametersFooFactory).isNotNull();
331   }
332 }
333