Home | History | Annotate | Download | only in robolectric
      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 
     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 
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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 
    379   @Test public void testPackageHierarchyOf() throws Exception {
    380     assertThat(new ConfigMerger().packageHierarchyOf(ConfigMergerTest.class))
    381         .containsExactly("org.robolectric", "org", "");
    382   }
    383 
    384   /////////////////////////////
    385 
    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 
    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 
    395   private Config configFor(Class<?> testClass, String methodName, Config.Implementation globalConfig) throws InitializationError {
    396     return configFor(testClass, methodName, new HashMap<>(), globalConfig);
    397   }
    398 
    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().containsAllIn(shadows).inOrder();
    438     assertThat(config.instrumentedPackages()).asList().containsAllIn(instrumentedPackages);
    439     assertThat(config.libraries()).asList().containsAllIn(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