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.EntryPoints 31 import dagger.hilt.InstallIn 32 import dagger.hilt.android.components.ActivityComponent 33 import dagger.hilt.android.components.FragmentComponent 34 import dagger.hilt.android.components.FragmentRetainedComponent 35 import dagger.hilt.android.components.ViewComponent 36 import dagger.hilt.android.internal.managers.InternalFragmentRetainedComponent 37 import dagger.hilt.android.testing.HiltAndroidRule 38 import dagger.hilt.android.testing.HiltAndroidTest 39 import dagger.hilt.android.testing.HiltTestApplication 40 import dagger.hilt.components.SingletonComponent 41 import javax.inject.Inject 42 import javax.inject.Qualifier 43 import org.junit.Rule 44 import org.junit.Test 45 import org.junit.runner.RunWith 46 import org.robolectric.Robolectric 47 import org.robolectric.annotation.Config 48 49 @HiltAndroidTest 50 @RunWith(AndroidJUnit4::class) 51 // Robolectric requires Java9 to run API 29 and above, so use API 28 instead 52 @Config(sdk = [Build.VERSION_CODES.P], application = HiltTestApplication::class) 53 class EntryPointAccessorsTest { 54 55 companion object { 56 const val APPLICATION_STRING = "APPLICATION_STRING" 57 const val ACTIVITY_STRING = "ACTIVITY_STRING" 58 const val FRAGMENT_STRING = "FRAGMENT_STRING" 59 const val VIEW_STRING = "VIEW_STRING" 60 } 61 62 @get:Rule var rule = HiltAndroidRule(this) 63 64 @Qualifier @Retention(AnnotationRetention.BINARY) annotation class ApplicationLevel 65 66 @Qualifier @Retention(AnnotationRetention.BINARY) annotation class ActivityLevel 67 68 @Qualifier @Retention(AnnotationRetention.BINARY) annotation class FragmentLevel 69 70 @Qualifier @Retention(AnnotationRetention.BINARY) annotation class ViewLevel 71 72 @Module 73 @InstallIn(SingletonComponent::class) 74 internal object ApplicationModule { 75 @ApplicationLevel 76 @Provides provideStringnull77 fun provideString(): String { 78 return APPLICATION_STRING 79 } 80 } 81 82 @Module 83 @InstallIn(ActivityComponent::class) 84 internal object ActivityModule { 85 @ActivityLevel 86 @Provides provideStringnull87 fun provideString(): String { 88 return ACTIVITY_STRING 89 } 90 } 91 92 @Module 93 @InstallIn(FragmentComponent::class) 94 internal object FragmentModule { 95 @FragmentLevel 96 @Provides provideStringnull97 fun provideString(): String { 98 return FRAGMENT_STRING 99 } 100 } 101 102 @Module 103 @InstallIn(ViewComponent::class) 104 internal object ViewModule { 105 @ViewLevel 106 @Provides provideStringnull107 fun provideString(): String { 108 return VIEW_STRING 109 } 110 } 111 112 @EntryPoint 113 @InstallIn(SingletonComponent::class) 114 internal interface ApplicationEntryPoint { getStringnull115 @ApplicationLevel fun getString(): String 116 } 117 118 @EntryPoint 119 @InstallIn(ActivityComponent::class) 120 internal interface ActivityEntryPoint { 121 @ActivityLevel fun getString(): String 122 } 123 124 @EntryPoint 125 @InstallIn(FragmentComponent::class) 126 internal interface FragmentEntryPoint { getStringnull127 @FragmentLevel fun getString(): String 128 } 129 130 @EntryPoint 131 @InstallIn(ViewComponent::class) 132 internal interface ViewEntryPoint { 133 @ViewLevel fun getString(): String 134 } 135 136 @Test testApplicationEntryPointnull137 fun testApplicationEntryPoint() { 138 val app = getApplicationContext<HiltTestApplication>() 139 val entryPoint = EntryPointAccessors.fromApplication<ApplicationEntryPoint>(app) 140 Truth.assertThat(entryPoint.getString()).isEqualTo(APPLICATION_STRING) 141 142 val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get() 143 val applicationEntryPoint = EntryPointAccessors.fromApplication<ApplicationEntryPoint>(activity) 144 Truth.assertThat(applicationEntryPoint.getString()).isEqualTo(APPLICATION_STRING) 145 } 146 147 @Test testActivityEntryPointnull148 fun testActivityEntryPoint() { 149 val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get() 150 val entryPoint = EntryPointAccessors.fromActivity<ActivityEntryPoint>(activity) 151 Truth.assertThat(entryPoint.getString()).isEqualTo(ACTIVITY_STRING) 152 } 153 154 @Test testFragmentEntryPointnull155 fun testFragmentEntryPoint() { 156 val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get() 157 val fragment = TestFragment() 158 activity.supportFragmentManager.beginTransaction().add(fragment, "").commitNow() 159 val entryPoint = EntryPointAccessors.fromFragment<FragmentEntryPoint>(fragment) 160 Truth.assertThat(entryPoint.getString()).isEqualTo(FRAGMENT_STRING) 161 } 162 163 @Test testViewEntryPointnull164 fun testViewEntryPoint() { 165 val activity = Robolectric.buildActivity(TestActivity::class.java).setup().get() 166 val view = TestView(activity) 167 val entryPoint = EntryPointAccessors.fromView<ViewEntryPoint>(view) 168 Truth.assertThat(entryPoint.getString()).isEqualTo(VIEW_STRING) 169 } 170 171 @AndroidEntryPoint(FragmentActivity::class) 172 class TestActivity : Hilt_EntryPointAccessorsTest_TestActivity() 173 174 @AndroidEntryPoint(Fragment::class) 175 class TestFragment : Hilt_EntryPointAccessorsTest_TestFragment() { 176 } 177 178 @AndroidEntryPoint(View::class) 179 class TestView(context: Context) : Hilt_EntryPointAccessorsTest_TestView(context) 180 } 181