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