1 /* 2 * Copyright (C) 2016 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.android; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.fail; 21 import static org.robolectric.annotation.LooperMode.Mode.LEGACY; 22 23 import android.app.Activity; 24 import android.app.Application; 25 import android.app.Fragment; 26 import org.junit.Test; 27 import org.junit.runner.RunWith; 28 import org.robolectric.Robolectric; 29 import org.robolectric.RobolectricTestRunner; 30 import org.robolectric.annotation.Config; 31 import org.robolectric.annotation.LooperMode; 32 import org.robolectric.util.FragmentTestUtil; 33 34 @LooperMode(LEGACY) 35 @RunWith(RobolectricTestRunner.class) 36 public final class AndroidInjectionTest { 37 38 // Most positive tests are performed in javatests/dagger/android/support/functional, but 39 // Robolectric's support for framework fragments is lacking, so we supplement those tests here: 40 public static class InjectableFragment extends Fragment { 41 String tag; 42 } 43 fakeFragmentInjector(String tag)44 private static AndroidInjector<Object> fakeFragmentInjector(String tag) { 45 return instance -> { 46 if (instance instanceof InjectableFragment) { 47 ((InjectableFragment) instance).tag = tag; 48 } 49 }; 50 } 51 52 public static class ApplicationInjectsFragment extends Application implements HasAndroidInjector { 53 @Override 54 public AndroidInjector<Object> androidInjector() { 55 return fakeFragmentInjector("injected by app"); 56 } 57 } 58 59 @Config(application = ApplicationInjectsFragment.class) 60 @Test 61 public void fragmentInjectedByApplication() { 62 Activity activity = Robolectric.setupActivity(Activity.class); 63 InjectableFragment fragment = new InjectableFragment(); 64 activity.getFragmentManager().beginTransaction().add(fragment, "tag").commit(); 65 66 AndroidInjection.inject(fragment); 67 68 assertThat(fragment.tag).isEqualTo("injected by app"); 69 } 70 71 public static class ActivityInjectsFragment extends Activity implements HasAndroidInjector { 72 @Override 73 public AndroidInjector<Object> androidInjector() { 74 return fakeFragmentInjector("injected by activity"); 75 } 76 } 77 78 @Config(application = ApplicationInjectsFragment.class) 79 @Test 80 public void fragmentInjectedByActivity() { 81 ActivityInjectsFragment activity = Robolectric.setupActivity(ActivityInjectsFragment.class); 82 InjectableFragment fragment = new InjectableFragment(); 83 activity.getFragmentManager().beginTransaction().add(fragment, "tag").commit(); 84 85 AndroidInjection.inject(fragment); 86 87 assertThat(fragment.tag).isEqualTo("injected by activity"); 88 } 89 90 public static class ParentFragmentInjectsChildFragment extends Fragment 91 implements HasAndroidInjector { 92 @Override 93 public AndroidInjector<Object> androidInjector() { 94 return fakeFragmentInjector("injected by parent fragment"); 95 } 96 } 97 98 @Config(application = ApplicationInjectsFragment.class) 99 @Test 100 public void fragmentInjectedByParentFragment() { 101 ActivityInjectsFragment activity = Robolectric.setupActivity(ActivityInjectsFragment.class); 102 ParentFragmentInjectsChildFragment parentFragment = new ParentFragmentInjectsChildFragment(); 103 InjectableFragment childFragment = new InjectableFragment(); 104 105 activity.getFragmentManager().beginTransaction().add(parentFragment, "tag").commit(); 106 parentFragment 107 .getChildFragmentManager() 108 .beginTransaction() 109 .add(childFragment, "child-tag") 110 .commit(); 111 AndroidInjection.inject(childFragment); 112 113 assertThat(childFragment.tag).isEqualTo("injected by parent fragment"); 114 } 115 116 @Test 117 public void injectActivity_applicationDoesntImplementHasAndroidInjector() { 118 Activity activity = Robolectric.setupActivity(Activity.class); 119 120 try { 121 AndroidInjection.inject(activity); 122 fail(); 123 } catch (Exception e) { 124 assertThat(e) 125 .hasMessageThat() 126 .contains("Application does not implement dagger.android.HasAndroidInjector"); 127 } 128 } 129 130 @Test 131 public void injectFragment_hasFragmentInjectorNotFound() { 132 Fragment fragment = new Fragment(); 133 FragmentTestUtil.startFragment(fragment); 134 135 try { 136 AndroidInjection.inject(fragment); 137 fail(); 138 } catch (Exception e) { 139 assertThat(e).hasMessageThat().contains("No injector was found"); 140 } 141 } 142 143 private static class ApplicationReturnsNull extends Application implements HasAndroidInjector { 144 @Override 145 public AndroidInjector<Object> androidInjector() { 146 return null; 147 } 148 } 149 150 @Test 151 @Config(application = ApplicationReturnsNull.class) 152 public void activityInjector_returnsNull() { 153 Activity activity = Robolectric.setupActivity(Activity.class); 154 155 try { 156 AndroidInjection.inject(activity); 157 fail(); 158 } catch (Exception e) { 159 assertThat(e).hasMessageThat().contains("androidInjector() returned null"); 160 } 161 } 162 163 @Test 164 @Config(application = ApplicationReturnsNull.class) 165 public void fragmentInjector_returnsNull() { 166 Fragment fragment = new Fragment(); 167 FragmentTestUtil.startFragment(fragment); 168 169 try { 170 AndroidInjection.inject(fragment); 171 fail(); 172 } catch (Exception e) { 173 assertThat(e).hasMessageThat().contains("androidInjector() returned null"); 174 } 175 } 176 177 @Test 178 public void injectActivity_nullInput() { 179 try { 180 AndroidInjection.inject((Activity) null); 181 fail(); 182 } catch (NullPointerException e) { 183 assertThat(e).hasMessageThat().contains("activity"); 184 } 185 } 186 187 @Test 188 public void injectFragment_nullInput() { 189 try { 190 AndroidInjection.inject((Fragment) null); 191 fail(); 192 } catch (NullPointerException e) { 193 assertThat(e).hasMessageThat().contains("fragment"); 194 } 195 } 196 } 197