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.nullables
18 
19 import com.google.common.truth.Truth.assertThat
20 import dagger.Component
21 import dagger.Module
22 import dagger.Provides
23 import javax.inject.Inject
24 import javax.inject.Qualifier
25 import org.junit.Test
26 import org.junit.runner.RunWith
27 import org.junit.runners.JUnit4
28 
29 /**
30  * A test that ensures nullable bindings created using an {@code @Nullable} annotation are
31  * interoperable with nullable bindings created using {@code T?} types in kotlin source.
32  */
33 @RunWith(JUnit4::class)
34 class NullabilityInteroptTest {
35   annotation class Nullable
36 
37   @Qualifier annotation class ProvidedWithNullable
38 
39   @Qualifier annotation class ProvidedWithNullType
40 
41   @Component(modules = [TestModule::class])
42   interface TestComponent {
providesUsagenull43     fun providesUsage(): ProvidesUsage
44 
45     fun injectUsage(): InjectUsage
46 
47     @ProvidedWithNullable @Nullable fun nullableWithNullable(): String
48 
49     @ProvidedWithNullable fun nullableWithNullType(): String?
50 
51     @ProvidedWithNullType @Nullable fun nullTypeWithNullable(): String
52 
53     @ProvidedWithNullType fun nullTypeWithNullType(): String?
54   }
55 
56   @Module
57   object TestModule {
58     @Provides
59     @ProvidedWithNullable
60     @Nullable
61     fun providedWithNullable(): String = PROVIDED_WITH_NULLABLE
62 
63     @Provides @ProvidedWithNullType fun providedWithNullType(): String? = PROVIDED_WITH_NULL_TYPE
64 
65     @Provides
66     fun providesUsage(
67       @ProvidedWithNullable nullableWithNullType: String?,
68       @ProvidedWithNullable @Nullable nullableWithNullable: String,
69       @ProvidedWithNullType nullTypeWithNullType: String?,
70       @ProvidedWithNullType @Nullable nullTypeWithNullable: String,
71     ): ProvidesUsage {
72       return ProvidesUsage(
73         nullableWithNullType,
74         nullableWithNullable,
75         nullTypeWithNullType,
76         nullTypeWithNullable,
77       )
78     }
79   }
80 
81   class ProvidesUsage
82   constructor(
83     val nullableWithNullType: String?,
84     val nullableWithNullable: String,
85     val nullTypeWithNullType: String?,
86     val nullTypeWithNullable: String,
87   )
88 
89   class InjectUsage
90   @Inject
91   constructor(
92     @ProvidedWithNullable val nullableWithNullType: String?,
93     @ProvidedWithNullable @Nullable val nullableWithNullable: String,
94     @ProvidedWithNullType val nullTypeWithNullType: String?,
95     @ProvidedWithNullType @Nullable val nullTypeWithNullable: String,
96   )
97 
98   @Test
testEntryPointsnull99   fun testEntryPoints() {
100     val component = DaggerNullabilityInteroptTest_TestComponent.create()
101     assertThat(component.nullableWithNullable()).isEqualTo(PROVIDED_WITH_NULLABLE)
102     assertThat(component.nullableWithNullType()).isEqualTo(PROVIDED_WITH_NULLABLE)
103     assertThat(component.nullTypeWithNullable()).isEqualTo(PROVIDED_WITH_NULL_TYPE)
104     assertThat(component.nullTypeWithNullType()).isEqualTo(PROVIDED_WITH_NULL_TYPE)
105   }
106 
107   @Test
testInjectUsagenull108   fun testInjectUsage() {
109     val injectUsage = DaggerNullabilityInteroptTest_TestComponent.create().injectUsage()
110     assertThat(injectUsage.nullableWithNullable).isEqualTo(PROVIDED_WITH_NULLABLE)
111     assertThat(injectUsage.nullableWithNullType).isEqualTo(PROVIDED_WITH_NULLABLE)
112     assertThat(injectUsage.nullTypeWithNullable).isEqualTo(PROVIDED_WITH_NULL_TYPE)
113     assertThat(injectUsage.nullTypeWithNullType).isEqualTo(PROVIDED_WITH_NULL_TYPE)
114   }
115 
116   @Test
testProvidesUsagenull117   fun testProvidesUsage() {
118     val providesUsage = DaggerNullabilityInteroptTest_TestComponent.create().providesUsage()
119     assertThat(providesUsage.nullableWithNullable).isEqualTo(PROVIDED_WITH_NULLABLE)
120     assertThat(providesUsage.nullableWithNullType).isEqualTo(PROVIDED_WITH_NULLABLE)
121     assertThat(providesUsage.nullTypeWithNullable).isEqualTo(PROVIDED_WITH_NULL_TYPE)
122     assertThat(providesUsage.nullTypeWithNullType).isEqualTo(PROVIDED_WITH_NULL_TYPE)
123   }
124 
125   companion object {
126     const val PROVIDED_WITH_NULLABLE: String = "ProvidedWithNullable"
127     const val PROVIDED_WITH_NULL_TYPE: String = "ProvidedWithNullType"
128   }
129 }
130