1 package org.robolectric.internal;
2 
3 import java.util.ServiceLoader;
4 import org.robolectric.ApkLoader;
5 import org.robolectric.RobolectricTestRunner;
6 import org.robolectric.TestLifecycle;
7 import org.robolectric.android.fakes.RoboCharsets;
8 import org.robolectric.android.fakes.RoboCleaner;
9 import org.robolectric.android.fakes.RoboExtendedResponseCache;
10 import org.robolectric.android.fakes.RoboResponseSource;
11 import org.robolectric.annotation.Config;
12 import org.robolectric.annotation.Implements;
13 import org.robolectric.internal.bytecode.InstrumentationConfiguration;
14 import org.robolectric.internal.bytecode.Interceptors;
15 import org.robolectric.internal.bytecode.MethodRef;
16 import org.robolectric.manifest.AndroidManifest;
17 import org.robolectric.res.ResourcePath;
18 import org.robolectric.res.ResourceTable;
19 import org.robolectric.res.builder.XmlBlock;
20 import org.robolectric.shadow.api.ShadowPicker;
21 
22 public class AndroidConfigurer {
withConfig(InstrumentationConfiguration.Builder builder, Config config)23   public static void withConfig(InstrumentationConfiguration.Builder builder, Config config) {
24     for (Class<?> clazz : config.shadows()) {
25       Implements annotation = clazz.getAnnotation(Implements.class);
26       if (annotation == null) {
27         throw new IllegalArgumentException(clazz + " is not annotated with @Implements");
28       }
29 
30       String className = annotation.className();
31       if (className.isEmpty()) {
32         className = annotation.value().getName();
33       }
34 
35       if (!className.isEmpty()) {
36         builder.addInstrumentedClass(className);
37       }
38     }
39     for (String packageName : config.instrumentedPackages()) {
40       builder.addInstrumentedPackage(packageName);
41     }
42   }
43 
configure(InstrumentationConfiguration.Builder builder, Interceptors interceptors)44   public static void configure(InstrumentationConfiguration.Builder builder, Interceptors interceptors) {
45     for (MethodRef methodRef : interceptors.getAllMethodRefs()) {
46       builder.addInterceptedMethod(methodRef);
47     }
48 
49     builder
50         .doNotAcquireClass(TestLifecycle.class)
51         .doNotAcquireClass(AndroidManifest.class)
52         .doNotAcquireClass(RobolectricTestRunner.class)
53         .doNotAcquireClass(RobolectricTestRunner.HelperTestRunner.class)
54         .doNotAcquireClass(ShadowPicker.class)
55         .doNotAcquireClass(ResourcePath.class)
56         .doNotAcquireClass(ResourceTable.class)
57         .doNotAcquireClass(ApkLoader.class)
58         .doNotAcquireClass(XmlBlock.class);
59 
60     builder
61         .doNotAcquirePackage("javax.")
62         .doNotAcquirePackage("org.junit")
63         .doNotAcquirePackage("org.hamcrest")
64         .doNotAcquirePackage("org.robolectric.annotation.")
65         .doNotAcquirePackage("org.robolectric.internal.")
66         .doNotAcquirePackage("org.robolectric.manifest.")
67         .doNotAcquirePackage("org.robolectric.res.")
68         .doNotAcquirePackage("org.robolectric.util.")
69         .doNotAcquirePackage("org.robolectric.RobolectricTestRunner$")
70         .doNotAcquirePackage("sun.")
71         .doNotAcquirePackage("com.sun.")
72         .doNotAcquirePackage("org.w3c.")
73         .doNotAcquirePackage("org.xml.")
74         .doNotAcquirePackage("org.specs2")  // allows for android projects with mixed scala\java tests to be
75         .doNotAcquirePackage("scala.")      //  run with Maven Surefire (see the RoboSpecs project on github)
76         .doNotAcquirePackage("kotlin.")
77          // Fix #958: SQLite native library must be loaded once.
78         .doNotAcquirePackage("com.almworks.sqlite4java")
79         .doNotAcquirePackage("org.jacoco.");
80 
81     builder
82         .addClassNameTranslation(
83             "java.net.ExtendedResponseCache", RoboExtendedResponseCache.class.getName())
84         .addClassNameTranslation("java.net.ResponseSource", RoboResponseSource.class.getName())
85         .addClassNameTranslation("java.nio.charset.Charsets", RoboCharsets.class.getName())
86         .addClassNameTranslation("java.lang.UnsafeByteSequence", Object.class.getName())
87         .addClassNameTranslation("java.util.jar.StrictJarFile", Object.class.getName())
88         .addClassNameTranslation("sun.misc.Cleaner", RoboCleaner.class.getName());
89 
90     // Instrumenting these classes causes a weird failure.
91     builder.doNotInstrumentClass("android.R")
92         .doNotInstrumentClass("android.R$styleable");
93 
94     builder.addInstrumentedPackage("dalvik.")
95         .addInstrumentedPackage("libcore.")
96         .addInstrumentedPackage("android.")
97         .addInstrumentedPackage("androidx.")
98         .addInstrumentedPackage("com.android.internal.")
99         .addInstrumentedPackage("org.apache.http.")
100         .addInstrumentedPackage("org.ccil.cowan.tagsoup")
101         .addInstrumentedPackage("org.kxml2.");
102 
103     // Room's migration package uses GSON and reflection to create Java classes from JSON files.
104     // This results in an error where two __robo_data__ fields get added to the same object.
105     builder.doNotInstrumentPackage("androidx.room.migration");
106     builder.doNotInstrumentPackage("androidx.test");
107     builder.doNotInstrumentPackage("android.arch.persistence.room.migration");
108     builder.doNotInstrumentPackage("android.support.test");
109 
110     for (ShadowProvider provider : ServiceLoader.load(ShadowProvider.class)) {
111       for (String packagePrefix : provider.getProvidedPackageNames()) {
112         builder.addInstrumentedPackage(packagePrefix);
113       }
114     }
115   }
116 }
117