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.Binds
21 import dagger.BindsInstance
22 import dagger.BindsOptionalOf
23 import dagger.Component
24 import dagger.Module
25 import dagger.Provides
26 import dagger.assisted.AssistedFactory
27 import dagger.assisted.AssistedInject
28 import dagger.multibindings.IntoSet
29 import dagger.multibindings.Multibinds
30 import java.util.Optional
31 import javax.inject.Inject
32 import javax.inject.Qualifier
33 import org.junit.Test
34 import org.junit.runner.RunWith
35 import org.junit.runners.JUnit4
36 
37 /** Tests that qualified assisted types can be provided and injected as normal types. */
38 @RunWith(JUnit4::class)
39 internal class AssistedFactoryAsQualifiedBindingTest {
40   @Qualifier annotation class AsComponentDependency
41 
42   @Qualifier annotation class AsProvides
43 
44   @Qualifier annotation class AsBinds
45 
46   @Qualifier annotation class AsOptional
47 
48   @Qualifier annotation class AsMultibinding
49 
50   @Component(modules = [BarFactoryModule::class])
51   interface TestComponent {
foonull52     fun foo(): Foo
53 
54     @Component.Factory
55     interface Factory {
56       fun create(
57         @BindsInstance @AsComponentDependency bar: Bar,
58         @BindsInstance @AsComponentDependency barFactory: BarFactory,
59       ): TestComponent
60     }
61   }
62 
63   @Module
64   interface BarFactoryModule {
bindsBarnull65     @Binds @AsBinds fun bindsBar(@AsComponentDependency bar: Bar): Bar
66 
67     @Binds @AsBinds fun bindsBarFactory(@AsComponentDependency barFactory: BarFactory): BarFactory
68 
69     @BindsOptionalOf @AsOptional fun optionalBar(): Bar
70 
71     @BindsOptionalOf @AsOptional fun optionalBarFactory(): BarFactory
72 
73     @Multibinds @AsMultibinding fun barSet(): Set<Bar>
74 
75     @Multibinds @AsMultibinding fun barFactorySet(): Set<BarFactory>
76 
77     @Multibinds fun unqualifiedBarSet(): Set<Bar>
78 
79     @Multibinds fun unqualifiedBarFactorySet(): Set<BarFactory>
80 
81     companion object {
82       @Provides @AsProvides fun providesBar(@AsComponentDependency bar: Bar): Bar = bar
83 
84       @Provides
85       @AsProvides
86       fun providesBarFactory(@AsComponentDependency barFactory: BarFactory): BarFactory = barFactory
87 
88       @Provides @AsOptional fun providesOptionalBar(@AsComponentDependency bar: Bar): Bar = bar
89 
90       @Provides
91       @AsOptional
92       fun providesOptionalBarFactory(@AsComponentDependency barFactory: BarFactory): BarFactory =
93         barFactory
94 
95       @Provides
96       @IntoSet
97       @AsMultibinding
98       fun providesMultibindingBar(@AsComponentDependency bar: Bar): Bar = bar
99 
100       @Provides
101       @IntoSet
102       @AsMultibinding
103       fun providesMultibindingBarFactory(
104         @AsComponentDependency barFactory: BarFactory
105       ): BarFactory = barFactory
106 
107       @Provides
108       @IntoSet
109       fun providesUnqualifiedMultibindingBar(@AsComponentDependency bar: Bar): Bar = bar
110 
111       @Provides
112       @IntoSet
113       fun providesUnqualifiedMultibindingBarFactory(
114         @AsComponentDependency barFactory: BarFactory
115       ): BarFactory = barFactory
116     }
117   }
118 
119   class Foo
120   @Inject
121   constructor(
122     val barFactory: BarFactory,
123     @AsComponentDependency val barAsComponentDependency: Bar,
124     @AsComponentDependency val barFactoryAsComponentDependency: BarFactory,
125     @AsProvides val barAsProvides: Bar,
126     @AsProvides val barFactoryAsProvides: BarFactory,
127     @AsBinds val barAsBinds: Bar,
128     @AsBinds val barFactoryAsBinds: BarFactory,
129     @AsOptional val optionalBar: Optional<Bar>,
130     @AsOptional val optionalBarFactory: Optional<BarFactory>,
131     @AsMultibinding val barSet: Set<Bar>,
132     @AsMultibinding val barFactorySet: Set<@JvmSuppressWildcards BarFactory>,
133     val unqualifiedBarSet: Set<Bar>,
134     val unqualifiedBarFactorySet: Set<@JvmSuppressWildcards BarFactory>,
135   )
136 
137   class Bar @AssistedInject constructor()
138 
139   @AssistedFactory
interfacenull140   fun interface BarFactory {
141     fun create(): Bar
142   }
143 
144   @Test
testFoonull145   fun testFoo() {
146     val bar = Bar()
147     val barFactory = BarFactory { bar }
148     val foo =
149       DaggerAssistedFactoryAsQualifiedBindingTest_TestComponent.factory()
150         .create(bar, barFactory)
151         .foo()
152 
153     // Test we can inject the "real" BarFactory implemented by Dagger
154     assertThat(foo.barFactory).isNotNull()
155     assertThat(foo.barFactory).isNotEqualTo(barFactory)
156     assertThat(foo.barFactory.create()).isNotEqualTo(bar)
157 
158     // Test injection of a qualified Bar/BarFactory with custom @BindsInstance implementation
159     assertThat(foo.barAsComponentDependency).isEqualTo(bar)
160     assertThat(foo.barFactoryAsComponentDependency).isEqualTo(barFactory)
161 
162     // Test injection of a qualified Bar/BarFactory with custom @Provides implementation
163     assertThat(foo.barAsProvides).isEqualTo(bar)
164     assertThat(foo.barFactoryAsProvides).isEqualTo(barFactory)
165 
166     // Test injection of a qualified Bar/BarFactory with custom @Binds implementation
167     assertThat(foo.barAsBinds).isEqualTo(bar)
168     assertThat(foo.barFactoryAsBinds).isEqualTo(barFactory)
169 
170     // Test injection of a qualified Bar/BarFactory with custom @BindsOptionalOf implementation
171     assertThat(foo.optionalBar).isPresent()
172     assertThat(foo.optionalBar).hasValue(bar)
173     assertThat(foo.optionalBarFactory).isPresent()
174     assertThat(foo.optionalBarFactory).hasValue(barFactory)
175 
176     // Test injection of a qualified Bar/BarFactory as multibinding
177     assertThat(foo.barSet).containsExactly(bar)
178     assertThat(foo.barFactorySet).containsExactly(barFactory)
179 
180     // Test injection of a unqualified Bar/BarFactory as multibinding
181     assertThat(foo.unqualifiedBarSet).containsExactly(bar)
182     assertThat(foo.unqualifiedBarFactorySet).containsExactly(barFactory)
183   }
184 }
185