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 javax.inject.Singleton;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.junit.runners.JUnit4;
31 
32 @RunWith(JUnit4.class)
33 public final class AssistedFactoryParameterizedTest {
34   @Singleton
35   @Component
36   interface ParentComponent {
37     // Tests a parameterized Factory with unique @Assisted types
uniqueParameterizedFooFactory()38     ParameterizedFooFactory<Dep2, AssistedDep2> uniqueParameterizedFooFactory();
39 
40     // Tests a parameterized Factory with duplicate @Assisted types in its resolved request type.
41     // Note: this is fine since the @Assisted types are still unique on the @AssistedInject and
42     // @AssistedFactory types, so that the generated code can correctly matches types.
dupeParameterizedFooFactory()43     ParameterizedFooFactory<Dep1, AssistedDep1> dupeParameterizedFooFactory();
44 
45     // Tests a parameterized Factory with same type as binding
bindingParameterizedFooFactory()46     ParameterizedFooFactory<Dep1, Dep1> bindingParameterizedFooFactory();
47 
48     // Tests a parameterized Factory with fixed type parameters
fixedParameterizedFooFactory()49     FixedParameterizedFooFactory fixedParameterizedFooFactory();
50 
51     // Tests a parameterized Factory that extends an interface with a parameterized return type
extendedParameterizedFooFactory()52     ExtendedFooFactory<Dep2, AssistedDep2> extendedParameterizedFooFactory();
53 
54     // Tests a request of factories from another binding.
someEntryPoint()55     SomeEntryPoint someEntryPoint();
56   }
57 
58   static final class Dep1 {
59     @Inject
Dep1(Dep2 dep2, Dep3 dep3)60     Dep1(Dep2 dep2, Dep3 dep3) {}
61   }
62 
63   static final class Dep2 {
64     @Inject
Dep2(Dep3 dep3)65     Dep2(Dep3 dep3) {}
66   }
67 
68   static final class Dep3 {
69     @Inject
Dep3(Dep4 dep4)70     Dep3(Dep4 dep4) {}
71   }
72 
73   static final class Dep4 {
74     @Inject
Dep4()75     Dep4() {}
76   }
77 
78   // A base interface to test that factories can reference subclasses of the assisted parameter.
79   interface AssistedDep {}
80 
81   static final class AssistedDep1 implements AssistedDep {}
82 
83   static final class AssistedDep2 implements AssistedDep {}
84 
85   abstract static class BaseFoo {
86     @Inject Dep4 dep4;
87   }
88 
89   static final class ParameterizedFoo<DepT, AssistedDepT> extends BaseFoo {
90     private final Dep1 dep1;
91     private final Provider<DepT> depTProvider;
92     private final AssistedDep1 assistedDep1;
93     private final AssistedDepT assistedDepT;
94     private final int assistedInt;
95     private final ParameterizedFooFactory<DepT, AssistedDepT> factory;
96 
97     @Inject Dep3 dep3;
98 
99     @AssistedInject
ParameterizedFoo( Dep1 dep1, @Assisted AssistedDep1 assistedDep1, Provider<DepT> depTProvider, @Assisted AssistedDepT assistedDepT, @Assisted int assistedInt, ParameterizedFooFactory<DepT, AssistedDepT> factory)100     ParameterizedFoo(
101         Dep1 dep1,
102         @Assisted AssistedDep1 assistedDep1,
103         Provider<DepT> depTProvider,
104         @Assisted AssistedDepT assistedDepT,
105         @Assisted int assistedInt,
106         ParameterizedFooFactory<DepT, AssistedDepT> factory) {
107       this.dep1 = dep1;
108       this.depTProvider = depTProvider;
109       this.assistedDep1 = assistedDep1;
110       this.assistedDepT = assistedDepT;
111       this.assistedInt = assistedInt;
112       this.factory = factory;
113     }
114   }
115 
116   @AssistedFactory
117   interface ParameterizedFooFactory<DepT, AssistedDepT> {
create( AssistedDep1 assistedDep1, AssistedDepT assistedDepT, int assistedInt)118     ParameterizedFoo<DepT, AssistedDepT> create(
119         AssistedDep1 assistedDep1, AssistedDepT assistedDepT, int assistedInt);
120   }
121 
122   @Test
testUniqueParameterizedFooFactory()123   public void testUniqueParameterizedFooFactory() {
124     AssistedDep1 assistedDep1 = new AssistedDep1();
125     AssistedDep2 assistedDep2 = new AssistedDep2();
126     int assistedInt = 7;
127     ParameterizedFoo<Dep2, AssistedDep2> parameterizedFoo =
128         DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
129             .uniqueParameterizedFooFactory()
130             .create(assistedDep1, assistedDep2, assistedInt);
131     assertThat(parameterizedFoo.dep1).isNotNull();
132     assertThat(parameterizedFoo.depTProvider).isNotNull();
133     assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
134     assertThat(parameterizedFoo.dep3).isNotNull();
135     assertThat(parameterizedFoo.dep4).isNotNull();
136     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
137     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep2);
138     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
139     assertThat(parameterizedFoo.factory).isNotNull();
140   }
141 
142   @Test
testDupeParameterizedFooFactory()143   public void testDupeParameterizedFooFactory() {
144     AssistedDep1 assistedDep1 = new AssistedDep1();
145     int assistedInt = 7;
146     ParameterizedFoo<Dep1, AssistedDep1> parameterizedFoo =
147         DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
148             .dupeParameterizedFooFactory()
149             .create(assistedDep1, assistedDep1, assistedInt);
150     assertThat(parameterizedFoo.dep1).isNotNull();
151     assertThat(parameterizedFoo.depTProvider).isNotNull();
152     assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
153     assertThat(parameterizedFoo.dep3).isNotNull();
154     assertThat(parameterizedFoo.dep4).isNotNull();
155     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
156     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep1);
157     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
158     assertThat(parameterizedFoo.factory).isNotNull();
159   }
160 
161   @Test
testBindingParameterizedFooFactory()162   public void testBindingParameterizedFooFactory() {
163     AssistedDep1 assistedDep1 = new AssistedDep1();
164     Dep1 dep1 = new Dep1(new Dep2(new Dep3(new Dep4())), new Dep3(new Dep4()));
165     int assistedInt = 7;
166     ParameterizedFoo<Dep1, Dep1> parameterizedFoo =
167         DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
168             .bindingParameterizedFooFactory()
169             .create(assistedDep1, dep1, assistedInt);
170     assertThat(parameterizedFoo.dep1).isNotNull();
171     assertThat(parameterizedFoo.depTProvider).isNotNull();
172     assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
173     assertThat(parameterizedFoo.dep3).isNotNull();
174     assertThat(parameterizedFoo.dep4).isNotNull();
175     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
176     assertThat(parameterizedFoo.assistedDepT).isEqualTo(dep1);
177     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
178     assertThat(parameterizedFoo.factory).isNotNull();
179   }
180 
181   @AssistedFactory
182   interface FixedParameterizedFooFactory {
create( AssistedDep1 assistedDep1, AssistedDep2 assistedDep2, int assistedInt)183     ParameterizedFoo<Dep2, AssistedDep2> create(
184         AssistedDep1 assistedDep1, AssistedDep2 assistedDep2, int assistedInt);
185   }
186 
187   @Test
testFixedParameterizedFooFactory()188   public void testFixedParameterizedFooFactory() {
189     AssistedDep1 assistedDep1 = new AssistedDep1();
190     AssistedDep2 assistedDep2 = new AssistedDep2();
191     int assistedInt = 7;
192     ParameterizedFoo<Dep2, AssistedDep2> parameterizedFoo =
193         DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
194             .fixedParameterizedFooFactory()
195             .create(assistedDep1, assistedDep2, assistedInt);
196     assertThat(parameterizedFoo.dep1).isNotNull();
197     assertThat(parameterizedFoo.depTProvider).isNotNull();
198     assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
199     assertThat(parameterizedFoo.dep3).isNotNull();
200     assertThat(parameterizedFoo.dep4).isNotNull();
201     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
202     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep2);
203     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
204     assertThat(parameterizedFoo.factory).isNotNull();
205   }
206 
207   interface ParameterizedFactory<ReturnT, DepT, AssistedDepT> {
208     // Use different parameter names than Foo to make sure we're not assuming they're the same.
create( AssistedDep1 factoryAssistedDep1, AssistedDepT factoryAssistedDepT, int factoryAssistedInt)209     ReturnT create(
210         AssistedDep1 factoryAssistedDep1, AssistedDepT factoryAssistedDepT, int factoryAssistedInt);
211   }
212 
213   @AssistedFactory
214   interface ExtendedFooFactory<DepT, AssistedDepT>
215       extends ParameterizedFactory<ParameterizedFoo<DepT, AssistedDepT>, DepT, AssistedDepT> {}
216 
217   @Test
testExtendedFooFactory()218   public void testExtendedFooFactory() {
219     AssistedDep1 assistedDep1 = new AssistedDep1();
220     AssistedDep2 assistedDep2 = new AssistedDep2();
221     int assistedInt = 7;
222     ParameterizedFoo<Dep2, AssistedDep2> parameterizedFoo =
223         DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
224             .extendedParameterizedFooFactory()
225             .create(assistedDep1, assistedDep2, assistedInt);
226     assertThat(parameterizedFoo.dep1).isNotNull();
227     assertThat(parameterizedFoo.depTProvider).isNotNull();
228     assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
229     assertThat(parameterizedFoo.dep3).isNotNull();
230     assertThat(parameterizedFoo.dep4).isNotNull();
231     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
232     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep2);
233     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
234     assertThat(parameterizedFoo.factory).isNotNull();
235   }
236 
237   static class SomeEntryPoint {
238     private final ParameterizedFooFactory<Dep1, AssistedDep1> dupeParameterizedFooFactory;
239 
240     @Inject
SomeEntryPoint(ParameterizedFooFactory<Dep1, AssistedDep1> dupeParameterizedFooFactory)241     SomeEntryPoint(ParameterizedFooFactory<Dep1, AssistedDep1> dupeParameterizedFooFactory) {
242       this.dupeParameterizedFooFactory = dupeParameterizedFooFactory;
243     }
244   }
245 
246   @Test
testParameterizedFooFactoryFromSomeEntryPoint()247   public void testParameterizedFooFactoryFromSomeEntryPoint() {
248     AssistedDep1 assistedDep1 = new AssistedDep1();
249     int assistedInt = 7;
250     ParameterizedFoo<Dep1, AssistedDep1> parameterizedFoo =
251         DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
252             .someEntryPoint()
253             .dupeParameterizedFooFactory
254             .create(assistedDep1, assistedDep1, assistedInt);
255     assertThat(parameterizedFoo.dep1).isNotNull();
256     assertThat(parameterizedFoo.depTProvider).isNotNull();
257     assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
258     assertThat(parameterizedFoo.dep3).isNotNull();
259     assertThat(parameterizedFoo.dep4).isNotNull();
260     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
261     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep1);
262     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
263     assertThat(parameterizedFoo.factory).isNotNull();
264   }
265 }
266