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