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.components.SingletonComponent; 37*f585d8a3SJacky Wang import javax.inject.Inject; 38*f585d8a3SJacky Wang import javax.inject.Named; 39*f585d8a3SJacky Wang import org.junit.Rule; 40*f585d8a3SJacky Wang import org.junit.Test; 41*f585d8a3SJacky Wang import org.junit.runner.RunWith; 42*f585d8a3SJacky Wang import org.robolectric.Robolectric; 43*f585d8a3SJacky Wang import org.robolectric.android.controller.ActivityController; 44*f585d8a3SJacky Wang import org.robolectric.annotation.Config; 45*f585d8a3SJacky Wang 46*f585d8a3SJacky Wang @HiltAndroidTest 47*f585d8a3SJacky Wang @RunWith(AndroidJUnit4.class) 48*f585d8a3SJacky Wang // Robolectric requires Java9 to run API 29 and above, so use API 28 instead 49*f585d8a3SJacky Wang @Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class) 50*f585d8a3SJacky Wang public final class MultiTestRoot2Test { 51*f585d8a3SJacky Wang private static final int INT_VALUE = 13; 52*f585d8a3SJacky Wang private static final String STR_VALUE = "MultiTestRoot2TestValue"; 53*f585d8a3SJacky Wang private static final long LONG_VALUE = 17L; 54*f585d8a3SJacky Wang private static final String BIND_VALUE_STRING = "BIND_VALUE_STRING"; 55*f585d8a3SJacky Wang private static final String TEST_QUALIFIER = "TEST_QUALIFIER"; 56*f585d8a3SJacky Wang 57*f585d8a3SJacky Wang @EntryPoint 58*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 59*f585d8a3SJacky Wang public interface BindValueEntryPoint { 60*f585d8a3SJacky Wang @Named(TEST_QUALIFIER) bindValueString()61*f585d8a3SJacky Wang String bindValueString(); 62*f585d8a3SJacky Wang } 63*f585d8a3SJacky Wang 64*f585d8a3SJacky Wang @AndroidEntryPoint(ComponentActivity.class) 65*f585d8a3SJacky Wang public static class TestActivity extends Hilt_MultiTestRoot2Test_TestActivity { 66*f585d8a3SJacky Wang @Inject Baz baz; 67*f585d8a3SJacky Wang @Inject @MultiTestRootExternalModules.External Long externalLongValue; 68*f585d8a3SJacky Wang } 69*f585d8a3SJacky Wang 70*f585d8a3SJacky Wang @Module 71*f585d8a3SJacky Wang @InstallIn(ActivityComponent.class) 72*f585d8a3SJacky Wang public interface TestActivityModule { 73*f585d8a3SJacky Wang @Provides provideBaz()74*f585d8a3SJacky Wang static Baz provideBaz() { 75*f585d8a3SJacky Wang return new Baz(LONG_VALUE); 76*f585d8a3SJacky Wang } 77*f585d8a3SJacky Wang } 78*f585d8a3SJacky Wang 79*f585d8a3SJacky Wang @Module 80*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 81*f585d8a3SJacky Wang interface PkgPrivateTestModule { 82*f585d8a3SJacky Wang @Provides provideQux()83*f585d8a3SJacky Wang static Qux provideQux() { 84*f585d8a3SJacky Wang return new Qux(); 85*f585d8a3SJacky Wang } 86*f585d8a3SJacky Wang } 87*f585d8a3SJacky Wang 88*f585d8a3SJacky Wang @Module 89*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 90*f585d8a3SJacky Wang public interface TestModule { 91*f585d8a3SJacky Wang @Provides provideInt()92*f585d8a3SJacky Wang static int provideInt() { 93*f585d8a3SJacky Wang return INT_VALUE; 94*f585d8a3SJacky Wang } 95*f585d8a3SJacky Wang 96*f585d8a3SJacky Wang @Provides provideString()97*f585d8a3SJacky Wang static String provideString() { 98*f585d8a3SJacky Wang return STR_VALUE; 99*f585d8a3SJacky Wang } 100*f585d8a3SJacky Wang } 101*f585d8a3SJacky Wang 102*f585d8a3SJacky Wang public static final class Outer { 103*f585d8a3SJacky Wang @Module 104*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 105*f585d8a3SJacky Wang public interface NestedTestModule { 106*f585d8a3SJacky Wang @Provides provideLong()107*f585d8a3SJacky Wang static long provideLong() { 108*f585d8a3SJacky Wang return LONG_VALUE; 109*f585d8a3SJacky Wang } 110*f585d8a3SJacky Wang } 111*f585d8a3SJacky Wang Outer()112*f585d8a3SJacky Wang private Outer() {} 113*f585d8a3SJacky Wang } 114*f585d8a3SJacky Wang 115*f585d8a3SJacky Wang static class Foo { 116*f585d8a3SJacky Wang final int value; 117*f585d8a3SJacky Wang 118*f585d8a3SJacky Wang @Inject Foo(int value)119*f585d8a3SJacky Wang Foo(int value) { 120*f585d8a3SJacky Wang this.value = value; 121*f585d8a3SJacky Wang } 122*f585d8a3SJacky Wang } 123*f585d8a3SJacky Wang 124*f585d8a3SJacky Wang // Must be public due to b/183636779 125*f585d8a3SJacky Wang public static class Bar { 126*f585d8a3SJacky Wang final String value; 127*f585d8a3SJacky Wang Bar(String value)128*f585d8a3SJacky Wang Bar(String value) { 129*f585d8a3SJacky Wang this.value = value; 130*f585d8a3SJacky Wang } 131*f585d8a3SJacky Wang } 132*f585d8a3SJacky Wang 133*f585d8a3SJacky Wang static class Baz { 134*f585d8a3SJacky Wang final long value; 135*f585d8a3SJacky Wang Baz(long value)136*f585d8a3SJacky Wang Baz(long value) { 137*f585d8a3SJacky Wang this.value = value; 138*f585d8a3SJacky Wang } 139*f585d8a3SJacky Wang } 140*f585d8a3SJacky Wang 141*f585d8a3SJacky Wang // Must be public due to b/183636779 142*f585d8a3SJacky Wang public static class Qux {} 143*f585d8a3SJacky Wang 144*f585d8a3SJacky Wang @Module 145*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 146*f585d8a3SJacky Wang public interface BarModule { 147*f585d8a3SJacky Wang @Provides provideBar(String value)148*f585d8a3SJacky Wang static Bar provideBar(String value) { 149*f585d8a3SJacky Wang return new Bar(value); 150*f585d8a3SJacky Wang } 151*f585d8a3SJacky Wang } 152*f585d8a3SJacky Wang 153*f585d8a3SJacky Wang @EntryPoint 154*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 155*f585d8a3SJacky Wang public interface BarEntryPoint { getBar()156*f585d8a3SJacky Wang Bar getBar(); 157*f585d8a3SJacky Wang } 158*f585d8a3SJacky Wang 159*f585d8a3SJacky Wang @EntryPoint 160*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 161*f585d8a3SJacky Wang interface PkgPrivateQuxEntryPoint { getQux()162*f585d8a3SJacky Wang Qux getQux(); 163*f585d8a3SJacky Wang } 164*f585d8a3SJacky Wang 165*f585d8a3SJacky Wang @Rule public HiltAndroidRule rule = new HiltAndroidRule(this); 166*f585d8a3SJacky Wang 167*f585d8a3SJacky Wang @Inject Foo foo; 168*f585d8a3SJacky Wang @Inject Qux qux; 169*f585d8a3SJacky Wang @Inject String str; 170*f585d8a3SJacky Wang @Inject Long longValue; 171*f585d8a3SJacky Wang @Inject @MultiTestRootExternalModules.External String externalStrValue; 172*f585d8a3SJacky Wang 173*f585d8a3SJacky Wang @BindValue 174*f585d8a3SJacky Wang @Named(TEST_QUALIFIER) 175*f585d8a3SJacky Wang String bindValueString = BIND_VALUE_STRING; 176*f585d8a3SJacky Wang 177*f585d8a3SJacky Wang @Test testInjectFromTestModule()178*f585d8a3SJacky Wang public void testInjectFromTestModule() throws Exception { 179*f585d8a3SJacky Wang assertThat(foo).isNull(); 180*f585d8a3SJacky Wang rule.inject(); 181*f585d8a3SJacky Wang assertThat(foo).isNotNull(); 182*f585d8a3SJacky Wang assertThat(foo.value).isEqualTo(INT_VALUE); 183*f585d8a3SJacky Wang } 184*f585d8a3SJacky Wang 185*f585d8a3SJacky Wang @Test testInjectFromTestModuleWithArgs()186*f585d8a3SJacky Wang public void testInjectFromTestModuleWithArgs() throws Exception { 187*f585d8a3SJacky Wang assertThat(str).isNull(); 188*f585d8a3SJacky Wang rule.inject(); 189*f585d8a3SJacky Wang assertThat(str).isNotNull(); 190*f585d8a3SJacky Wang assertThat(str).isEqualTo(STR_VALUE); 191*f585d8a3SJacky Wang } 192*f585d8a3SJacky Wang 193*f585d8a3SJacky Wang @Test testInjectFromNestedTestModule()194*f585d8a3SJacky Wang public void testInjectFromNestedTestModule() throws Exception { 195*f585d8a3SJacky Wang assertThat(longValue).isNull(); 196*f585d8a3SJacky Wang rule.inject(); 197*f585d8a3SJacky Wang assertThat(longValue).isNotNull(); 198*f585d8a3SJacky Wang assertThat(longValue).isEqualTo(LONG_VALUE); 199*f585d8a3SJacky Wang } 200*f585d8a3SJacky Wang 201*f585d8a3SJacky Wang @Test testInjectFromPkgPrivateTestModule()202*f585d8a3SJacky Wang public void testInjectFromPkgPrivateTestModule() throws Exception { 203*f585d8a3SJacky Wang assertThat(qux).isNull(); 204*f585d8a3SJacky Wang rule.inject(); 205*f585d8a3SJacky Wang assertThat(qux).isNotNull(); 206*f585d8a3SJacky Wang } 207*f585d8a3SJacky Wang 208*f585d8a3SJacky Wang @Test testInjectFromExternalAppModule()209*f585d8a3SJacky Wang public void testInjectFromExternalAppModule() throws Exception { 210*f585d8a3SJacky Wang assertThat(externalStrValue).isNull(); 211*f585d8a3SJacky Wang rule.inject(); 212*f585d8a3SJacky Wang assertThat(externalStrValue).isNotNull(); 213*f585d8a3SJacky Wang assertThat(externalStrValue).isEqualTo(MultiTestRootExternalModules.EXTERNAL_STR_VALUE); 214*f585d8a3SJacky Wang } 215*f585d8a3SJacky Wang 216*f585d8a3SJacky Wang @Test testInjectFromExternalActivityModule()217*f585d8a3SJacky Wang public void testInjectFromExternalActivityModule() throws Exception { 218*f585d8a3SJacky Wang rule.inject(); 219*f585d8a3SJacky Wang ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class); 220*f585d8a3SJacky Wang assertThat(ac.get().externalLongValue).isNull(); 221*f585d8a3SJacky Wang ac.create(); 222*f585d8a3SJacky Wang assertThat(ac.get().externalLongValue).isNotNull(); 223*f585d8a3SJacky Wang assertThat(ac.get().externalLongValue) 224*f585d8a3SJacky Wang .isEqualTo(MultiTestRootExternalModules.EXTERNAL_LONG_VALUE); 225*f585d8a3SJacky Wang } 226*f585d8a3SJacky Wang 227*f585d8a3SJacky Wang @Test testLocalEntryPoint()228*f585d8a3SJacky Wang public void testLocalEntryPoint() throws Exception { 229*f585d8a3SJacky Wang rule.inject(); 230*f585d8a3SJacky Wang Bar bar = EntryPoints.get(getApplicationContext(), BarEntryPoint.class).getBar(); 231*f585d8a3SJacky Wang assertThat(bar).isNotNull(); 232*f585d8a3SJacky Wang assertThat(bar.value).isEqualTo(STR_VALUE); 233*f585d8a3SJacky Wang } 234*f585d8a3SJacky Wang 235*f585d8a3SJacky Wang @Test testLocalPkgPrivateEntryPoint()236*f585d8a3SJacky Wang public void testLocalPkgPrivateEntryPoint() throws Exception { 237*f585d8a3SJacky Wang rule.inject(); 238*f585d8a3SJacky Wang Qux qux = EntryPoints.get(getApplicationContext(), PkgPrivateQuxEntryPoint.class).getQux(); 239*f585d8a3SJacky Wang assertThat(qux).isNotNull(); 240*f585d8a3SJacky Wang } 241*f585d8a3SJacky Wang 242*f585d8a3SJacky Wang @Test testAndroidEntryPoint()243*f585d8a3SJacky Wang public void testAndroidEntryPoint() throws Exception { 244*f585d8a3SJacky Wang rule.inject(); 245*f585d8a3SJacky Wang ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class); 246*f585d8a3SJacky Wang assertThat(ac.get().baz).isNull(); 247*f585d8a3SJacky Wang ac.create(); 248*f585d8a3SJacky Wang assertThat(ac.get().baz).isNotNull(); 249*f585d8a3SJacky Wang assertThat(ac.get().baz.value).isEqualTo(LONG_VALUE); 250*f585d8a3SJacky Wang } 251*f585d8a3SJacky Wang 252*f585d8a3SJacky Wang @Test testMissingMultiTestRoot1EntryPoint()253*f585d8a3SJacky Wang public void testMissingMultiTestRoot1EntryPoint() throws Exception { 254*f585d8a3SJacky Wang rule.inject(); 255*f585d8a3SJacky Wang ClassCastException exception = 256*f585d8a3SJacky Wang assertThrows( 257*f585d8a3SJacky Wang ClassCastException.class, 258*f585d8a3SJacky Wang () -> EntryPoints.get(getApplicationContext(), MultiTestRoot1Test.BarEntryPoint.class)); 259*f585d8a3SJacky Wang assertThat(exception) 260*f585d8a3SJacky Wang .hasMessageThat() 261*f585d8a3SJacky Wang .isEqualTo( 262*f585d8a3SJacky Wang "Cannot cast dagger.hilt.android.internal.testing.root." 263*f585d8a3SJacky Wang + "DaggerMultiTestRoot2Test_HiltComponents_SingletonC$SingletonCImpl" 264*f585d8a3SJacky Wang + " to dagger.hilt.android.MultiTestRoot1Test$BarEntryPoint"); 265*f585d8a3SJacky Wang } 266*f585d8a3SJacky Wang 267*f585d8a3SJacky Wang @Test testBindValueFieldIsProvided()268*f585d8a3SJacky Wang public void testBindValueFieldIsProvided() throws Exception { 269*f585d8a3SJacky Wang rule.inject(); 270*f585d8a3SJacky Wang assertThat(bindValueString).isEqualTo(BIND_VALUE_STRING); 271*f585d8a3SJacky Wang assertThat(getBinding()).isEqualTo(BIND_VALUE_STRING); 272*f585d8a3SJacky Wang } 273*f585d8a3SJacky Wang 274*f585d8a3SJacky Wang @Test testBindValueIsMutable()275*f585d8a3SJacky Wang public void testBindValueIsMutable() throws Exception { 276*f585d8a3SJacky Wang rule.inject(); 277*f585d8a3SJacky Wang bindValueString = "newValue"; 278*f585d8a3SJacky Wang assertThat(getBinding()).isEqualTo("newValue"); 279*f585d8a3SJacky Wang } 280*f585d8a3SJacky Wang getBinding()281*f585d8a3SJacky Wang private static String getBinding() { 282*f585d8a3SJacky Wang return EntryPoints.get(getApplicationContext(), BindValueEntryPoint.class).bindValueString(); 283*f585d8a3SJacky Wang } 284*f585d8a3SJacky Wang } 285