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 java.lang.annotation.RetentionPolicy.RUNTIME; 22 import static org.junit.Assert.fail; 23 24 import android.annotation.TargetApi; 25 import android.app.Activity; 26 import android.app.IntentService; 27 import android.app.Service; 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.os.Build; 32 import android.os.Bundle; 33 import android.os.IBinder; 34 import androidx.fragment.app.Fragment; 35 import androidx.fragment.app.FragmentActivity; 36 import android.util.AttributeSet; 37 import android.widget.LinearLayout; 38 import androidx.test.ext.junit.runners.AndroidJUnit4; 39 import dagger.Module; 40 import dagger.Provides; 41 import dagger.hilt.InstallIn; 42 import dagger.hilt.android.components.ActivityComponent; 43 import dagger.hilt.android.components.FragmentComponent; 44 import dagger.hilt.android.components.ServiceComponent; 45 import dagger.hilt.android.testing.HiltAndroidRule; 46 import dagger.hilt.android.testing.HiltAndroidTest; 47 import dagger.hilt.android.testing.HiltTestApplication; 48 import dagger.hilt.components.SingletonComponent; 49 import java.lang.annotation.ElementType; 50 import java.lang.annotation.Retention; 51 import java.lang.annotation.Target; 52 import java.util.concurrent.atomic.AtomicLong; 53 import javax.inject.Inject; 54 import javax.inject.Qualifier; 55 import javax.inject.Singleton; 56 import org.junit.Before; 57 import org.junit.Rule; 58 import org.junit.Test; 59 import org.junit.runner.RunWith; 60 import org.robolectric.Robolectric; 61 import org.robolectric.android.controller.ActivityController; 62 import org.robolectric.annotation.Config; 63 64 @HiltAndroidTest 65 @RunWith(AndroidJUnit4.class) 66 // Robolectric requires Java9 to run API 29 and above, so use API 28 instead 67 @Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class) 68 public final class InjectionTest { 69 private static final String APP_BINDING = "APP_BINDING"; 70 private static final String ACTIVITY_BINDING = "ACTIVIY_BINDING"; 71 private static final String FRAGMENT_BINDING = "FRAGMENT_BINDING"; 72 private static final String SERVICE_BINDING = "SERVICE_BINDING"; 73 74 @Retention(RUNTIME) 75 @Qualifier 76 @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) 77 @interface ApplicationLevel {} 78 79 @Retention(RUNTIME) 80 @Qualifier 81 @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) 82 @interface ActivityLevel {} 83 84 @Retention(RUNTIME) 85 @Qualifier 86 @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) 87 @interface FragmentLevel {} 88 89 @Retention(RUNTIME) 90 @Qualifier 91 @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) 92 @interface ServiceLevel {} 93 94 /** Application level bindings */ 95 @Module 96 @InstallIn(SingletonComponent.class) 97 static final class AppModule { 98 @Provides 99 @ApplicationLevel providesAppBinding()100 static String providesAppBinding() { 101 return APP_BINDING; 102 } 103 104 @Provides 105 @Singleton provideCounter()106 static AtomicLong provideCounter() { 107 return new AtomicLong(); 108 } 109 110 @Provides provideCount(AtomicLong counter)111 static Long provideCount(AtomicLong counter) { 112 return counter.incrementAndGet(); 113 } 114 } 115 116 /** Activity level bindings */ 117 @Module 118 @InstallIn(ActivityComponent.class) 119 static final class ActivityModule { 120 @Provides 121 @ActivityLevel providesActivityBinding()122 static String providesActivityBinding() { 123 return ACTIVITY_BINDING; 124 } 125 } 126 127 /** Fragment level bindings */ 128 @Module 129 @InstallIn(FragmentComponent.class) 130 static final class FragmentModule { 131 @Provides 132 @FragmentLevel providesFragmentBinding()133 static String providesFragmentBinding() { 134 return FRAGMENT_BINDING; 135 } 136 } 137 138 /** Service level bindings */ 139 @Module 140 @InstallIn(ServiceComponent.class) 141 static final class ServiceModule { 142 @Provides 143 @ServiceLevel providesServiceBinding()144 static String providesServiceBinding() { 145 return SERVICE_BINDING; 146 } 147 } 148 149 /** Hilt Activity */ 150 @AndroidEntryPoint(FragmentActivity.class) 151 public static final class TestActivity extends Hilt_InjectionTest_TestActivity { 152 @Inject @ApplicationLevel String appBinding; 153 @Inject @ActivityLevel String activityBinding; 154 boolean onCreateCalled; 155 156 @Override onCreate(Bundle onSavedInstanceState)157 public void onCreate(Bundle onSavedInstanceState) { 158 assertThat(appBinding).isNull(); 159 assertThat(activityBinding).isNull(); 160 161 super.onCreate(onSavedInstanceState); 162 163 assertThat(appBinding).isEqualTo(APP_BINDING); 164 assertThat(activityBinding).isEqualTo(ACTIVITY_BINDING); 165 166 onCreateCalled = true; 167 } 168 } 169 170 /** Non-Hilt Activity */ 171 public static final class NonHiltActivity extends FragmentActivity {} 172 173 /** Hilt Fragment */ 174 @AndroidEntryPoint(Fragment.class) 175 public static final class TestFragment extends Hilt_InjectionTest_TestFragment { 176 @Inject @ApplicationLevel String appBinding; 177 @Inject @ActivityLevel String activityBinding; 178 @Inject @FragmentLevel String fragmentBinding; 179 boolean onAttachContextCalled; 180 boolean onAttachActivityCalled; 181 182 @Override onAttach(Context context)183 public void onAttach(Context context) { 184 preInjectionAssert(); 185 super.onAttach(context); 186 postInjectionAssert(); 187 onAttachContextCalled = true; 188 } 189 190 @Override onAttach(Activity activity)191 public void onAttach(Activity activity) { 192 preInjectionAssert(); 193 super.onAttach(activity); 194 postInjectionAssert(); 195 onAttachActivityCalled = true; 196 } 197 preInjectionAssert()198 private void preInjectionAssert() { 199 assertThat(appBinding).isNull(); 200 assertThat(activityBinding).isNull(); 201 assertThat(fragmentBinding).isNull(); 202 } 203 postInjectionAssert()204 private void postInjectionAssert() { 205 assertThat(appBinding).isEqualTo(APP_BINDING); 206 assertThat(activityBinding).isEqualTo(ACTIVITY_BINDING); 207 assertThat(fragmentBinding).isEqualTo(FRAGMENT_BINDING); 208 } 209 } 210 211 /** Non-Hilt Fragment */ 212 public static final class NonHiltFragment extends Fragment {} 213 214 /** Hilt extends parameterized fragment. */ 215 @AndroidEntryPoint(ParameterizedFragment.class) 216 public static final class TestParameterizedFragment 217 extends Hilt_InjectionTest_TestParameterizedFragment<Integer> { 218 @Inject @ApplicationLevel String appBinding; 219 @Inject @ActivityLevel String activityBinding; 220 @Inject @FragmentLevel String fragmentBinding; 221 boolean onAttachContextCalled; 222 boolean onAttachActivityCalled; 223 224 @Override onAttach(Context context)225 public void onAttach(Context context) { 226 preInjectionAssert(); 227 super.onAttach(context); 228 postInjectionAssert(); 229 onAttachContextCalled = true; 230 } 231 232 @Override onAttach(Activity activity)233 public void onAttach(Activity activity) { 234 preInjectionAssert(); 235 super.onAttach(activity); 236 postInjectionAssert(); 237 onAttachActivityCalled = true; 238 } 239 preInjectionAssert()240 private void preInjectionAssert() { 241 assertThat(appBinding).isNull(); 242 assertThat(activityBinding).isNull(); 243 assertThat(fragmentBinding).isNull(); 244 } 245 postInjectionAssert()246 private void postInjectionAssert() { 247 assertThat(appBinding).isEqualTo(APP_BINDING); 248 assertThat(activityBinding).isEqualTo(ACTIVITY_BINDING); 249 assertThat(fragmentBinding).isEqualTo(FRAGMENT_BINDING); 250 } 251 } 252 253 /** Non-Hilt parameterized fragment */ 254 public static class ParameterizedFragment<T> extends Fragment {} 255 256 /** Hilt View */ 257 @AndroidEntryPoint(LinearLayout.class) 258 public static final class TestView extends Hilt_InjectionTest_TestView { 259 @Inject @ApplicationLevel String appBinding; 260 @Inject @ActivityLevel String activityBinding; 261 TestView(Context context)262 TestView(Context context) { 263 super(context); 264 } 265 TestView(Context context, AttributeSet attrs)266 TestView(Context context, AttributeSet attrs) { 267 super(context, attrs); 268 } 269 TestView(Context context, AttributeSet attrs, int defStyleAttr)270 TestView(Context context, AttributeSet attrs, int defStyleAttr) { 271 super(context, attrs, defStyleAttr); 272 } 273 274 @TargetApi(21) TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)275 TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 276 super(context, attrs, defStyleAttr, defStyleRes); 277 } 278 } 279 280 /** Hilt View (With Fragment bindings) */ 281 @WithFragmentBindings 282 @AndroidEntryPoint(LinearLayout.class) 283 public static final class TestViewWithFragmentBindings 284 extends Hilt_InjectionTest_TestViewWithFragmentBindings { 285 @Inject @ApplicationLevel String appBinding; 286 @Inject @ActivityLevel String activityBinding; 287 @Inject @FragmentLevel String fragmentBinding; 288 TestViewWithFragmentBindings(Context context)289 TestViewWithFragmentBindings(Context context) { 290 super(context); 291 } 292 } 293 294 @AndroidEntryPoint(Service.class) 295 public static final class TestService extends Hilt_InjectionTest_TestService { 296 @Inject @ApplicationLevel String appBinding; 297 @Inject @ServiceLevel String serviceBinding; 298 299 @Override onBind(Intent intent)300 public IBinder onBind(Intent intent) { 301 return null; 302 } 303 } 304 305 @AndroidEntryPoint(IntentService.class) 306 public static final class TestIntentService extends Hilt_InjectionTest_TestIntentService { 307 private static final String NAME = "TestIntentServiceName"; 308 @Inject @ApplicationLevel String appBinding; 309 @Inject @ServiceLevel String serviceBinding; 310 TestIntentService()311 TestIntentService() { 312 super(NAME); 313 } 314 315 @Override onHandleIntent(Intent intent)316 public void onHandleIntent(Intent intent) {} 317 } 318 319 @AndroidEntryPoint(BroadcastReceiver.class) 320 public static final class TestBroadcastReceiver extends Hilt_InjectionTest_TestBroadcastReceiver { 321 @Inject @ApplicationLevel String appBinding; 322 Intent lastIntent = null; 323 324 @Override onReceive(Context context, Intent intent)325 public void onReceive(Context context, Intent intent) { 326 super.onReceive(context, intent); 327 lastIntent = intent; 328 } 329 } 330 331 @AndroidEntryPoint(BaseBroadcastReceiver.class) 332 public static final class TestBroadcastReceiverWithBaseImplementingOnReceive 333 extends Hilt_InjectionTest_TestBroadcastReceiverWithBaseImplementingOnReceive { 334 @Inject @ApplicationLevel String appBinding; 335 Intent baseLastIntent = null; 336 337 @Override onReceive(Context context, Intent intent)338 public void onReceive(Context context, Intent intent) { 339 super.onReceive(context, intent); 340 baseLastIntent = intent; 341 } 342 } 343 344 abstract static class BaseBroadcastReceiver extends BroadcastReceiver { 345 Intent lastIntent = null; 346 347 @Override onReceive(Context context, Intent intent)348 public void onReceive(Context context, Intent intent) { 349 lastIntent = intent; 350 } 351 } 352 353 @Rule public final HiltAndroidRule rule = new HiltAndroidRule(this); 354 355 @Inject @ApplicationLevel String appBinding; 356 357 @Before setup()358 public void setup() { 359 rule.inject(); 360 } 361 362 @Test testAppInjection()363 public void testAppInjection() throws Exception { 364 assertThat(appBinding).isEqualTo(APP_BINDING); 365 } 366 367 @Test testActivityInjection()368 public void testActivityInjection() throws Exception { 369 ActivityController<TestActivity> controller = Robolectric.buildActivity(TestActivity.class); 370 371 assertThat(controller.get().onCreateCalled).isFalse(); 372 controller.create(); 373 assertThat(controller.get().onCreateCalled).isTrue(); 374 } 375 376 @Test testFragmentInjection()377 public void testFragmentInjection() throws Exception { 378 TestFragment fragment = new TestFragment(); 379 assertThat(fragment.onAttachContextCalled).isFalse(); 380 assertThat(fragment.onAttachActivityCalled).isFalse(); 381 setupFragment(TestActivity.class, fragment); 382 assertThat(fragment.onAttachContextCalled).isTrue(); 383 assertThat(fragment.onAttachActivityCalled).isTrue(); 384 } 385 386 @Test testParameterizedFragmentInjection()387 public void testParameterizedFragmentInjection() throws Exception { 388 TestParameterizedFragment fragment = new TestParameterizedFragment(); 389 assertThat(fragment.onAttachContextCalled).isFalse(); 390 assertThat(fragment.onAttachActivityCalled).isFalse(); 391 setupFragment(TestActivity.class, fragment); 392 assertThat(fragment.onAttachContextCalled).isTrue(); 393 assertThat(fragment.onAttachActivityCalled).isTrue(); 394 } 395 396 @Test testViewNoFragmentBindingsWithActivity()397 public void testViewNoFragmentBindingsWithActivity() throws Exception { 398 TestActivity activity = Robolectric.setupActivity(TestActivity.class); 399 TestView view = new TestView(activity); 400 assertThat(view.appBinding).isEqualTo(APP_BINDING); 401 assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING); 402 } 403 404 @Test testViewNoFragmentBindingsWithFragment()405 public void testViewNoFragmentBindingsWithFragment() throws Exception { 406 TestFragment fragment = setupFragment(TestActivity.class, new TestFragment()); 407 TestView view = new TestView(fragment.getContext()); 408 assertThat(view.appBinding).isEqualTo(APP_BINDING); 409 assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING); 410 } 411 412 @Test testViewNoFragmentBindingsWithFragment_secondConstructor()413 public void testViewNoFragmentBindingsWithFragment_secondConstructor() throws Exception { 414 TestFragment fragment = setupFragment(TestActivity.class, new TestFragment()); 415 TestView view = new TestView(fragment.getContext(), /* attrs= */ null); 416 assertThat(view.appBinding).isEqualTo(APP_BINDING); 417 assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING); 418 } 419 420 @Test testViewNoFragmentBindingsWithFragment_thirdConstructor()421 public void testViewNoFragmentBindingsWithFragment_thirdConstructor() throws Exception { 422 TestFragment fragment = setupFragment(TestActivity.class, new TestFragment()); 423 TestView view = new TestView(fragment.getContext(), /* attrs= */ null, /* defStyleAttr= */ 0); 424 assertThat(view.appBinding).isEqualTo(APP_BINDING); 425 assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING); 426 } 427 428 @Test 429 @Config(sdk = 21) testViewNoFragmentBindingsWithFragment_fourthConstructor_presentOnTwentyOne()430 public void testViewNoFragmentBindingsWithFragment_fourthConstructor_presentOnTwentyOne() 431 throws Exception { 432 TestFragment fragment = setupFragment(TestActivity.class, new TestFragment()); 433 TestView view = 434 new TestView( 435 fragment.getContext(), /* attrs= */ null, /* defStyleAttr= */ 0, /* defStyleRes= */ 0); 436 assertThat(view.appBinding).isEqualTo(APP_BINDING); 437 assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING); 438 } 439 440 @Test testServiceInjection()441 public void testServiceInjection() throws Exception { 442 TestService testService = Robolectric.setupService(TestService.class); 443 assertThat(testService.appBinding).isEqualTo(APP_BINDING); 444 assertThat(testService.serviceBinding).isEqualTo(SERVICE_BINDING); 445 } 446 447 @Test testIntentServiceInjection()448 public void testIntentServiceInjection() throws Exception { 449 TestIntentService testIntentService = Robolectric.setupService(TestIntentService.class); 450 assertThat(testIntentService.appBinding).isEqualTo(APP_BINDING); 451 assertThat(testIntentService.serviceBinding).isEqualTo(SERVICE_BINDING); 452 } 453 454 @Test testBroadcastReceiverInjection()455 public void testBroadcastReceiverInjection() throws Exception { 456 TestBroadcastReceiver testBroadcastReceiver = new TestBroadcastReceiver(); 457 Intent intent = new Intent(); 458 testBroadcastReceiver.onReceive(getApplicationContext(), intent); 459 assertThat(testBroadcastReceiver.appBinding).isEqualTo(APP_BINDING); 460 assertThat(testBroadcastReceiver.lastIntent).isSameInstanceAs(intent); 461 } 462 463 @Test testBroadcastReceiverWithBaseImplementingOnReceiveInjection()464 public void testBroadcastReceiverWithBaseImplementingOnReceiveInjection() throws Exception { 465 TestBroadcastReceiverWithBaseImplementingOnReceive testBroadcastReceiver = 466 new TestBroadcastReceiverWithBaseImplementingOnReceive(); 467 Intent intent = new Intent(); 468 testBroadcastReceiver.onReceive(getApplicationContext(), intent); 469 assertThat(testBroadcastReceiver.appBinding).isEqualTo(APP_BINDING); 470 assertThat(testBroadcastReceiver.lastIntent).isSameInstanceAs(intent); 471 assertThat(testBroadcastReceiver.baseLastIntent).isSameInstanceAs(intent); 472 } 473 474 @Test testViewWithFragmentBindingsWithFragment()475 public void testViewWithFragmentBindingsWithFragment() throws Exception { 476 TestFragment fragment = setupFragment(TestActivity.class, new TestFragment()); 477 478 Context fragmentContext = fragment.getContext(); 479 TestViewWithFragmentBindings view = new TestViewWithFragmentBindings(fragmentContext); 480 assertThat(view.appBinding).isEqualTo(APP_BINDING); 481 assertThat(view.activityBinding).isEqualTo(ACTIVITY_BINDING); 482 assertThat(view.fragmentBinding).isEqualTo(FRAGMENT_BINDING); 483 } 484 485 @Test testViewWithFragmentBindingsFailsWithActivity()486 public void testViewWithFragmentBindingsFailsWithActivity() throws Exception { 487 TestActivity activity = Robolectric.setupActivity(TestActivity.class); 488 try { 489 new TestViewWithFragmentBindings(activity); 490 fail("Expected test to fail but it passes!"); 491 } catch (IllegalStateException e) { 492 assertThat(e) 493 .hasMessageThat() 494 .contains( 495 "@WithFragmentBindings Hilt view must be attached to an @AndroidEntryPoint Fragment"); 496 } 497 } 498 499 @Test testFragmentAttachedToNonHiltActivityFails()500 public void testFragmentAttachedToNonHiltActivityFails() throws Exception { 501 NonHiltActivity activity = Robolectric.setupActivity(NonHiltActivity.class); 502 try { 503 activity 504 .getSupportFragmentManager() 505 .beginTransaction() 506 .add(new TestFragment(), null) 507 .commitNow(); 508 fail("Expected test to fail but it passes!"); 509 } catch (IllegalStateException e) { 510 assertThat(e) 511 .hasMessageThat() 512 .contains("Hilt Fragments must be attached to an @AndroidEntryPoint Activity"); 513 } 514 } 515 516 @Test testViewAttachedToNonHiltActivityFails()517 public void testViewAttachedToNonHiltActivityFails() throws Exception { 518 NonHiltActivity activity = Robolectric.setupActivity(NonHiltActivity.class); 519 try { 520 new TestView(activity); 521 fail("Expected test to fail but it passes!"); 522 } catch (IllegalStateException e) { 523 assertThat(e) 524 .hasMessageThat() 525 .contains("Hilt view must be attached to an @AndroidEntryPoint Fragment or Activity"); 526 } 527 } 528 529 @Test testViewAttachedToNonHiltFragmentFails()530 public void testViewAttachedToNonHiltFragmentFails() throws Exception { 531 NonHiltActivity activity = Robolectric.setupActivity(NonHiltActivity.class); 532 NonHiltFragment fragment = new NonHiltFragment(); 533 activity.getSupportFragmentManager().beginTransaction().add(fragment, null).commitNow(); 534 Context nonHiltContext = fragment.getContext(); 535 try { 536 new TestView(nonHiltContext); 537 fail("Expected test to fail but it passes!"); 538 } catch (IllegalStateException e) { 539 assertThat(e) 540 .hasMessageThat() 541 .contains("Hilt view must be attached to an @AndroidEntryPoint Fragment or Activity"); 542 } 543 } 544 545 @Test testViewAttachedToApplicationContextFails()546 public void testViewAttachedToApplicationContextFails() throws Exception { 547 try { 548 new TestView(getApplicationContext()); 549 fail("Expected test to fail but it passes!"); 550 } catch (IllegalStateException e) { 551 assertThat(e) 552 .hasMessageThat() 553 .contains( 554 "Hilt view cannot be created using the application context. " 555 + "Use a Hilt Fragment or Activity context"); 556 } 557 } 558 559 /** Hilt Activity that manually calls inject(). */ 560 @AndroidEntryPoint(FragmentActivity.class) 561 public static final class DoubleInjectActivity extends Hilt_InjectionTest_DoubleInjectActivity { 562 @Inject Long counter; 563 564 @Override onCreate(Bundle onSavedInstanceState)565 public void onCreate(Bundle onSavedInstanceState) { 566 inject(); 567 super.onCreate(onSavedInstanceState); 568 } 569 } 570 571 @Test testActivityDoesNotInjectTwice()572 public void testActivityDoesNotInjectTwice() throws Exception { 573 ActivityController<DoubleInjectActivity> controller = 574 Robolectric.buildActivity(DoubleInjectActivity.class); 575 controller.create(); 576 assertThat(controller.get().counter).isEqualTo(1L); 577 } 578 579 /** Hilt Fragment that manually calls inject(). */ 580 @AndroidEntryPoint(Fragment.class) 581 public static final class DoubleInjectFragment extends Hilt_InjectionTest_DoubleInjectFragment { 582 @Inject Long counter; 583 584 @Override onAttach(Context context)585 public void onAttach(Context context) { 586 inject(); 587 super.onAttach(context); 588 } 589 590 @Override onAttach(Activity activity)591 public void onAttach(Activity activity) { 592 inject(); 593 super.onAttach(activity); 594 } 595 } 596 597 @Test testFragmentDoesNotInjectTwice()598 public void testFragmentDoesNotInjectTwice() throws Exception { 599 DoubleInjectFragment fragment = setupFragment(TestActivity.class, new DoubleInjectFragment()); 600 assertThat(fragment.counter).isEqualTo(1L); 601 } 602 603 /** Hilt View that manually calls inject(). */ 604 @AndroidEntryPoint(LinearLayout.class) 605 public static final class DoubleInjectView extends Hilt_InjectionTest_DoubleInjectView { 606 @Inject Long counter; 607 DoubleInjectView(Context context)608 DoubleInjectView(Context context) { 609 super(context); 610 inject(); 611 } 612 DoubleInjectView(Context context, AttributeSet attrs)613 DoubleInjectView(Context context, AttributeSet attrs) { 614 super(context, attrs); 615 inject(); 616 } 617 DoubleInjectView(Context context, AttributeSet attrs, int defStyleAttr)618 DoubleInjectView(Context context, AttributeSet attrs, int defStyleAttr) { 619 super(context, attrs, defStyleAttr); 620 inject(); 621 } 622 623 @TargetApi(21) DoubleInjectView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)624 DoubleInjectView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 625 super(context, attrs, defStyleAttr, defStyleRes); 626 inject(); 627 } 628 } 629 630 @Test testViewDoesNotInjectTwice()631 public void testViewDoesNotInjectTwice() throws Exception { 632 TestActivity activity = Robolectric.setupActivity(TestActivity.class); 633 DoubleInjectView view = new DoubleInjectView(activity); 634 assertThat(view.counter).isEqualTo(1L); 635 } 636 637 /** Hilt Service that manually calls inject(). */ 638 @AndroidEntryPoint(Service.class) 639 public static final class DoubleInjectService extends Hilt_InjectionTest_DoubleInjectService { 640 @Inject Long counter; 641 onCreate()642 @Override public void onCreate() { 643 inject(); 644 super.onCreate(); 645 } 646 647 @Override onBind(Intent intent)648 public IBinder onBind(Intent intent) { 649 return null; 650 } 651 } 652 653 @Test testServiceDoesNotInjectTwice()654 public void testServiceDoesNotInjectTwice() throws Exception { 655 DoubleInjectService testService = Robolectric.setupService(DoubleInjectService.class); 656 assertThat(testService.counter).isEqualTo(1L); 657 } 658 659 /** Hilt BroadcastReceiver that manually calls inject(). */ 660 @AndroidEntryPoint(BroadcastReceiver.class) 661 public static final class DoubleInjectBroadcastReceiver 662 extends Hilt_InjectionTest_DoubleInjectBroadcastReceiver { 663 @Inject Long counter; 664 665 @Override onReceive(Context context, Intent intent)666 public void onReceive(Context context, Intent intent) { 667 inject(context); 668 super.onReceive(context, intent); 669 } 670 } 671 672 @Test testBroadcastReceiverDoesNotInjectTwice()673 public void testBroadcastReceiverDoesNotInjectTwice() throws Exception { 674 DoubleInjectBroadcastReceiver testBroadcastReceiver = new DoubleInjectBroadcastReceiver(); 675 Intent intent = new Intent(); 676 testBroadcastReceiver.onReceive(getApplicationContext(), intent); 677 assertThat(testBroadcastReceiver.counter).isEqualTo(1L); 678 } 679 setupFragment( Class<? extends FragmentActivity> activityClass, T fragment)680 private static <T extends Fragment> T setupFragment( 681 Class<? extends FragmentActivity> activityClass, T fragment) { 682 FragmentActivity activity = Robolectric.setupActivity(activityClass); 683 attachFragment(activity, fragment); 684 return fragment; 685 } 686 attachFragment(FragmentActivity activity, Fragment fragment)687 private static void attachFragment(FragmentActivity activity, Fragment fragment) { 688 activity.getSupportFragmentManager().beginTransaction().add(fragment, "").commitNow(); 689 } 690 } 691