1 /* 2 * Copyright (C) 2021 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.hilt.android 18 19 import android.content.Context 20 import android.os.Build 21 import androidx.fragment.app.Fragment 22 import androidx.fragment.app.FragmentActivity 23 import android.view.View 24 import androidx.test.core.app.ApplicationProvider.getApplicationContext 25 import androidx.test.ext.junit.runners.AndroidJUnit4 26 import com.google.common.truth.Truth 27 import dagger.Module 28 import dagger.Provides 29 import dagger.hilt.EntryPoint 30 import dagger.hilt.InstallIn 31 import dagger.hilt.android.components.ActivityComponent 32 import dagger.hilt.android.components.FragmentComponent 33 import dagger.hilt.android.components.ViewComponent 34 import dagger.hilt.android.testing.HiltAndroidRule 35 import dagger.hilt.android.testing.HiltAndroidTest 36 import dagger.hilt.android.testing.HiltTestApplication 37 import dagger.hilt.components.SingletonComponent 38 import javax.inject.Qualifier 39 import org.junit.Rule 40 import org.junit.Test 41 import org.junit.runner.RunWith 42 import org.robolectric.Robolectric 43 import org.robolectric.annotation.Config 44 45 @HiltAndroidTest 46 @RunWith(AndroidJUnit4::class) 47 // Robolectric requires Java9 to run API 29 and above, so use API 28 instead 48 @Config(sdk = [Build.VERSION_CODES.P], application = HiltTestApplication::class) 49 class EntryPointAccessorsTest { 50 51 companion object { 52 const val APPLICATION_STRING = "APPLICATION_STRING" 53 const val ACTIVITY_STRING = "ACTIVITY_STRING" 54 const val FRAGMENT_STRING = "FRAGMENT_STRING" 55 const val VIEW_STRING = "VIEW_STRING" 56 } 57 58 @get:Rule 59 var rule = HiltAndroidRule(this) 60 61 @Qualifier 62 @Retention(AnnotationRetention.BINARY) 63 annotation class ApplicationLevel 64 65 @Qualifier 66 @Retention(AnnotationRetention.BINARY) 67 annotation class ActivityLevel 68 69 @Qualifier 70 @Retention(AnnotationRetention.BINARY) 71 annotation class FragmentLevel 72 73 @Qualifier 74 @Retention(AnnotationRetention.BINARY) 75 annotation class ViewLevel 76 77 @Module 78 @InstallIn(SingletonComponent::class) 79 internal object ApplicationModule { 80 @ApplicationLevel 81 @Provides provideStringnull82 fun provideString(): String { 83 return APPLICATION_STRING 84 } 85 } 86 87 @Module 88 @InstallIn(ActivityComponent::class) 89 internal object ActivityModule { 90 @ActivityLevel 91 @Provides provideStringnull92 fun provideString(): String { 93 return ACTIVITY_STRING 94 } 95 } 96 97 @Module 98 @InstallIn(FragmentComponent::class) 99 internal object FragmentModule { 100 @FragmentLevel 101 @Provides provideStringnull102 fun provideString(): String { 103 return FRAGMENT_STRING 104 } 105 } 106 107 @Module 108 @InstallIn(ViewComponent::class) 109 internal object ViewModule { 110 @ViewLevel 111 @Provides provideStringnull112 fun provideString(): String { 113 return VIEW_STRING 114 } 115 } 116 117 @EntryPoint 118 @InstallIn(SingletonComponent::class) 119 internal interface ApplicationEntryPoint { 120 @ApplicationLevel getStringnull121 fun getString(): String 122 } 123 124 @EntryPoint 125 @InstallIn(ActivityComponent::class) 126 internal interface ActivityEntryPoint { 127 @ActivityLevel 128 fun getString(): String 129 } 130 131 @EntryPoint 132 @InstallIn(FragmentComponent::class) 133 internal interface FragmentEntryPoint { 134 @FragmentLevel getStringnull135 fun getString(): String 136 } 137 138 @EntryPoint 139 @InstallIn(ViewComponent::class) 140 internal interface ViewEntryPoint { 141 @ViewLevel 142 fun getString(): String 143 } 144 145 @Test testApplicationEntryPointnull146 fun testApplicationEntryPoint() { 147 val app = getApplicationContext<HiltTestApplication>() 148 val entryPoint = EntryPointAccessors.fromApplication<ApplicationEntryPoint>(app) 149 Truth.assertThat(entryPoint.getString()) 150 .isEqualTo(APPLICATION_STRING) 151 152 val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get() 153 val applicationEntryPoint = EntryPointAccessors.fromApplication<ApplicationEntryPoint>(activity) 154 Truth.assertThat(applicationEntryPoint.getString()) 155 .isEqualTo(APPLICATION_STRING) 156 } 157 158 @Test testActivityEntryPointnull159 fun testActivityEntryPoint() { 160 val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get() 161 val entryPoint = EntryPointAccessors.fromActivity<ActivityEntryPoint>(activity) 162 Truth.assertThat(entryPoint.getString()) 163 .isEqualTo(ACTIVITY_STRING) 164 } 165 166 @Test testFragmentEntryPointnull167 fun testFragmentEntryPoint() { 168 val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get() 169 val fragment = TestFragment() 170 activity.supportFragmentManager.beginTransaction().add(fragment, "").commitNow() 171 val entryPoint = EntryPointAccessors.fromFragment<FragmentEntryPoint>(fragment) 172 Truth.assertThat(entryPoint.getString()) 173 .isEqualTo(FRAGMENT_STRING) 174 } 175 176 @Test testViewEntryPointnull177 fun testViewEntryPoint() { 178 val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get() 179 val view = TestView(activity) 180 val entryPoint = EntryPointAccessors.fromView<ViewEntryPoint>(view) 181 Truth.assertThat(entryPoint.getString()) 182 .isEqualTo(VIEW_STRING) 183 } 184 185 @AndroidEntryPoint(FragmentActivity::class) 186 class TestActivity : Hilt_EntryPointAccessorsTest_TestActivity() 187 188 @AndroidEntryPoint(Fragment::class) 189 class TestFragment : Hilt_EntryPointAccessorsTest_TestFragment() 190 191 @AndroidEntryPoint(View::class) 192 class TestView(context: Context) : Hilt_EntryPointAccessorsTest_TestView(context) 193 } 194