• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.android.testing.UninstallModules;
37 import dagger.hilt.components.SingletonComponent;
38 import javax.inject.Inject;
39 import javax.inject.Named;
40 import org.junit.Rule;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.robolectric.Robolectric;
44 import org.robolectric.android.controller.ActivityController;
45 import org.robolectric.annotation.Config;
46 
47 // TODO(bcorso): Support transitively ignoring the @Module.includes of ignored modules?
48 // TODO(bcorso): Support including non-test @UninstallModules using @UninstallModules.includes?
49 @UninstallModules({
50   MultiTestRootExternalModules.PkgPrivateAppModule.class,
51   MultiTestRootExternalModules.PkgPrivateActivityModule.class
52 })
53 @HiltAndroidTest
54 @RunWith(AndroidJUnit4.class)
55 // Robolectric requires Java9 to run API 29 and above, so use API 28 instead
56 @Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
57 public final class MultiTestRoot1Test {
58   private static final int INT_VALUE = 9;
59   private static final String STR_VALUE = "MultiTestRoot1TestValue";
60   private static final long LONG_VALUE = 11L;
61   private static final String REPLACE_EXTERNAL_STR_VALUE = "REPLACED_EXTERNAL_STR_VALUE";
62   private static final long REPLACE_EXTERNAL_LONG_VALUE = 17L;
63   private static final String BIND_VALUE_STRING = "BIND_VALUE_STRING";
64   private static final String TEST_QUALIFIER = "TEST_QUALIFIER";
65 
66   @AndroidEntryPoint(ComponentActivity.class)
67   public static class TestActivity extends Hilt_MultiTestRoot1Test_TestActivity {
68     @Inject Baz baz;
69     @Inject @MultiTestRootExternalModules.External Long externalLongValue;
70   }
71 
72   @EntryPoint
73   @InstallIn(SingletonComponent.class)
74   public interface BindValueEntryPoint {
75     @Named(TEST_QUALIFIER)
bindValueString()76     String bindValueString();
77   }
78 
79   @Module
80   @InstallIn(SingletonComponent.class)
81   public interface ReplaceExternalAppModule {
82     @Provides
83     @MultiTestRootExternalModules.External
provideString()84     static String provideString() {
85       return REPLACE_EXTERNAL_STR_VALUE;
86     }
87   }
88 
89   @Module
90   @InstallIn(ActivityComponent.class)
91   public interface ReplaceExternalActivityModule {
92     @Provides
93     @MultiTestRootExternalModules.External
provideString()94     static Long provideString() {
95       return REPLACE_EXTERNAL_LONG_VALUE;
96     }
97   }
98 
99   @Module
100   @InstallIn(ActivityComponent.class)
101   public interface TestActivityModule {
102     @Provides
provideBaz()103     static Baz provideBaz() {
104       return new Baz(LONG_VALUE);
105     }
106   }
107 
108   @Module
109   @InstallIn(SingletonComponent.class)
110   interface PkgPrivateTestModule {
111     @Provides
provideQux()112     static Qux provideQux() {
113       return new Qux();
114     }
115   }
116 
117   @Module
118   @InstallIn(SingletonComponent.class)
119   public interface TestModule {
120     @Provides
provideInt()121     static int provideInt() {
122       return INT_VALUE;
123     }
124 
125     @Provides
provideString()126     static String provideString() {
127       return STR_VALUE;
128     }
129   }
130 
131   public static final class Outer {
132     @Module
133     @InstallIn(SingletonComponent.class)
134     public interface NestedTestModule {
135       @Provides
provideLong()136       static long provideLong() {
137         return LONG_VALUE;
138       }
139     }
140 
Outer()141     private Outer() {}
142   }
143 
144   static class Foo {
145     final int value;
146 
147     @Inject
Foo(int value)148     Foo(int value) {
149       this.value = value;
150     }
151   }
152 
153   static class Bar {
154     final String value;
155 
Bar(String value)156     Bar(String value) {
157       this.value = value;
158     }
159   }
160 
161   static class Baz {
162     final long value;
163 
Baz(long value)164     Baz(long value) {
165       this.value = value;
166     }
167   }
168 
169   static class Qux {}
170 
171   @Module
172   @InstallIn(SingletonComponent.class)
173   public interface BarModule {
174     @Provides
provideBar(String value)175     static Bar provideBar(String value) {
176       return new Bar(value);
177     }
178   }
179 
180   @EntryPoint
181   @InstallIn(SingletonComponent.class)
182   public interface BarEntryPoint {
getBar()183     Bar getBar();
184   }
185 
186   @EntryPoint
187   @InstallIn(SingletonComponent.class)
188   interface PkgPrivateQuxEntryPoint {
getQux()189     Qux getQux();
190   }
191 
192   @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
193 
194   @Inject Foo foo;
195   @Inject Qux qux;
196   @Inject Long longValue;
197   @Inject @MultiTestRootExternalModules.External String externalStrValue;
198 
199   @BindValue
200   @Named(TEST_QUALIFIER)
201   String bindValueString = BIND_VALUE_STRING;
202 
203   @Test
testInjectFromTestModule()204   public void testInjectFromTestModule() throws Exception {
205     assertThat(foo).isNull();
206     setupComponent();
207     assertThat(foo).isNotNull();
208     assertThat(foo.value).isEqualTo(INT_VALUE);
209   }
210 
211   @Test
testInjectFromNestedTestModule()212   public void testInjectFromNestedTestModule() throws Exception {
213     assertThat(longValue).isNull();
214     setupComponent();
215     assertThat(longValue).isNotNull();
216     assertThat(longValue).isEqualTo(LONG_VALUE);
217   }
218 
219   @Test
testInjectFromExternalAppModule()220   public void testInjectFromExternalAppModule() throws Exception {
221     assertThat(externalStrValue).isNull();
222     setupComponent();
223     assertThat(externalStrValue).isNotNull();
224     assertThat(externalStrValue).isEqualTo(REPLACE_EXTERNAL_STR_VALUE);
225     assertThat(externalStrValue).isNotEqualTo(MultiTestRootExternalModules.EXTERNAL_STR_VALUE);
226   }
227 
228   @Test
testInjectFromExternalActivityModule()229   public void testInjectFromExternalActivityModule() throws Exception {
230     setupComponent();
231     ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class);
232     assertThat(ac.get().externalLongValue).isNull();
233     ac.create();
234     assertThat(ac.get().externalLongValue).isNotNull();
235     assertThat(ac.get().externalLongValue).isEqualTo(REPLACE_EXTERNAL_LONG_VALUE);
236     assertThat(ac.get().externalLongValue)
237         .isNotEqualTo(MultiTestRootExternalModules.EXTERNAL_LONG_VALUE);
238   }
239 
240   @Test
testInjectFromPkgPrivateTestModule()241   public void testInjectFromPkgPrivateTestModule() throws Exception {
242     assertThat(qux).isNull();
243     setupComponent();
244     assertThat(qux).isNotNull();
245   }
246 
247   @Test
testLocalEntryPoint()248   public void testLocalEntryPoint() throws Exception {
249     setupComponent();
250     Bar bar = EntryPoints.get(getApplicationContext(), BarEntryPoint.class).getBar();
251     assertThat(bar).isNotNull();
252     assertThat(bar.value).isEqualTo(STR_VALUE);
253   }
254 
255   @Test
testLocalPkgPrivateEntryPoint()256   public void testLocalPkgPrivateEntryPoint() throws Exception {
257     setupComponent();
258     Qux qux = EntryPoints.get(getApplicationContext(), PkgPrivateQuxEntryPoint.class).getQux();
259     assertThat(qux).isNotNull();
260   }
261 
262   @Test
testAndroidEntryPoint()263   public void testAndroidEntryPoint() throws Exception {
264     setupComponent();
265     ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class);
266     assertThat(ac.get().baz).isNull();
267     ac.create();
268     assertThat(ac.get().baz).isNotNull();
269     assertThat(ac.get().baz.value).isEqualTo(LONG_VALUE);
270   }
271 
272   @Test
testMissingMultiTestRoot2EntryPoint()273   public void testMissingMultiTestRoot2EntryPoint() throws Exception {
274     setupComponent();
275     ClassCastException exception =
276         assertThrows(
277             ClassCastException.class,
278             () -> EntryPoints.get(getApplicationContext(), MultiTestRoot2Test.BarEntryPoint.class));
279     assertThat(exception)
280           .hasMessageThat()
281           .isEqualTo(
282               "Cannot cast dagger.hilt.android.DaggerMultiTestRoot1Test_HiltComponents_SingletonC"
283               + " to dagger.hilt.android.MultiTestRoot2Test$BarEntryPoint");
284   }
285 
286   @Test
testBindValueFieldIsProvided()287   public void testBindValueFieldIsProvided() throws Exception {
288     setupComponent();
289     assertThat(bindValueString).isEqualTo(BIND_VALUE_STRING);
290     assertThat(getBinding()).isEqualTo(BIND_VALUE_STRING);
291   }
292 
293   @Test
testBindValueIsMutable()294   public void testBindValueIsMutable() throws Exception {
295     setupComponent();
296     bindValueString = "newValue";
297     assertThat(getBinding()).isEqualTo("newValue");
298   }
299 
setupComponent()300   void setupComponent() {
301     rule.inject();
302   }
303 
getBinding()304   private static String getBinding() {
305     return EntryPoints.get(getApplicationContext(), BindValueEntryPoint.class).bindValueString();
306   }
307 }
308