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 // Must be public due to b/183636779 125 public static class Bar { 126 final String value; 127 Bar(String value)128 Bar(String value) { 129 this.value = value; 130 } 131 } 132 133 static class Baz { 134 final long value; 135 Baz(long value)136 Baz(long value) { 137 this.value = value; 138 } 139 } 140 141 // Must be public due to b/183636779 142 public static class Qux {} 143 144 @Module 145 @InstallIn(SingletonComponent.class) 146 public interface BarModule { 147 @Provides provideBar(String value)148 static Bar provideBar(String value) { 149 return new Bar(value); 150 } 151 } 152 153 @EntryPoint 154 @InstallIn(SingletonComponent.class) 155 public interface BarEntryPoint { getBar()156 Bar getBar(); 157 } 158 159 @EntryPoint 160 @InstallIn(SingletonComponent.class) 161 interface PkgPrivateQuxEntryPoint { getQux()162 Qux getQux(); 163 } 164 165 @Rule public HiltAndroidRule rule = new HiltAndroidRule(this); 166 167 @Inject Foo foo; 168 @Inject Qux qux; 169 @Inject String str; 170 @Inject Long longValue; 171 @Inject @MultiTestRootExternalModules.External String externalStrValue; 172 173 @BindValue 174 @Named(TEST_QUALIFIER) 175 String bindValueString = BIND_VALUE_STRING; 176 177 @Test testInjectFromTestModule()178 public void testInjectFromTestModule() throws Exception { 179 assertThat(foo).isNull(); 180 rule.inject(); 181 assertThat(foo).isNotNull(); 182 assertThat(foo.value).isEqualTo(INT_VALUE); 183 } 184 185 @Test testInjectFromTestModuleWithArgs()186 public void testInjectFromTestModuleWithArgs() throws Exception { 187 assertThat(str).isNull(); 188 rule.inject(); 189 assertThat(str).isNotNull(); 190 assertThat(str).isEqualTo(STR_VALUE); 191 } 192 193 @Test testInjectFromNestedTestModule()194 public void testInjectFromNestedTestModule() throws Exception { 195 assertThat(longValue).isNull(); 196 rule.inject(); 197 assertThat(longValue).isNotNull(); 198 assertThat(longValue).isEqualTo(LONG_VALUE); 199 } 200 201 @Test testInjectFromPkgPrivateTestModule()202 public void testInjectFromPkgPrivateTestModule() throws Exception { 203 assertThat(qux).isNull(); 204 rule.inject(); 205 assertThat(qux).isNotNull(); 206 } 207 208 @Test testInjectFromExternalAppModule()209 public void testInjectFromExternalAppModule() throws Exception { 210 assertThat(externalStrValue).isNull(); 211 rule.inject(); 212 assertThat(externalStrValue).isNotNull(); 213 assertThat(externalStrValue).isEqualTo(MultiTestRootExternalModules.EXTERNAL_STR_VALUE); 214 } 215 216 @Test testInjectFromExternalActivityModule()217 public void testInjectFromExternalActivityModule() throws Exception { 218 rule.inject(); 219 ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class); 220 assertThat(ac.get().externalLongValue).isNull(); 221 ac.create(); 222 assertThat(ac.get().externalLongValue).isNotNull(); 223 assertThat(ac.get().externalLongValue) 224 .isEqualTo(MultiTestRootExternalModules.EXTERNAL_LONG_VALUE); 225 } 226 227 @Test testLocalEntryPoint()228 public void testLocalEntryPoint() throws Exception { 229 rule.inject(); 230 Bar bar = EntryPoints.get(getApplicationContext(), BarEntryPoint.class).getBar(); 231 assertThat(bar).isNotNull(); 232 assertThat(bar.value).isEqualTo(STR_VALUE); 233 } 234 235 @Test testLocalPkgPrivateEntryPoint()236 public void testLocalPkgPrivateEntryPoint() throws Exception { 237 rule.inject(); 238 Qux qux = EntryPoints.get(getApplicationContext(), PkgPrivateQuxEntryPoint.class).getQux(); 239 assertThat(qux).isNotNull(); 240 } 241 242 @Test testAndroidEntryPoint()243 public void testAndroidEntryPoint() throws Exception { 244 rule.inject(); 245 ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class); 246 assertThat(ac.get().baz).isNull(); 247 ac.create(); 248 assertThat(ac.get().baz).isNotNull(); 249 assertThat(ac.get().baz.value).isEqualTo(LONG_VALUE); 250 } 251 252 @Test testMissingMultiTestRoot1EntryPoint()253 public void testMissingMultiTestRoot1EntryPoint() throws Exception { 254 rule.inject(); 255 ClassCastException exception = 256 assertThrows( 257 ClassCastException.class, 258 () -> EntryPoints.get(getApplicationContext(), MultiTestRoot1Test.BarEntryPoint.class)); 259 assertThat(exception) 260 .hasMessageThat() 261 .isEqualTo( 262 "Cannot cast dagger.hilt.android.internal.testing.root." 263 + "DaggerMultiTestRoot2Test_HiltComponents_SingletonC" 264 + " to dagger.hilt.android.MultiTestRoot1Test$BarEntryPoint"); 265 } 266 267 @Test testBindValueFieldIsProvided()268 public void testBindValueFieldIsProvided() throws Exception { 269 rule.inject(); 270 assertThat(bindValueString).isEqualTo(BIND_VALUE_STRING); 271 assertThat(getBinding()).isEqualTo(BIND_VALUE_STRING); 272 } 273 274 @Test testBindValueIsMutable()275 public void testBindValueIsMutable() throws Exception { 276 rule.inject(); 277 bindValueString = "newValue"; 278 assertThat(getBinding()).isEqualTo("newValue"); 279 } 280 getBinding()281 private static String getBinding() { 282 return EntryPoints.get(getApplicationContext(), BindValueEntryPoint.class).bindValueString(); 283 } 284 } 285