1 /*
2  * Copyright (C) 2023 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.kotlinsrc.assisted
18 
19 import com.google.common.truth.Truth.assertThat
20 import dagger.Component
21 import dagger.assisted.Assisted
22 import dagger.assisted.AssistedFactory
23 import dagger.assisted.AssistedInject
24 import javax.inject.Inject
25 import javax.inject.Provider
26 import javax.inject.Singleton
27 import org.junit.Test
28 import org.junit.runner.RunWith
29 import org.junit.runners.JUnit4
30 
31 @RunWith(JUnit4::class)
32 internal class AssistedFactoryParameterizedTest {
33   @Singleton
34   @Component
35   interface ParentComponent {
36     // Tests a parameterized Factory with unique @Assisted types
uniqueParameterizedFooFactorynull37     fun uniqueParameterizedFooFactory(): ParameterizedFooFactory<Dep2, AssistedDep2>
38 
39     // Tests a parameterized Factory with duplicate @Assisted types in its resolved request type.
40     // Note: this is fine since the @Assisted types are still unique on the @AssistedInject and
41     // @AssistedFactory types, so that the generated code can correctly matches types.
42     fun dupeParameterizedFooFactory(): ParameterizedFooFactory<Dep1, AssistedDep1>
43 
44     // Tests a parameterized Factory with same type as binding
45     fun bindingParameterizedFooFactory(): ParameterizedFooFactory<Dep1, Dep1>
46 
47     // Tests a parameterized Factory with fixed type parameters
48     fun fixedParameterizedFooFactory(): FixedParameterizedFooFactory
49 
50     // Tests a parameterized Factory that extends an interface with a parameterized return type
51     fun extendedParameterizedFooFactory(): ExtendedFooFactory<Dep2, AssistedDep2>
52 
53     // Tests a request of factories from another binding.
54     fun someEntryPoint(): SomeEntryPoint
55   }
56 
57   class Dep1 @Inject constructor(
58     @Suppress("UNUSED_PARAMETER") dep2: Dep2, @Suppress("UNUSED_PARAMETER") dep3: Dep3)
59   class Dep2 @Inject constructor(@Suppress("UNUSED_PARAMETER") dep3: Dep3)
60   class Dep3 @Inject constructor(@Suppress("UNUSED_PARAMETER") dep4: Dep4)
61   class Dep4 @Inject constructor()
62 
63   // A base interface to test that factories can reference subclasses of the assisted parameter.
64   interface AssistedDep
65   class AssistedDep1 : AssistedDep
66   class AssistedDep2 : AssistedDep
67   abstract class BaseFoo {
68     @Inject lateinit var dep4: Dep4
69   }
70 
71   class ParameterizedFoo<DepT, AssistedDepT>
72   @AssistedInject
73   constructor(
74     val dep1: Dep1,
75     @Assisted val assistedDep1: AssistedDep1,
76     val depTProvider: Provider<DepT>,
77     @Assisted val assistedDepT: AssistedDepT,
78     @Assisted val assistedInt: Int,
79     val factory: ParameterizedFooFactory<DepT, AssistedDepT>
80   ) : BaseFoo() {
81     @Inject lateinit var dep3: Dep3
82   }
83 
84   @AssistedFactory
85   interface ParameterizedFooFactory<DepT, AssistedDepT> {
createnull86     fun create(
87       assistedDep1: AssistedDep1,
88       assistedDepT: AssistedDepT,
89       assistedInt: Int
90     ): ParameterizedFoo<DepT, AssistedDepT>
91   }
92 
93   @Test
94   fun testUniqueParameterizedFooFactory() {
95     val assistedDep1 = AssistedDep1()
96     val assistedDep2 = AssistedDep2()
97     val assistedInt = 7
98     val parameterizedFoo =
99       DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
100         .uniqueParameterizedFooFactory()
101         .create(assistedDep1, assistedDep2, assistedInt)
102     assertThat(parameterizedFoo.dep1).isNotNull()
103     assertThat(parameterizedFoo.depTProvider).isNotNull()
104     assertThat(parameterizedFoo.depTProvider.get()).isNotNull()
105     assertThat(parameterizedFoo.dep3).isNotNull()
106     assertThat(parameterizedFoo.dep4).isNotNull()
107     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1)
108     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep2)
109     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt)
110     assertThat(parameterizedFoo.factory).isNotNull()
111   }
112 
113   @Test
testDupeParameterizedFooFactorynull114   fun testDupeParameterizedFooFactory() {
115     val assistedDep1 = AssistedDep1()
116     val assistedInt = 7
117     val parameterizedFoo =
118       DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
119         .dupeParameterizedFooFactory()
120         .create(assistedDep1, assistedDep1, assistedInt)
121     assertThat(parameterizedFoo.dep1).isNotNull()
122     assertThat(parameterizedFoo.depTProvider).isNotNull()
123     assertThat(parameterizedFoo.depTProvider.get()).isNotNull()
124     assertThat(parameterizedFoo.dep3).isNotNull()
125     assertThat(parameterizedFoo.dep4).isNotNull()
126     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1)
127     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep1)
128     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt)
129     assertThat(parameterizedFoo.factory).isNotNull()
130   }
131 
132   @Test
testBindingParameterizedFooFactorynull133   fun testBindingParameterizedFooFactory() {
134     val assistedDep1 = AssistedDep1()
135     val dep1 = Dep1(Dep2(Dep3(Dep4())), Dep3(Dep4()))
136     val assistedInt = 7
137     val parameterizedFoo =
138       DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
139         .bindingParameterizedFooFactory()
140         .create(assistedDep1, dep1, assistedInt)
141     assertThat(parameterizedFoo.dep1).isNotNull()
142     assertThat(parameterizedFoo.depTProvider).isNotNull()
143     assertThat(parameterizedFoo.depTProvider.get()).isNotNull()
144     assertThat(parameterizedFoo.dep3).isNotNull()
145     assertThat(parameterizedFoo.dep4).isNotNull()
146     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1)
147     assertThat(parameterizedFoo.assistedDepT).isEqualTo(dep1)
148     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt)
149     assertThat(parameterizedFoo.factory).isNotNull()
150   }
151 
152   @AssistedFactory
153   interface FixedParameterizedFooFactory {
createnull154     fun create(
155       assistedDep1: AssistedDep1,
156       assistedDep2: AssistedDep2,
157       assistedInt: Int
158     ): ParameterizedFoo<Dep2, AssistedDep2>
159   }
160 
161   @Test
162   fun testFixedParameterizedFooFactory() {
163     val assistedDep1 = AssistedDep1()
164     val assistedDep2 = AssistedDep2()
165     val assistedInt = 7
166     val parameterizedFoo =
167       DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
168         .fixedParameterizedFooFactory()
169         .create(assistedDep1, assistedDep2, 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(assistedDep2)
177     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt)
178     assertThat(parameterizedFoo.factory).isNotNull()
179   }
180 
181   interface ParameterizedFactory<ReturnT, DepT, AssistedDepT> {
182     // Use different parameter names than Foo to make sure we're not assuming they're the same.
createnull183     fun create(
184       factoryAssistedDep1: AssistedDep1,
185       factoryAssistedDepT: AssistedDepT,
186       factoryAssistedInt: Int
187     ): ReturnT
188   }
189 
190   @AssistedFactory
191   interface ExtendedFooFactory<DepT, AssistedDepT> :
192     ParameterizedFactory<ParameterizedFoo<DepT, AssistedDepT>, DepT, AssistedDepT>
193 
194   @Test
195   fun testExtendedFooFactory() {
196     val assistedDep1 = AssistedDep1()
197     val assistedDep2 = AssistedDep2()
198     val assistedInt = 7
199     val parameterizedFoo =
200       DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
201         .extendedParameterizedFooFactory()
202         .create(assistedDep1, assistedDep2, assistedInt)
203     assertThat(parameterizedFoo.dep1).isNotNull()
204     assertThat(parameterizedFoo.depTProvider).isNotNull()
205     assertThat(parameterizedFoo.depTProvider.get()).isNotNull()
206     assertThat(parameterizedFoo.dep3).isNotNull()
207     assertThat(parameterizedFoo.dep4).isNotNull()
208     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1)
209     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep2)
210     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt)
211     assertThat(parameterizedFoo.factory).isNotNull()
212   }
213 
214   class SomeEntryPoint
215   @Inject
216   constructor(val dupeParameterizedFooFactory: ParameterizedFooFactory<Dep1, AssistedDep1>)
217 
218   @Test
testParameterizedFooFactoryFromSomeEntryPointnull219   fun testParameterizedFooFactoryFromSomeEntryPoint() {
220     val assistedDep1 = AssistedDep1()
221     val assistedInt = 7
222     val parameterizedFoo =
223       DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
224         .someEntryPoint()
225         .dupeParameterizedFooFactory
226         .create(assistedDep1, assistedDep1, assistedInt)
227     assertThat(parameterizedFoo.dep1).isNotNull()
228     assertThat(parameterizedFoo.depTProvider).isNotNull()
229     assertThat(parameterizedFoo.depTProvider.get()).isNotNull()
230     assertThat(parameterizedFoo.dep3).isNotNull()
231     assertThat(parameterizedFoo.dep4).isNotNull()
232     assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1)
233     assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep1)
234     assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt)
235     assertThat(parameterizedFoo.factory).isNotNull()
236   }
237 }
238