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