• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric;
2 
3 import static com.google.common.collect.ImmutableMap.of;
4 import static com.google.common.truth.Truth.assertThat;
5 import static java.nio.charset.StandardCharsets.UTF_8;
6 import static org.robolectric.annotation.Config.DEFAULT_APPLICATION;
7 
8 import android.app.Application;
9 import java.io.ByteArrayInputStream;
10 import java.io.InputStream;
11 import java.lang.reflect.Method;
12 import java.util.HashMap;
13 import java.util.Map;
14 import org.junit.Ignore;
15 import org.junit.Test;
16 import org.junit.runner.RunWith;
17 import org.junit.runners.JUnit4;
18 import org.junit.runners.model.InitializationError;
19 import org.robolectric.annotation.Config;
20 import org.robolectric.shadows.ShadowView;
21 import org.robolectric.shadows.ShadowViewGroup;
22 import org.robolectric.shadows.testing.TestApplication;
23 
24 @RunWith(JUnit4.class)
25 public class ConfigMergerTest {
26 
defaultValuesAreMerged()27   @Test public void defaultValuesAreMerged() throws Exception {
28     assertThat(configFor(Test2.class, "withoutAnnotation",
29         new Config.Builder().build()).manifest())
30         .isEqualTo("AndroidManifest.xml");
31   }
32 
globalValuesAreMerged()33   @Test public void globalValuesAreMerged() throws Exception {
34     assertThat(configFor(Test2.class, "withoutAnnotation",
35         new Config.Builder().setManifest("ManifestFromGlobal.xml").build()).manifest())
36         .isEqualTo("ManifestFromGlobal.xml");
37   }
38 
39   @Test
whenClassHasConfigAnnotation_getConfig_shouldMergeClassAndMethodConfig()40   public void whenClassHasConfigAnnotation_getConfig_shouldMergeClassAndMethodConfig() throws Exception {
41     assertConfig(
42         configFor(Test1.class, "withoutAnnotation"),
43         new int[] {1},
44         "foo",
45         TestFakeApp.class,
46         "com.example.test",
47         "from-test",
48         "test/res",
49         "test/assets",
50         new Class[] {Test1.class},
51         new String[] {"com.example.test1"},
52         new String[] {"libs/test"});
53 
54     assertConfig(
55         configFor(Test1.class, "withDefaultsAnnotation"),
56         new int[] {1},
57         "foo",
58         TestFakeApp.class,
59         "com.example.test",
60         "from-test",
61         "test/res",
62         "test/assets",
63         new Class[] {Test1.class},
64         new String[] {"com.example.test1"},
65         new String[] {"libs/test"});
66 
67     assertConfig(
68         configFor(Test1.class, "withOverrideAnnotation"),
69         new int[] {9},
70         "furf",
71         TestApplication.class,
72         "com.example.method",
73         "from-method",
74         "method/res",
75         "method/assets",
76         new Class[] {Test1.class, Test2.class},
77         new String[] {"com.example.test1", "com.example.method1"},
78         new String[] {"libs/method", "libs/test"});
79   }
80 
81   @Test
whenClassDoesntHaveConfigAnnotation_getConfig_shouldUseMethodConfig()82   public void whenClassDoesntHaveConfigAnnotation_getConfig_shouldUseMethodConfig() throws Exception {
83     assertConfig(
84         configFor(Test2.class, "withoutAnnotation"),
85         new int[0],
86         "AndroidManifest.xml",
87         DEFAULT_APPLICATION,
88         "",
89         "",
90         "res",
91         "assets",
92         new Class[] {},
93         new String[] {},
94         new String[] {});
95 
96     assertConfig(
97         configFor(Test2.class, "withDefaultsAnnotation"),
98         new int[0],
99         "AndroidManifest.xml",
100         DEFAULT_APPLICATION,
101         "",
102         "",
103         "res",
104         "assets",
105         new Class[] {},
106         new String[] {},
107         new String[] {});
108 
109     assertConfig(
110         configFor(Test2.class, "withOverrideAnnotation"),
111         new int[] {9},
112         "furf",
113         TestFakeApp.class,
114         "com.example.method",
115         "from-method",
116         "method/res",
117         "method/assets",
118         new Class[] {Test1.class},
119         new String[] {"com.example.method2"},
120         new String[] {"libs/method"});
121   }
122 
123   @Test
whenClassDoesntHaveConfigAnnotation_getConfig_shouldMergeParentClassAndMethodConfig()124   public void whenClassDoesntHaveConfigAnnotation_getConfig_shouldMergeParentClassAndMethodConfig() throws Exception {
125     assertConfig(
126         configFor(Test5.class, "withoutAnnotation"),
127         new int[] {1},
128         "foo",
129         TestFakeApp.class,
130         "com.example.test",
131         "from-test",
132         "test/res",
133         "test/assets",
134         new Class[] {Test1.class, Test1.class},
135         new String[] {"com.example.test1"},
136         new String[] {"libs/test"});
137 
138     assertConfig(
139         configFor(Test5.class, "withDefaultsAnnotation"),
140         new int[] {1},
141         "foo",
142         TestFakeApp.class,
143         "com.example.test",
144         "from-test",
145         "test/res",
146         "test/assets",
147         new Class[] {Test1.class, Test1.class},
148         new String[] {"com.example.test1"},
149         new String[] {"libs/test"});
150 
151     assertConfig(
152         configFor(Test5.class, "withOverrideAnnotation"),
153         new int[] {14},
154         "foo",
155         TestFakeApp.class,
156         "com.example.test",
157         "from-method5",
158         "test/res",
159         "method5/assets",
160         new Class[] {Test1.class, Test1.class, Test5.class},
161         new String[] {"com.example.test1", "com.example.method5"},
162         new String[] {"libs/test"});
163   }
164 
165   @Test
whenClassAndParentClassHaveConfigAnnotation_getConfig_shouldMergeParentClassAndMethodConfig()166   public void whenClassAndParentClassHaveConfigAnnotation_getConfig_shouldMergeParentClassAndMethodConfig() throws Exception {
167     assertConfig(
168         configFor(Test6.class, "withoutAnnotation"),
169         new int[] {1},
170         "foo",
171         TestFakeApp.class,
172         "com.example.test",
173         "from-class6",
174         "class6/res",
175         "test/assets",
176         new Class[] {Test1.class, Test1.class, Test6.class},
177         new String[] {"com.example.test1", "com.example.test6"},
178         new String[] {"libs/test"});
179 
180     assertConfig(
181         configFor(Test6.class, "withDefaultsAnnotation"),
182         new int[] {1},
183         "foo",
184         TestFakeApp.class,
185         "com.example.test",
186         "from-class6",
187         "class6/res",
188         "test/assets",
189         new Class[] {Test1.class, Test1.class, Test6.class},
190         new String[] {"com.example.test1", "com.example.test6"},
191         new String[] {"libs/test"});
192 
193     assertConfig(
194         configFor(Test6.class, "withOverrideAnnotation"),
195         new int[] {14},
196         "foo",
197         TestFakeApp.class,
198         "com.example.test",
199         "from-method5",
200         "class6/res",
201         "method5/assets",
202         new Class[] {Test1.class, Test1.class, Test6.class, Test5.class},
203         new String[] {"com.example.test1", "com.example.method5", "com.example.test6"},
204         new String[] {"libs/test"});
205   }
206 
207   @Test
whenClassAndSubclassHaveConfigAnnotation_getConfig_shouldMergeClassSubclassAndMethodConfig()208   public void whenClassAndSubclassHaveConfigAnnotation_getConfig_shouldMergeClassSubclassAndMethodConfig() throws Exception {
209     assertConfig(
210         configFor(Test3.class, "withoutAnnotation"),
211         new int[] {1},
212         "foo",
213         TestFakeApp.class,
214         "com.example.test",
215         "from-subclass",
216         "test/res",
217         "test/assets",
218         new Class[] {Test1.class},
219         new String[] {"com.example.test1"},
220         new String[] {"libs/test"});
221 
222     assertConfig(
223         configFor(Test3.class, "withDefaultsAnnotation"),
224         new int[] {1},
225         "foo",
226         TestFakeApp.class,
227         "com.example.test",
228         "from-subclass",
229         "test/res",
230         "test/assets",
231         new Class[] {Test1.class},
232         new String[] {"com.example.test1"},
233         new String[] {"libs/test"});
234 
235     assertConfig(
236         configFor(Test3.class, "withOverrideAnnotation"),
237         new int[] {9},
238         "furf",
239         TestApplication.class,
240         "com.example.method",
241         "from-method",
242         "method/res",
243         "method/assets",
244         new Class[] {Test1.class, Test2.class},
245         new String[] {"com.example.test1", "com.example.method1"},
246         new String[] {"libs/method", "libs/test"});
247   }
248 
249   @Test
whenClassDoesntHaveConfigAnnotationButSubclassDoes_getConfig_shouldMergeSubclassAndMethodConfig()250   public void whenClassDoesntHaveConfigAnnotationButSubclassDoes_getConfig_shouldMergeSubclassAndMethodConfig() throws Exception {
251     assertConfig(
252         configFor(Test4.class, "withoutAnnotation"),
253         new int[0],
254         "AndroidManifest.xml",
255         DEFAULT_APPLICATION,
256         "",
257         "from-subclass",
258         "res",
259         "assets",
260         new Class[] {},
261         new String[] {},
262         new String[] {});
263 
264     assertConfig(
265         configFor(Test4.class, "withDefaultsAnnotation"),
266         new int[0],
267         "AndroidManifest.xml",
268         DEFAULT_APPLICATION,
269         "",
270         "from-subclass",
271         "res",
272         "assets",
273         new Class[] {},
274         new String[] {},
275         new String[] {});
276 
277     assertConfig(
278         configFor(Test4.class, "withOverrideAnnotation"),
279         new int[] {9},
280         "furf",
281         TestFakeApp.class,
282         "com.example.method",
283         "from-method",
284         "method/res",
285         "method/assets",
286         new Class[] {Test1.class},
287         new String[] {"com.example.method2"},
288         new String[] {"libs/method"});
289   }
290 
291   @Test
shouldLoadDefaultsFromGlobalPropertiesFile()292   public void shouldLoadDefaultsFromGlobalPropertiesFile() throws Exception {
293     String properties =
294         "sdk: 432\n"
295             + "manifest: --none\n"
296             + "qualifiers: from-properties-file\n"
297             + "resourceDir: from/properties/file/res\n"
298             + "assetDir: from/properties/file/assets\n"
299             + "shadows: org.robolectric.shadows.ShadowView, org.robolectric.shadows.ShadowViewGroup\n"
300             + "application: org.robolectric.TestFakeApp\n"
301             + "packageName: com.example.test\n"
302             + "instrumentedPackages: com.example.test1, com.example.test2\n"
303             + "libraries: libs/test, libs/test2";
304 
305     assertConfig(
306         configFor(Test2.class, "withoutAnnotation", of("robolectric.properties", properties)),
307         new int[] {432},
308         "--none",
309         TestFakeApp.class,
310         "com.example.test",
311         "from-properties-file",
312         "from/properties/file/res",
313         "from/properties/file/assets",
314         new Class[] {ShadowView.class, ShadowViewGroup.class},
315         new String[] {"com.example.test1", "com.example.test2"},
316         new String[] {"libs/test", "libs/test2"});
317   }
318 
319   @Test
shouldMergeConfigFromTestClassPackageProperties()320   public void shouldMergeConfigFromTestClassPackageProperties() throws Exception {
321     assertConfig(
322         configFor(
323             Test2.class,
324             "withoutAnnotation",
325             of("org/robolectric/robolectric.properties", "sdk: 432\n")),
326         new int[] {432},
327         "AndroidManifest.xml",
328         DEFAULT_APPLICATION,
329         "",
330         "",
331         "res",
332         "assets",
333         new Class[] {},
334         new String[] {},
335         new String[] {});
336   }
337 
338   @Test
shouldMergeConfigUpPackageHierarchy()339   public void shouldMergeConfigUpPackageHierarchy() throws Exception {
340     assertConfig(
341         configFor(
342             Test2.class,
343             "withoutAnnotation",
344             of(
345                 "org/robolectric/robolectric.properties",
346                     "qualifiers: from-org-robolectric\nlibraries: FromOrgRobolectric\n",
347                 "org/robolectric.properties",
348                     "sdk: 123\nqualifiers: from-org\nlibraries: FromOrg\n",
349                 "robolectric.properties",
350                     "sdk: 456\nqualifiers: from-top-level\nlibraries: FromTopLevel\n")),
351         new int[] {123},
352         "AndroidManifest.xml",
353         DEFAULT_APPLICATION,
354         "",
355         "from-org-robolectric",
356         "res",
357         "assets",
358         new Class[] {},
359         new String[] {},
360         new String[] {"FromOrgRobolectric", "FromOrg", "FromTopLevel"});
361   }
362 
363   @Test
withEmptyShadowList_shouldLoadDefaultsFromGlobalPropertiesFile()364   public void withEmptyShadowList_shouldLoadDefaultsFromGlobalPropertiesFile() throws Exception {
365     assertConfig(
366         configFor(Test2.class, "withoutAnnotation", of("robolectric.properties", "shadows:")),
367         new int[0],
368         "AndroidManifest.xml",
369         DEFAULT_APPLICATION,
370         "",
371         "",
372         "res",
373         "assets",
374         new Class[] {},
375         new String[] {},
376         new String[] {});
377   }
378 
testPackageHierarchyOf()379   @Test public void testPackageHierarchyOf() throws Exception {
380     assertThat(new ConfigMerger().packageHierarchyOf(ConfigMergerTest.class))
381         .containsExactly("org.robolectric", "org", "");
382   }
383 
384   /////////////////////////////
385 
configFor(Class<?> testClass, String methodName, final Map<String, String> configProperties)386   private Config configFor(Class<?> testClass, String methodName, final Map<String, String> configProperties) throws InitializationError {
387     return configFor(testClass, methodName, configProperties, Config.Builder.defaults().build());
388   }
389 
configFor(Class<?> testClass, String methodName)390   private Config configFor(Class<?> testClass, String methodName) throws InitializationError {
391     Config.Implementation globalConfig = Config.Builder.defaults().build();
392     return configFor(testClass, methodName, globalConfig);
393   }
394 
configFor(Class<?> testClass, String methodName, Config.Implementation globalConfig)395   private Config configFor(Class<?> testClass, String methodName, Config.Implementation globalConfig) throws InitializationError {
396     return configFor(testClass, methodName, new HashMap<>(), globalConfig);
397   }
398 
configFor(Class<?> testClass, String methodName, final Map<String, String> configProperties, Config.Implementation globalConfig)399   private Config configFor(Class<?> testClass, String methodName, final Map<String, String> configProperties, Config.Implementation globalConfig) throws InitializationError {
400     Method info = getMethod(testClass, methodName);
401     return new ConfigMerger() {
402       @Override
403       InputStream getResourceAsStream(String resourceName) {
404         String properties = configProperties.get(resourceName);
405         return properties == null ? null : new ByteArrayInputStream(properties.getBytes(UTF_8));
406       }
407     }.getConfig(testClass, info, globalConfig);
408   }
409 
410   private static Method getMethod(Class<?> testClass, String methodName) {
411     try {
412       return testClass.getMethod(methodName);
413     } catch (NoSuchMethodException e) {
414       throw new RuntimeException(e);
415     }
416   }
417 
418   private static void assertConfig(
419       Config config,
420       int[] sdk,
421       String manifest,
422       Class<? extends Application> application,
423       String packageName,
424       String qualifiers,
425       String resourceDir,
426       String assetsDir,
427       Class<?>[] shadows,
428       String[] instrumentedPackages,
429       String[] libraries) {
430     assertThat(config.sdk()).isEqualTo(sdk);
431     assertThat(config.manifest()).isEqualTo(manifest);
432     assertThat(config.application()).isEqualTo(application);
433     assertThat(config.packageName()).isEqualTo(packageName);
434     assertThat(config.qualifiers()).isEqualTo(qualifiers);
435     assertThat(config.resourceDir()).isEqualTo(resourceDir);
436     assertThat(config.assetDir()).isEqualTo(assetsDir);
437     assertThat(config.shadows()).asList().containsAtLeastElementsIn(shadows).inOrder();
438     assertThat(config.instrumentedPackages()).asList().containsAtLeastElementsIn(instrumentedPackages);
439     assertThat(config.libraries()).asList().containsAtLeastElementsIn(libraries);
440   }
441 
442   @Ignore
443   @Config(
444       sdk = 1,
445       manifest = "foo",
446       application = TestFakeApp.class,
447       packageName = "com.example.test",
448       shadows = Test1.class,
449       instrumentedPackages = "com.example.test1",
450       libraries = "libs/test",
451       qualifiers = "from-test",
452       resourceDir = "test/res",
453       assetDir = "test/assets")
454   public static class Test1 {
455     @Test
456     public void withoutAnnotation() throws Exception {
457     }
458 
459     @Test
460     @Config
461     public void withDefaultsAnnotation() throws Exception {
462     }
463 
464     @Test
465     @Config(
466         sdk = 9,
467         manifest = "furf",
468         application = TestApplication.class,
469         packageName = "com.example.method",
470         shadows = Test2.class,
471         instrumentedPackages = "com.example.method1",
472         libraries = "libs/method",
473         qualifiers = "from-method",
474         resourceDir = "method/res",
475         assetDir = "method/assets")
476     public void withOverrideAnnotation() throws Exception {}
477   }
478 
479   @Ignore
480   public static class Test2 {
481     @Test
482     public void withoutAnnotation() throws Exception {
483     }
484 
485     @Test
486     @Config
487     public void withDefaultsAnnotation() throws Exception {
488     }
489 
490     @Test
491     @Config(
492         sdk = 9,
493         manifest = "furf",
494         application = TestFakeApp.class,
495         packageName = "com.example.method",
496         shadows = Test1.class,
497         instrumentedPackages = "com.example.method2",
498         libraries = "libs/method",
499         qualifiers = "from-method",
500         resourceDir = "method/res",
501         assetDir = "method/assets")
502     public void withOverrideAnnotation() throws Exception {}
503   }
504 
505   @Ignore
506   @Config(qualifiers = "from-subclass")
507   public static class Test3 extends Test1 {
508   }
509 
510   @Ignore
511   @Config(qualifiers = "from-subclass")
512   public static class Test4 extends Test2 {
513   }
514 
515   @Ignore
516   public static class Test5 extends Test1 {
517     @Override
518     @Test
519     public void withoutAnnotation() throws Exception {
520     }
521 
522     @Override
523     @Test
524     @Config
525     public void withDefaultsAnnotation() throws Exception {
526     }
527 
528     @Override
529     @Test
530     @Config(
531         sdk = 14,
532         shadows = Test5.class,
533         instrumentedPackages = "com.example.method5",
534         packageName = "com.example.test",
535         qualifiers = "from-method5",
536         assetDir = "method5/assets")
537     public void withOverrideAnnotation() throws Exception {}
538   }
539 
540   @Ignore
541   @Config(
542       qualifiers = "from-class6",
543       shadows = Test6.class,
544       instrumentedPackages = "com.example.test6",
545       resourceDir = "class6/res")
546   public static class Test6 extends Test5 {}
547 }
548