blob: 30682d9343c7d1f4b67713a2f59448273f18333c [file] [log] [blame]
package org.robolectric;
import android.app.Activity;
import android.app.Fragment;
import android.app.Service;
import android.app.IntentService;
import android.content.ContentProvider;
import android.content.Intent;
import android.util.AttributeSet;
import android.view.View;
import org.robolectric.internal.ShadowProvider;
import org.robolectric.res.ResName;
import org.robolectric.res.ResourceTable;
import org.robolectric.res.builder.XmlResourceParserImpl;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.util.ServiceLoader;
public class Robolectric {
private static ShadowsAdapter shadowsAdapter = null;
private static Iterable<ShadowProvider> providers;
public static void reset() {
if (providers == null) {
providers = ServiceLoader.load(ShadowProvider.class);
}
for (ShadowProvider provider : providers) {
provider.reset();
}
RuntimeEnvironment.application = null;
RuntimeEnvironment.setRobolectricPackageManager(null);
RuntimeEnvironment.setActivityThread(null);
}
public static ShadowsAdapter getShadowsAdapter() {
synchronized (ShadowsAdapter.class) {
if (shadowsAdapter == null) {
shadowsAdapter = instantiateShadowsAdapter();
}
}
return shadowsAdapter;
}
public static <T extends Service> ServiceController<T> buildService(Class<T> serviceClass) {
return buildService(serviceClass, null);
}
public static <T extends Service> ServiceController<T> buildService(Class<T> serviceClass, Intent intent) {
return ServiceController.of(getShadowsAdapter(), ReflectionHelpers.callConstructor(serviceClass), intent);
}
public static <T extends Service> T setupService(Class<T> serviceClass) {
return buildService(serviceClass).create().get();
}
public static <T extends IntentService> IntentServiceController<T> buildIntentService(Class<T> serviceClass) {
return buildIntentService(serviceClass, null);
}
public static <T extends IntentService> IntentServiceController<T> buildIntentService(Class<T> serviceClass, Intent intent) {
return IntentServiceController.of(getShadowsAdapter(), ReflectionHelpers.callConstructor(serviceClass, new ReflectionHelpers.ClassParameter<String>(String.class, "IntentService")), intent);
}
public static <T extends IntentService> T setupIntentService(Class<T> serviceClass) {
return buildIntentService(serviceClass).create().get();
}
public static <T extends ContentProvider> ContentProviderController<T> buildContentProvider(Class<T> contentProviderClass) {
return ContentProviderController.of(ReflectionHelpers.callConstructor(contentProviderClass));
}
public static <T extends ContentProvider> T setupContentProvider(Class<T> contentProviderClass) {
return buildContentProvider(contentProviderClass).create().get();
}
public static <T extends Activity> ActivityController<T> buildActivity(Class<T> activityClass) {
return buildActivity(activityClass, null);
}
public static <T extends Activity> ActivityController<T> buildActivity(Class<T> activityClass, Intent intent) {
return ActivityController.of(getShadowsAdapter(), ReflectionHelpers.callConstructor(activityClass), intent);
}
public static <T extends Activity> T setupActivity(Class<T> activityClass) {
return buildActivity(activityClass).setup().get();
}
public static <T extends Fragment> FragmentController<T> buildFragment(Class<T> fragmentClass) {
return FragmentController.of(ReflectionHelpers.callConstructor(fragmentClass));
}
public static <T extends Fragment> FragmentController<T> buildFragment(Class<T> fragmentClass, Class<? extends Activity> activityClass) {
return FragmentController.of(ReflectionHelpers.callConstructor(fragmentClass), activityClass);
}
public static <T extends Fragment> FragmentController<T> buildFragment(Class<T> fragmentClass, Intent intent) {
return FragmentController.of(ReflectionHelpers.callConstructor(fragmentClass), intent);
}
public static <T extends Fragment> FragmentController<T> buildFragment(Class<T> fragmentClass, Class<? extends Activity> activityClass, Intent intent) {
return FragmentController.of(ReflectionHelpers.callConstructor(fragmentClass), activityClass, intent);
}
/**
* Allows for the programatic creation of an {@link AttributeSet} useful for testing {@link View} classes without
* the need for creating XML snippets.
*/
public static AttributeSetBuilder buildAttributeSet() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
Document document;
try {
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
document = documentBuilder.newDocument();
Element dummy = document.createElementNS("http://schemas.android.com/apk/res/" + RuntimeEnvironment.application.getPackageName(), "dummy");
document.appendChild(dummy);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
}
return new AttributeSetBuilder(document, RuntimeEnvironment.getCompileTimeResourceProvider());
}
public static class AttributeSetBuilder {
private Document doc;
private ResourceTable appResourceTable;
AttributeSetBuilder(Document doc, ResourceTable resourceTable) {
this.doc = doc;
this.appResourceTable = resourceTable;
}
public AttributeSetBuilder addAttribute(int resId, String value) {
ResName resName = appResourceTable.getResName(resId);
if ("style".equals(resName.name)) {
((Element)doc.getFirstChild()).setAttribute(resName.name, value);
} else {
((Element)doc.getFirstChild()).setAttributeNS(resName.getNamespaceUri(), resName.packageName + ":" + resName.name, value);
}
return this;
}
public AttributeSetBuilder setStyleAttribute(String value) {
((Element)doc.getFirstChild()).setAttribute("style", value);
return this;
}
public AttributeSet build() {
XmlResourceParserImpl parser = new XmlResourceParserImpl(doc, null, RuntimeEnvironment.application.getPackageName(), RuntimeEnvironment.application.getPackageName(), appResourceTable);
try {
parser.next(); // Root document element
parser.next(); // "dummy" element
} catch (Exception e) {
throw new IllegalStateException("Expected single dummy element in the document to contain the attributes.", e);
}
return parser;
}
}
/**
* Return the foreground scheduler (e.g. the UI thread scheduler).
*
* @return Foreground scheduler.
*/
public static Scheduler getForegroundThreadScheduler() {
return ShadowApplication.getInstance().getForegroundThreadScheduler();
}
/**
* Execute all runnables that have been enqueued on the foreground scheduler.
*/
public static void flushForegroundThreadScheduler() {
getForegroundThreadScheduler().advanceToLastPostedRunnable();
}
/**
* Return the background scheduler.
*
* @return Background scheduler.
*/
public static Scheduler getBackgroundThreadScheduler() {
return ShadowApplication.getInstance().getBackgroundThreadScheduler();
}
/**
* Execute all runnables that have been enqueued on the background scheduler.
*/
public static void flushBackgroundThreadScheduler() {
getBackgroundThreadScheduler().advanceToLastPostedRunnable();
}
private static ShadowsAdapter instantiateShadowsAdapter() {
ShadowsAdapter result = null;
for (ShadowsAdapter adapter : ServiceLoader.load(ShadowsAdapter.class)) {
if (result == null) {
result = adapter;
} else {
throw new RuntimeException("Multiple " + ShadowsAdapter.class.getCanonicalName() + "s found. Robolectric has loaded multiple core shadow modules for some reason.");
}
}
if (result == null) {
throw new RuntimeException("No shadows modules found containing a " + ShadowsAdapter.class.getCanonicalName());
} else {
return result;
}
}
}