1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2020 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.hilt.android; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import static androidx.test.core.app.ApplicationProvider.getApplicationContext; 20*f585d8a3SJacky Wang import static com.google.common.truth.Truth.assertThat; 21*f585d8a3SJacky Wang import static org.junit.Assert.assertThrows; 22*f585d8a3SJacky Wang 23*f585d8a3SJacky Wang import android.os.Build; 24*f585d8a3SJacky Wang import androidx.activity.ComponentActivity; 25*f585d8a3SJacky Wang import androidx.test.ext.junit.runners.AndroidJUnit4; 26*f585d8a3SJacky Wang import dagger.Module; 27*f585d8a3SJacky Wang import dagger.Provides; 28*f585d8a3SJacky Wang import dagger.hilt.EntryPoint; 29*f585d8a3SJacky Wang import dagger.hilt.EntryPoints; 30*f585d8a3SJacky Wang import dagger.hilt.InstallIn; 31*f585d8a3SJacky Wang import dagger.hilt.android.components.ActivityComponent; 32*f585d8a3SJacky Wang import dagger.hilt.android.testing.BindValue; 33*f585d8a3SJacky Wang import dagger.hilt.android.testing.HiltAndroidRule; 34*f585d8a3SJacky Wang import dagger.hilt.android.testing.HiltAndroidTest; 35*f585d8a3SJacky Wang import dagger.hilt.android.testing.HiltTestApplication; 36*f585d8a3SJacky Wang import dagger.hilt.android.testing.UninstallModules; 37*f585d8a3SJacky Wang import dagger.hilt.components.SingletonComponent; 38*f585d8a3SJacky Wang import javax.inject.Inject; 39*f585d8a3SJacky Wang import javax.inject.Named; 40*f585d8a3SJacky Wang import org.junit.Rule; 41*f585d8a3SJacky Wang import org.junit.Test; 42*f585d8a3SJacky Wang import org.junit.runner.RunWith; 43*f585d8a3SJacky Wang import org.robolectric.Robolectric; 44*f585d8a3SJacky Wang import org.robolectric.android.controller.ActivityController; 45*f585d8a3SJacky Wang import org.robolectric.annotation.Config; 46*f585d8a3SJacky Wang 47*f585d8a3SJacky Wang // TODO(bcorso): Support transitively ignoring the @Module.includes of ignored modules? 48*f585d8a3SJacky Wang // TODO(bcorso): Support including non-test @UninstallModules using @UninstallModules.includes? 49*f585d8a3SJacky Wang @UninstallModules({ 50*f585d8a3SJacky Wang MultiTestRootExternalModules.PkgPrivateAppModule.class, 51*f585d8a3SJacky Wang MultiTestRootExternalModules.PkgPrivateActivityModule.class 52*f585d8a3SJacky Wang }) 53*f585d8a3SJacky Wang @HiltAndroidTest 54*f585d8a3SJacky Wang @RunWith(AndroidJUnit4.class) 55*f585d8a3SJacky Wang // Robolectric requires Java9 to run API 29 and above, so use API 28 instead 56*f585d8a3SJacky Wang @Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class) 57*f585d8a3SJacky Wang public final class MultiTestRoot1Test { 58*f585d8a3SJacky Wang private static final int INT_VALUE = 9; 59*f585d8a3SJacky Wang private static final String STR_VALUE = "MultiTestRoot1TestValue"; 60*f585d8a3SJacky Wang private static final long LONG_VALUE = 11L; 61*f585d8a3SJacky Wang private static final String REPLACE_EXTERNAL_STR_VALUE = "REPLACED_EXTERNAL_STR_VALUE"; 62*f585d8a3SJacky Wang private static final long REPLACE_EXTERNAL_LONG_VALUE = 17L; 63*f585d8a3SJacky Wang private static final String BIND_VALUE_STRING = "BIND_VALUE_STRING"; 64*f585d8a3SJacky Wang private static final String TEST_QUALIFIER = "TEST_QUALIFIER"; 65*f585d8a3SJacky Wang 66*f585d8a3SJacky Wang @AndroidEntryPoint(ComponentActivity.class) 67*f585d8a3SJacky Wang public static class TestActivity extends Hilt_MultiTestRoot1Test_TestActivity { 68*f585d8a3SJacky Wang @Inject Baz baz; 69*f585d8a3SJacky Wang @Inject @MultiTestRootExternalModules.External Long externalLongValue; 70*f585d8a3SJacky Wang } 71*f585d8a3SJacky Wang 72*f585d8a3SJacky Wang @EntryPoint 73*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 74*f585d8a3SJacky Wang public interface BindValueEntryPoint { 75*f585d8a3SJacky Wang @Named(TEST_QUALIFIER) bindValueString()76*f585d8a3SJacky Wang String bindValueString(); 77*f585d8a3SJacky Wang } 78*f585d8a3SJacky Wang 79*f585d8a3SJacky Wang @Module 80*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 81*f585d8a3SJacky Wang public interface ReplaceExternalAppModule { 82*f585d8a3SJacky Wang @Provides 83*f585d8a3SJacky Wang @MultiTestRootExternalModules.External provideString()84*f585d8a3SJacky Wang static String provideString() { 85*f585d8a3SJacky Wang return REPLACE_EXTERNAL_STR_VALUE; 86*f585d8a3SJacky Wang } 87*f585d8a3SJacky Wang } 88*f585d8a3SJacky Wang 89*f585d8a3SJacky Wang @Module 90*f585d8a3SJacky Wang @InstallIn(ActivityComponent.class) 91*f585d8a3SJacky Wang public interface ReplaceExternalActivityModule { 92*f585d8a3SJacky Wang @Provides 93*f585d8a3SJacky Wang @MultiTestRootExternalModules.External provideString()94*f585d8a3SJacky Wang static Long provideString() { 95*f585d8a3SJacky Wang return REPLACE_EXTERNAL_LONG_VALUE; 96*f585d8a3SJacky Wang } 97*f585d8a3SJacky Wang } 98*f585d8a3SJacky Wang 99*f585d8a3SJacky Wang @Module 100*f585d8a3SJacky Wang @InstallIn(ActivityComponent.class) 101*f585d8a3SJacky Wang public interface TestActivityModule { 102*f585d8a3SJacky Wang @Provides provideBaz()103*f585d8a3SJacky Wang static Baz provideBaz() { 104*f585d8a3SJacky Wang return new Baz(LONG_VALUE); 105*f585d8a3SJacky Wang } 106*f585d8a3SJacky Wang } 107*f585d8a3SJacky Wang 108*f585d8a3SJacky Wang @Module 109*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 110*f585d8a3SJacky Wang interface PkgPrivateTestModule { 111*f585d8a3SJacky Wang @Provides provideQux()112*f585d8a3SJacky Wang static Qux provideQux() { 113*f585d8a3SJacky Wang return new Qux(); 114*f585d8a3SJacky Wang } 115*f585d8a3SJacky Wang } 116*f585d8a3SJacky Wang 117*f585d8a3SJacky Wang @Module 118*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 119*f585d8a3SJacky Wang public interface TestModule { 120*f585d8a3SJacky Wang @Provides provideInt()121*f585d8a3SJacky Wang static int provideInt() { 122*f585d8a3SJacky Wang return INT_VALUE; 123*f585d8a3SJacky Wang } 124*f585d8a3SJacky Wang 125*f585d8a3SJacky Wang @Provides provideString()126*f585d8a3SJacky Wang static String provideString() { 127*f585d8a3SJacky Wang return STR_VALUE; 128*f585d8a3SJacky Wang } 129*f585d8a3SJacky Wang } 130*f585d8a3SJacky Wang 131*f585d8a3SJacky Wang public static final class Outer { 132*f585d8a3SJacky Wang @Module 133*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 134*f585d8a3SJacky Wang public interface NestedTestModule { 135*f585d8a3SJacky Wang @Provides provideLong()136*f585d8a3SJacky Wang static long provideLong() { 137*f585d8a3SJacky Wang return LONG_VALUE; 138*f585d8a3SJacky Wang } 139*f585d8a3SJacky Wang } 140*f585d8a3SJacky Wang Outer()141*f585d8a3SJacky Wang private Outer() {} 142*f585d8a3SJacky Wang } 143*f585d8a3SJacky Wang 144*f585d8a3SJacky Wang static class Foo { 145*f585d8a3SJacky Wang final int value; 146*f585d8a3SJacky Wang 147*f585d8a3SJacky Wang @Inject Foo(int value)148*f585d8a3SJacky Wang Foo(int value) { 149*f585d8a3SJacky Wang this.value = value; 150*f585d8a3SJacky Wang } 151*f585d8a3SJacky Wang } 152*f585d8a3SJacky Wang 153*f585d8a3SJacky Wang // Must be public due to b/183636779 154*f585d8a3SJacky Wang public static class Bar { 155*f585d8a3SJacky Wang final String value; 156*f585d8a3SJacky Wang Bar(String value)157*f585d8a3SJacky Wang Bar(String value) { 158*f585d8a3SJacky Wang this.value = value; 159*f585d8a3SJacky Wang } 160*f585d8a3SJacky Wang } 161*f585d8a3SJacky Wang 162*f585d8a3SJacky Wang static class Baz { 163*f585d8a3SJacky Wang final long value; 164*f585d8a3SJacky Wang Baz(long value)165*f585d8a3SJacky Wang Baz(long value) { 166*f585d8a3SJacky Wang this.value = value; 167*f585d8a3SJacky Wang } 168*f585d8a3SJacky Wang } 169*f585d8a3SJacky Wang 170*f585d8a3SJacky Wang // Must be public due to b/183636779 171*f585d8a3SJacky Wang public static class Qux {} 172*f585d8a3SJacky Wang 173*f585d8a3SJacky Wang @Module 174*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 175*f585d8a3SJacky Wang public interface BarModule { 176*f585d8a3SJacky Wang @Provides provideBar(String value)177*f585d8a3SJacky Wang static Bar provideBar(String value) { 178*f585d8a3SJacky Wang return new Bar(value); 179*f585d8a3SJacky Wang } 180*f585d8a3SJacky Wang } 181*f585d8a3SJacky Wang 182*f585d8a3SJacky Wang @EntryPoint 183*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 184*f585d8a3SJacky Wang public interface BarEntryPoint { getBar()185*f585d8a3SJacky Wang Bar getBar(); 186*f585d8a3SJacky Wang } 187*f585d8a3SJacky Wang 188*f585d8a3SJacky Wang @EntryPoint 189*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 190*f585d8a3SJacky Wang interface PkgPrivateQuxEntryPoint { getQux()191*f585d8a3SJacky Wang Qux getQux(); 192*f585d8a3SJacky Wang } 193*f585d8a3SJacky Wang 194*f585d8a3SJacky Wang @Rule public HiltAndroidRule rule = new HiltAndroidRule(this); 195*f585d8a3SJacky Wang 196*f585d8a3SJacky Wang @Inject Foo foo; 197*f585d8a3SJacky Wang @Inject Qux qux; 198*f585d8a3SJacky Wang @Inject Long longValue; 199*f585d8a3SJacky Wang @Inject @MultiTestRootExternalModules.External String externalStrValue; 200*f585d8a3SJacky Wang 201*f585d8a3SJacky Wang @BindValue 202*f585d8a3SJacky Wang @Named(TEST_QUALIFIER) 203*f585d8a3SJacky Wang String bindValueString = BIND_VALUE_STRING; 204*f585d8a3SJacky Wang 205*f585d8a3SJacky Wang @Test testInjectFromTestModule()206*f585d8a3SJacky Wang public void testInjectFromTestModule() throws Exception { 207*f585d8a3SJacky Wang assertThat(foo).isNull(); 208*f585d8a3SJacky Wang setupComponent(); 209*f585d8a3SJacky Wang assertThat(foo).isNotNull(); 210*f585d8a3SJacky Wang assertThat(foo.value).isEqualTo(INT_VALUE); 211*f585d8a3SJacky Wang } 212*f585d8a3SJacky Wang 213*f585d8a3SJacky Wang @Test testInjectFromNestedTestModule()214*f585d8a3SJacky Wang public void testInjectFromNestedTestModule() throws Exception { 215*f585d8a3SJacky Wang assertThat(longValue).isNull(); 216*f585d8a3SJacky Wang setupComponent(); 217*f585d8a3SJacky Wang assertThat(longValue).isNotNull(); 218*f585d8a3SJacky Wang assertThat(longValue).isEqualTo(LONG_VALUE); 219*f585d8a3SJacky Wang } 220*f585d8a3SJacky Wang 221*f585d8a3SJacky Wang @Test testInjectFromExternalAppModule()222*f585d8a3SJacky Wang public void testInjectFromExternalAppModule() throws Exception { 223*f585d8a3SJacky Wang assertThat(externalStrValue).isNull(); 224*f585d8a3SJacky Wang setupComponent(); 225*f585d8a3SJacky Wang assertThat(externalStrValue).isNotNull(); 226*f585d8a3SJacky Wang assertThat(externalStrValue).isEqualTo(REPLACE_EXTERNAL_STR_VALUE); 227*f585d8a3SJacky Wang assertThat(externalStrValue).isNotEqualTo(MultiTestRootExternalModules.EXTERNAL_STR_VALUE); 228*f585d8a3SJacky Wang } 229*f585d8a3SJacky Wang 230*f585d8a3SJacky Wang @Test testInjectFromExternalActivityModule()231*f585d8a3SJacky Wang public void testInjectFromExternalActivityModule() throws Exception { 232*f585d8a3SJacky Wang setupComponent(); 233*f585d8a3SJacky Wang ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class); 234*f585d8a3SJacky Wang assertThat(ac.get().externalLongValue).isNull(); 235*f585d8a3SJacky Wang ac.create(); 236*f585d8a3SJacky Wang assertThat(ac.get().externalLongValue).isNotNull(); 237*f585d8a3SJacky Wang assertThat(ac.get().externalLongValue).isEqualTo(REPLACE_EXTERNAL_LONG_VALUE); 238*f585d8a3SJacky Wang assertThat(ac.get().externalLongValue) 239*f585d8a3SJacky Wang .isNotEqualTo(MultiTestRootExternalModules.EXTERNAL_LONG_VALUE); 240*f585d8a3SJacky Wang } 241*f585d8a3SJacky Wang 242*f585d8a3SJacky Wang @Test testInjectFromPkgPrivateTestModule()243*f585d8a3SJacky Wang public void testInjectFromPkgPrivateTestModule() throws Exception { 244*f585d8a3SJacky Wang assertThat(qux).isNull(); 245*f585d8a3SJacky Wang setupComponent(); 246*f585d8a3SJacky Wang assertThat(qux).isNotNull(); 247*f585d8a3SJacky Wang } 248*f585d8a3SJacky Wang 249*f585d8a3SJacky Wang @Test testLocalEntryPoint()250*f585d8a3SJacky Wang public void testLocalEntryPoint() throws Exception { 251*f585d8a3SJacky Wang setupComponent(); 252*f585d8a3SJacky Wang Bar bar = EntryPoints.get(getApplicationContext(), BarEntryPoint.class).getBar(); 253*f585d8a3SJacky Wang assertThat(bar).isNotNull(); 254*f585d8a3SJacky Wang assertThat(bar.value).isEqualTo(STR_VALUE); 255*f585d8a3SJacky Wang } 256*f585d8a3SJacky Wang 257*f585d8a3SJacky Wang @Test testLocalPkgPrivateEntryPoint()258*f585d8a3SJacky Wang public void testLocalPkgPrivateEntryPoint() throws Exception { 259*f585d8a3SJacky Wang setupComponent(); 260*f585d8a3SJacky Wang Qux qux = EntryPoints.get(getApplicationContext(), PkgPrivateQuxEntryPoint.class).getQux(); 261*f585d8a3SJacky Wang assertThat(qux).isNotNull(); 262*f585d8a3SJacky Wang } 263*f585d8a3SJacky Wang 264*f585d8a3SJacky Wang @Test testAndroidEntryPoint()265*f585d8a3SJacky Wang public void testAndroidEntryPoint() throws Exception { 266*f585d8a3SJacky Wang setupComponent(); 267*f585d8a3SJacky Wang ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class); 268*f585d8a3SJacky Wang assertThat(ac.get().baz).isNull(); 269*f585d8a3SJacky Wang ac.create(); 270*f585d8a3SJacky Wang assertThat(ac.get().baz).isNotNull(); 271*f585d8a3SJacky Wang assertThat(ac.get().baz.value).isEqualTo(LONG_VALUE); 272*f585d8a3SJacky Wang } 273*f585d8a3SJacky Wang 274*f585d8a3SJacky Wang @Test testMissingMultiTestRoot2EntryPoint()275*f585d8a3SJacky Wang public void testMissingMultiTestRoot2EntryPoint() throws Exception { 276*f585d8a3SJacky Wang setupComponent(); 277*f585d8a3SJacky Wang ClassCastException exception = 278*f585d8a3SJacky Wang assertThrows( 279*f585d8a3SJacky Wang ClassCastException.class, 280*f585d8a3SJacky Wang () -> EntryPoints.get(getApplicationContext(), MultiTestRoot2Test.BarEntryPoint.class)); 281*f585d8a3SJacky Wang assertThat(exception) 282*f585d8a3SJacky Wang .hasMessageThat() 283*f585d8a3SJacky Wang .isEqualTo( 284*f585d8a3SJacky Wang "Cannot cast dagger.hilt.android.internal.testing.root." 285*f585d8a3SJacky Wang + "DaggerMultiTestRoot1Test_HiltComponents_SingletonC$SingletonCImpl" 286*f585d8a3SJacky Wang + " to dagger.hilt.android.MultiTestRoot2Test$BarEntryPoint"); 287*f585d8a3SJacky Wang } 288*f585d8a3SJacky Wang 289*f585d8a3SJacky Wang @Test testBindValueFieldIsProvided()290*f585d8a3SJacky Wang public void testBindValueFieldIsProvided() throws Exception { 291*f585d8a3SJacky Wang setupComponent(); 292*f585d8a3SJacky Wang assertThat(bindValueString).isEqualTo(BIND_VALUE_STRING); 293*f585d8a3SJacky Wang assertThat(getBinding()).isEqualTo(BIND_VALUE_STRING); 294*f585d8a3SJacky Wang } 295*f585d8a3SJacky Wang 296*f585d8a3SJacky Wang @Test testBindValueIsMutable()297*f585d8a3SJacky Wang public void testBindValueIsMutable() throws Exception { 298*f585d8a3SJacky Wang setupComponent(); 299*f585d8a3SJacky Wang bindValueString = "newValue"; 300*f585d8a3SJacky Wang assertThat(getBinding()).isEqualTo("newValue"); 301*f585d8a3SJacky Wang } 302*f585d8a3SJacky Wang setupComponent()303*f585d8a3SJacky Wang void setupComponent() { 304*f585d8a3SJacky Wang rule.inject(); 305*f585d8a3SJacky Wang } 306*f585d8a3SJacky Wang getBinding()307*f585d8a3SJacky Wang private static String getBinding() { 308*f585d8a3SJacky Wang return EntryPoints.get(getApplicationContext(), BindValueEntryPoint.class).bindValueString(); 309*f585d8a3SJacky Wang } 310*f585d8a3SJacky Wang } 311