1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2021 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.test.ext.junit.runners.AndroidJUnit4; 25*f585d8a3SJacky Wang import dagger.hilt.EntryPoint; 26*f585d8a3SJacky Wang import dagger.hilt.EntryPoints; 27*f585d8a3SJacky Wang import dagger.hilt.InstallIn; 28*f585d8a3SJacky Wang import dagger.hilt.android.EarlyEntryPointHiltAndroidTestRuntimeClasses.BarEntryPoint; 29*f585d8a3SJacky Wang import dagger.hilt.android.EarlyEntryPointHiltAndroidTestRuntimeClasses.EarlyFooEntryPoint; 30*f585d8a3SJacky Wang import dagger.hilt.android.EarlyEntryPointHiltAndroidTestRuntimeClasses.EarlyMySubcomponentBuilderEntryPoint; 31*f585d8a3SJacky Wang import dagger.hilt.android.EarlyEntryPointHiltAndroidTestRuntimeClasses.MySubcomponent; 32*f585d8a3SJacky Wang import dagger.hilt.android.EarlyEntryPointHiltAndroidTestRuntimeClasses.MySubcomponentBuilderEntryPoint; 33*f585d8a3SJacky Wang import dagger.hilt.android.EarlyEntryPointHiltAndroidTestRuntimeClasses.MySubcomponentScoped; 34*f585d8a3SJacky Wang import dagger.hilt.android.internal.testing.TestApplicationComponentManager; 35*f585d8a3SJacky Wang import dagger.hilt.android.testing.HiltAndroidRule; 36*f585d8a3SJacky Wang import dagger.hilt.android.testing.HiltAndroidTest; 37*f585d8a3SJacky Wang import dagger.hilt.android.testing.HiltTestApplication; 38*f585d8a3SJacky Wang import dagger.hilt.components.SingletonComponent; 39*f585d8a3SJacky Wang import javax.inject.Inject; 40*f585d8a3SJacky Wang import javax.inject.Singleton; 41*f585d8a3SJacky Wang import org.junit.Rule; 42*f585d8a3SJacky Wang import org.junit.Test; 43*f585d8a3SJacky Wang import org.junit.runner.RunWith; 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 EarlyEntryPointHiltAndroidTestRuntimeTest { 51*f585d8a3SJacky Wang @EntryPoint 52*f585d8a3SJacky Wang @InstallIn(SingletonComponent.class) 53*f585d8a3SJacky Wang interface FooEntryPoint { foo()54*f585d8a3SJacky Wang Foo foo(); 55*f585d8a3SJacky Wang } 56*f585d8a3SJacky Wang 57*f585d8a3SJacky Wang @Singleton 58*f585d8a3SJacky Wang public static class Foo { 59*f585d8a3SJacky Wang @Inject Foo()60*f585d8a3SJacky Wang Foo() {} 61*f585d8a3SJacky Wang } 62*f585d8a3SJacky Wang 63*f585d8a3SJacky Wang @MySubcomponentScoped 64*f585d8a3SJacky Wang public static class Bar { 65*f585d8a3SJacky Wang final Foo foo; 66*f585d8a3SJacky Wang final int id; 67*f585d8a3SJacky Wang 68*f585d8a3SJacky Wang @Inject Bar(Foo foo, int id)69*f585d8a3SJacky Wang Bar(Foo foo, int id) { 70*f585d8a3SJacky Wang this.foo = foo; 71*f585d8a3SJacky Wang this.id = id; 72*f585d8a3SJacky Wang } 73*f585d8a3SJacky Wang } 74*f585d8a3SJacky Wang 75*f585d8a3SJacky Wang @Rule public HiltAndroidRule rule = new HiltAndroidRule(this); 76*f585d8a3SJacky Wang 77*f585d8a3SJacky Wang @Test testEarlyEntryPointsWrongEntryPointFails()78*f585d8a3SJacky Wang public void testEarlyEntryPointsWrongEntryPointFails() throws Exception { 79*f585d8a3SJacky Wang IllegalStateException exception = 80*f585d8a3SJacky Wang assertThrows( 81*f585d8a3SJacky Wang IllegalStateException.class, 82*f585d8a3SJacky Wang () -> EarlyEntryPoints.get(getApplicationContext(), FooEntryPoint.class)); 83*f585d8a3SJacky Wang 84*f585d8a3SJacky Wang assertThat(exception) 85*f585d8a3SJacky Wang .hasMessageThat() 86*f585d8a3SJacky Wang .contains( 87*f585d8a3SJacky Wang "FooEntryPoint should be called with EntryPoints.get() rather than " 88*f585d8a3SJacky Wang + "EarlyEntryPoints.get()"); 89*f585d8a3SJacky Wang } 90*f585d8a3SJacky Wang 91*f585d8a3SJacky Wang @Test testEntryPointsWrongEntryPointFails()92*f585d8a3SJacky Wang public void testEntryPointsWrongEntryPointFails() throws Exception { 93*f585d8a3SJacky Wang IllegalStateException exception = 94*f585d8a3SJacky Wang assertThrows( 95*f585d8a3SJacky Wang IllegalStateException.class, 96*f585d8a3SJacky Wang () -> EntryPoints.get(getApplicationContext(), EarlyFooEntryPoint.class)); 97*f585d8a3SJacky Wang 98*f585d8a3SJacky Wang assertThat(exception) 99*f585d8a3SJacky Wang .hasMessageThat() 100*f585d8a3SJacky Wang .contains( 101*f585d8a3SJacky Wang "Interface, dagger.hilt.android.EarlyEntryPointHiltAndroidTestRuntimeClasses." 102*f585d8a3SJacky Wang + "EarlyFooEntryPoint, annotated with @EarlyEntryPoint should be called with " 103*f585d8a3SJacky Wang + "EarlyEntryPoints.get() rather than EntryPoints.get()"); 104*f585d8a3SJacky Wang } 105*f585d8a3SJacky Wang 106*f585d8a3SJacky Wang @Test testComponentInstances()107*f585d8a3SJacky Wang public void testComponentInstances() { 108*f585d8a3SJacky Wang Object componentManager = ((HiltTestApplication) getApplicationContext()).componentManager(); 109*f585d8a3SJacky Wang Object component1 = ((TestApplicationComponentManager) componentManager).generatedComponent(); 110*f585d8a3SJacky Wang Object component2 = ((TestApplicationComponentManager) componentManager).generatedComponent(); 111*f585d8a3SJacky Wang assertThat(component1).isNotNull(); 112*f585d8a3SJacky Wang assertThat(component2).isNotNull(); 113*f585d8a3SJacky Wang assertThat(component1).isEqualTo(component2); 114*f585d8a3SJacky Wang 115*f585d8a3SJacky Wang Object earlyComponent1 = 116*f585d8a3SJacky Wang ((TestApplicationComponentManager) componentManager).earlySingletonComponent(); 117*f585d8a3SJacky Wang Object earlyComponent2 = 118*f585d8a3SJacky Wang ((TestApplicationComponentManager) componentManager).earlySingletonComponent(); 119*f585d8a3SJacky Wang assertThat(earlyComponent1).isNotNull(); 120*f585d8a3SJacky Wang assertThat(earlyComponent2).isNotNull(); 121*f585d8a3SJacky Wang assertThat(earlyComponent1).isEqualTo(earlyComponent2); 122*f585d8a3SJacky Wang assertThat(earlyComponent1).isNotEqualTo(component1); 123*f585d8a3SJacky Wang } 124*f585d8a3SJacky Wang 125*f585d8a3SJacky Wang // Test that the early entry point returns a different @Singleton binding instance. 126*f585d8a3SJacky Wang @Test testScopedEntryPointValues()127*f585d8a3SJacky Wang public void testScopedEntryPointValues() { 128*f585d8a3SJacky Wang Foo foo1 = EntryPoints.get(getApplicationContext(), FooEntryPoint.class).foo(); 129*f585d8a3SJacky Wang Foo foo2 = EntryPoints.get(getApplicationContext(), FooEntryPoint.class).foo(); 130*f585d8a3SJacky Wang Foo earlyFoo1 = 131*f585d8a3SJacky Wang EarlyEntryPoints.get(getApplicationContext(), EarlyFooEntryPoint.class).foo(); 132*f585d8a3SJacky Wang Foo earlyFoo2 = 133*f585d8a3SJacky Wang EarlyEntryPoints.get(getApplicationContext(), EarlyFooEntryPoint.class).foo(); 134*f585d8a3SJacky Wang 135*f585d8a3SJacky Wang assertThat(foo1).isNotNull(); 136*f585d8a3SJacky Wang assertThat(foo2).isNotNull(); 137*f585d8a3SJacky Wang assertThat(earlyFoo1).isNotNull(); 138*f585d8a3SJacky Wang assertThat(earlyFoo2).isNotNull(); 139*f585d8a3SJacky Wang 140*f585d8a3SJacky Wang assertThat(foo1).isEqualTo(foo2); 141*f585d8a3SJacky Wang assertThat(earlyFoo1).isEqualTo(earlyFoo2); 142*f585d8a3SJacky Wang assertThat(earlyFoo1).isNotEqualTo(foo1); 143*f585d8a3SJacky Wang } 144*f585d8a3SJacky Wang 145*f585d8a3SJacky Wang // Test that the a subcomponent of the early component does not need to use EarlyEntryPoints. 146*f585d8a3SJacky Wang @Test testSubcomponentEntryPoints()147*f585d8a3SJacky Wang public void testSubcomponentEntryPoints() { 148*f585d8a3SJacky Wang MySubcomponent subcomponent = 149*f585d8a3SJacky Wang EntryPoints.get(getApplicationContext(), MySubcomponentBuilderEntryPoint.class) 150*f585d8a3SJacky Wang .mySubcomponentBuilder() 151*f585d8a3SJacky Wang .id(5) 152*f585d8a3SJacky Wang .build(); 153*f585d8a3SJacky Wang 154*f585d8a3SJacky Wang MySubcomponent earlySubcomponent = 155*f585d8a3SJacky Wang EarlyEntryPoints.get( 156*f585d8a3SJacky Wang getApplicationContext(), EarlyMySubcomponentBuilderEntryPoint.class) 157*f585d8a3SJacky Wang .mySubcomponentBuilder() 158*f585d8a3SJacky Wang .id(11) 159*f585d8a3SJacky Wang .build(); 160*f585d8a3SJacky Wang 161*f585d8a3SJacky Wang assertThat(subcomponent).isNotNull(); 162*f585d8a3SJacky Wang assertThat(earlySubcomponent).isNotNull(); 163*f585d8a3SJacky Wang assertThat(subcomponent).isNotEqualTo(earlySubcomponent); 164*f585d8a3SJacky Wang 165*f585d8a3SJacky Wang // Test that subcomponents can use EntryPoints 166*f585d8a3SJacky Wang Bar bar1 = EntryPoints.get(subcomponent, BarEntryPoint.class).bar(); 167*f585d8a3SJacky Wang Bar bar2 = EntryPoints.get(subcomponent, BarEntryPoint.class).bar(); 168*f585d8a3SJacky Wang 169*f585d8a3SJacky Wang // Test that early subcomponents can use EntryPoints or EarlyEntryPoints 170*f585d8a3SJacky Wang Bar earlyBar1 = EntryPoints.get(earlySubcomponent, BarEntryPoint.class).bar(); 171*f585d8a3SJacky Wang Bar earlyBar2 = EntryPoints.get(earlySubcomponent, BarEntryPoint.class).bar(); 172*f585d8a3SJacky Wang 173*f585d8a3SJacky Wang assertThat(bar1).isNotNull(); 174*f585d8a3SJacky Wang assertThat(bar2).isNotNull(); 175*f585d8a3SJacky Wang assertThat(earlyBar1).isNotNull(); 176*f585d8a3SJacky Wang assertThat(earlyBar2).isNotNull(); 177*f585d8a3SJacky Wang assertThat(bar1).isEqualTo(bar2); 178*f585d8a3SJacky Wang assertThat(earlyBar1).isEqualTo(earlyBar2); 179*f585d8a3SJacky Wang assertThat(bar1).isNotEqualTo(earlyBar1); 180*f585d8a3SJacky Wang } 181*f585d8a3SJacky Wang } 182