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.subcomponent.multibindings
18 
19 import com.google.common.collect.ImmutableMap
20 import com.google.common.collect.ImmutableSet
21 import com.google.common.truth.Truth.assertThat
22 import dagger.functional.kotlinsrc.subcomponent.multibindings.MultibindingSubcomponents.*
23 import org.junit.Before
24 import org.junit.Test
25 import org.junit.runner.RunWith
26 import org.junit.runners.JUnit4
27 
28 @RunWith(JUnit4::class)
29 class SubcomponentMultibindingsTest {
30   private lateinit var parentWithoutProvisionHasChildWithoutProvision:
31     ParentWithoutProvisionHasChildWithoutProvision
32   private lateinit var parentWithoutProvisionHasChildWithProvision:
33     ParentWithoutProvisionHasChildWithProvision
34   private lateinit var parentWithProvisionHasChildWithoutProvision:
35     ParentWithProvisionHasChildWithoutProvision
36   private lateinit var parentWithProvisionHasChildWithProvision:
37     ParentWithProvisionHasChildWithProvision
38   @Before
setUpnull39   fun setUp() {
40     parentWithoutProvisionHasChildWithoutProvision =
41       DaggerMultibindingSubcomponents_ParentWithoutProvisionHasChildWithoutProvision.create()
42     parentWithoutProvisionHasChildWithProvision =
43       DaggerMultibindingSubcomponents_ParentWithoutProvisionHasChildWithProvision.create()
44     parentWithProvisionHasChildWithoutProvision =
45       DaggerMultibindingSubcomponents_ParentWithProvisionHasChildWithoutProvision.create()
46     parentWithProvisionHasChildWithProvision =
47       DaggerMultibindingSubcomponents_ParentWithProvisionHasChildWithProvision.create()
48   }
49 
50   @Test
testParentWithoutProvisionHasChildWithoutProvisionnull51   fun testParentWithoutProvisionHasChildWithoutProvision() {
52     // Child
53     assertThat(
54         parentWithoutProvisionHasChildWithoutProvision
55           .childWithoutProvision()
56           .grandchild()
57           .requiresMultibindingsBoundInParent()
58       )
59       .isEqualTo(BOUND_IN_PARENT)
60 
61     // Grandchild
62     assertThat(
63         parentWithoutProvisionHasChildWithoutProvision
64           .childWithoutProvision()
65           .grandchild()
66           .requiresMultibindingsBoundInParentAndChild()
67       )
68       .isEqualTo(BOUND_IN_PARENT_AND_CHILD)
69 
70     assertThat(
71         parentWithoutProvisionHasChildWithoutProvision
72           .childWithoutProvision()
73           .grandchild()
74           .requiresMultibindingsBoundInChild()
75       )
76       .isEqualTo(BOUND_IN_CHILD)
77 
78     // Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
79     // contribution from the child, it must be pushed down to (not duplicated in) the child because
80     // its contribution depends on multibindings that have one contribution from the parent and one
81     // from the child (see b/22821341).
82     assertThat(
83         parentWithoutProvisionHasChildWithoutProvision
84           .childWithoutProvision()
85           .grandchild()
86           .setOfRequiresMultibindingsInParentAndChild()
87       )
88       .containsExactly(BOUND_IN_PARENT_AND_CHILD)
89   }
90 
91   @Test
testParentWithoutProvisionHasChildWithProvisionnull92   fun testParentWithoutProvisionHasChildWithProvision() {
93     // Child
94     assertThat(
95         parentWithoutProvisionHasChildWithProvision
96           .childWithProvision()
97           .grandchild()
98           .requiresMultibindingsBoundInParent()
99       )
100       .isEqualTo(BOUND_IN_PARENT)
101 
102     // Grandchild
103     assertThat(
104         parentWithoutProvisionHasChildWithProvision
105           .childWithProvision()
106           .grandchild()
107           .requiresMultibindingsBoundInParentAndChild()
108       )
109       .isEqualTo(BOUND_IN_PARENT_AND_CHILD)
110 
111     assertThat(
112         parentWithoutProvisionHasChildWithProvision
113           .childWithProvision()
114           .grandchild()
115           .requiresMultibindingsBoundInChild()
116       )
117       .isEqualTo(BOUND_IN_CHILD)
118 
119     // Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
120     // contribution from the child, it must be pushed down to (not duplicated in) the child because
121     // its contribution depends on multibindings that have one contribution from the parent and one
122     // from the child (see b/22821341).
123     assertThat(
124         parentWithoutProvisionHasChildWithProvision
125           .childWithProvision()
126           .grandchild()
127           .setOfRequiresMultibindingsInParentAndChild()
128       )
129       .containsExactly(BOUND_IN_PARENT_AND_CHILD)
130   }
131 
132   @Test
testParentWithProvisionHasChildWithoutProvisionnull133   fun testParentWithProvisionHasChildWithoutProvision() {
134     // Parent
135     assertThat(parentWithProvisionHasChildWithoutProvision.requiresMultibindingsBoundInParent())
136       .isEqualTo(BOUND_IN_PARENT)
137     assertThat(
138         parentWithProvisionHasChildWithoutProvision.requiresMultibindingsBoundInParentAndChild()
139       )
140       .isEqualTo(BOUND_IN_PARENT_AND_CHILD_PROVIDED_BY_PARENT)
141 
142     // Grandchild
143     assertThat(
144         parentWithProvisionHasChildWithoutProvision
145           .childWithoutProvision()
146           .grandchild()
147           .requiresMultibindingsBoundInParent()
148       )
149       .isEqualTo(BOUND_IN_PARENT)
150     assertThat(
151         parentWithProvisionHasChildWithoutProvision
152           .childWithoutProvision()
153           .grandchild()
154           .requiresMultibindingsBoundInChild()
155       )
156       .isEqualTo(BOUND_IN_CHILD)
157 
158     assertThat(
159         parentWithProvisionHasChildWithoutProvision
160           .childWithoutProvision()
161           .grandchild()
162           .requiresMultibindingsBoundInParentAndChild()
163       )
164       .isEqualTo(BOUND_IN_PARENT_AND_CHILD)
165 
166     // Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
167     // contribution from the child, it must be pushed down to (not duplicated in) the child because
168     // its contribution depends on multibindings that have one contribution from the parent and one
169     // from the child (see b/22821341).
170     assertThat(
171         parentWithProvisionHasChildWithoutProvision
172           .childWithoutProvision()
173           .grandchild()
174           .setOfRequiresMultibindingsInParentAndChild()
175       )
176       .containsExactly(BOUND_IN_PARENT_AND_CHILD)
177   }
178 
179   @Test
testParentWithProvisionHasChildWithProvisionnull180   fun testParentWithProvisionHasChildWithProvision() {
181     // Parent
182     assertThat(parentWithProvisionHasChildWithProvision.requiresMultibindingsBoundInParent())
183       .isEqualTo(BOUND_IN_PARENT)
184 
185     // Child
186     assertThat(
187         parentWithProvisionHasChildWithProvision
188           .childWithProvision()
189           .requiresMultibindingsBoundInParent()
190       )
191       .isEqualTo(BOUND_IN_PARENT)
192     assertThat(
193         parentWithProvisionHasChildWithProvision
194           .childWithProvision()
195           .requiresMultibindingsBoundInChild()
196       )
197       .isEqualTo(BOUND_IN_CHILD)
198     assertThat(
199         parentWithProvisionHasChildWithProvision
200           .childWithProvision()
201           .requiresMultibindingsBoundInParentAndChild()
202       )
203       .isEqualTo(BOUND_IN_PARENT_AND_CHILD)
204 
205     // https://github.com/google/dagger/issues/401
206     assertThat(
207         DaggerMultibindingSubcomponents_ParentWithProvisionHasChildWithBinds.create()
208           .childWithBinds()
209           .requiresMultibindingsBoundInParentAndChild()
210       )
211       .isEqualTo(BOUND_IN_PARENT_AND_CHILD)
212 
213     // Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
214     // contribution from the child, it must be pushed down to (not duplicated in) the child because
215     // its contribution depends on multibindings that have one contribution from the parent and one
216     // from the child (see b/22821341).
217     assertThat(
218         parentWithProvisionHasChildWithProvision
219           .childWithProvision()
220           .setOfRequiresMultibindingsInParentAndChild()
221       )
222       .containsExactly(BOUND_IN_PARENT_AND_CHILD)
223 
224     // Grandchild
225     assertThat(
226         parentWithProvisionHasChildWithProvision
227           .childWithProvision()
228           .grandchild()
229           .requiresMultibindingsBoundInParent()
230       )
231       .isEqualTo(BOUND_IN_PARENT)
232 
233     assertThat(
234         parentWithProvisionHasChildWithProvision
235           .childWithProvision()
236           .grandchild()
237           .requiresMultibindingsBoundInChild()
238       )
239       .isEqualTo(BOUND_IN_CHILD)
240 
241     assertThat(
242         parentWithProvisionHasChildWithProvision
243           .childWithProvision()
244           .grandchild()
245           .requiresMultibindingsBoundInParentAndChild()
246       )
247       .isEqualTo(BOUND_IN_PARENT_AND_CHILD)
248 
249     // Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
250     // contribution from the child, it must be pushed down to (not duplicated in) the child because
251     // its contribution depends on multibindings that have one contribution from the parent and one
252     // from the child (see b/22821341).
253     assertThat(
254         parentWithProvisionHasChildWithProvision
255           .childWithProvision()
256           .grandchild()
257           .setOfRequiresMultibindingsInParentAndChild()
258       )
259       .containsExactly(BOUND_IN_PARENT_AND_CHILD)
260   }
261 
262   companion object {
263     private val BOUND_IN_PARENT =
264       RequiresMultibindings(
265         ImmutableSet.of(BoundInParent.INSTANCE),
266         ImmutableMap.of("parent key", BoundInParent.INSTANCE)
267       )
268     private val BOUND_IN_CHILD =
269       RequiresMultibindings(
270         ImmutableSet.of(BoundInChild.INSTANCE),
271         ImmutableMap.of("child key", BoundInChild.INSTANCE)
272       )
273     private val BOUND_IN_PARENT_AND_CHILD =
274       RequiresMultibindings(
275         ImmutableSet.of(BoundInParentAndChild.IN_PARENT, BoundInParentAndChild.IN_CHILD),
276         ImmutableMap.of(
277           "parent key",
278           BoundInParentAndChild.IN_PARENT,
279           "child key",
280           BoundInParentAndChild.IN_CHILD
281         )
282       )
283     private val BOUND_IN_PARENT_AND_CHILD_PROVIDED_BY_PARENT =
284       RequiresMultibindings(
285         ImmutableSet.of(BoundInParentAndChild.IN_PARENT),
286         ImmutableMap.of("parent key", BoundInParentAndChild.IN_PARENT)
287       )
288   }
289 }
290