Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Here's the magic to get ActionBarSherlock working with Robolectric 2.0-alpha-2!

You need to add the files below, and do this once in your base test runner:

ActionBarSherlock.registerImplementation(ActionBarSherlockRobolectric.class);
ActionBarSherlock.unregisterImplementation(ActionBarSherlockNative.class);
ActionBarSherlock.unregisterImplementation(ActionBarSherlockCompat.class);
// Copyright 2012 Square, Inc. License: Apache 2.
package com.squareup.test;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import com.actionbarsherlock.ActionBarSherlock;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.internal.ActionBarSherlockCompat;
import com.actionbarsherlock.internal.ActionBarSherlockNative;
import com.actionbarsherlock.view.MenuInflater;
import com.squareup.test.actionbarsherlock.SherlockMenuInflater;
import static org.robolectric.Robolectric.shadowOf;
/**
* During initialization, {@link ActionBarSherlock} figures out which {@link
* com.actionbarsherlock.app.ActionBar} to use based on the API level. It does this by checking the
* Build.Version.SDK_INT value which depends on the hidden <i>SystemProperties</i> class.
*
* Because Roboelectric does not have this, it always returns <code>0</code> for its API level
* causing {@link ActionBarSherlock} to crash. This class helps resolve this issue by providing
* an {@link ActionBarSherlockNative} implementation for API level 0.
* @see ActionBarSherlock#registerImplementation(Class)
*/
@ActionBarSherlock.Implementation(api = 0)
public class ActionBarSherlockRobolectric extends ActionBarSherlockCompat {
final private ActionBar actionBar;
public ActionBarSherlockRobolectric(Activity activity, int flags) {
super(activity, flags);
actionBar = new MockActionBar(activity);
}
@Override public void setContentView(int layoutResId) {
LayoutInflater layoutInflater = LayoutInflater.from(mActivity);
View contentView = layoutInflater.inflate(layoutResId, null);
shadowOf(mActivity).setContentView(contentView);
}
@Override public void setContentView(View view) {
shadowOf(mActivity).setContentView(view);
}
@Override public ActionBar getActionBar() {
return actionBar;
}
@Override protected Context getThemedContext() {
return mActivity;
}
@Override public MenuInflater getMenuInflater() {
if (mMenuInflater == null) {
mMenuInflater = new SherlockMenuInflater(mActivity);
}
return mMenuInflater;
}
}
// Copyright 2012 Square, Inc. License: Apache 2.
package com.squareup.test;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.SpinnerAdapter;
import com.actionbarsherlock.app.ActionBar;
public class MockActionBar extends ActionBar {
String title;
String subtitle;
View customView;
Context realContext;
public MockActionBar(Context context) {
realContext = context;
}
@Override public void setCustomView(View view) {
setCustomView(view, null);
}
@Override public void setCustomView(View view, LayoutParams layoutParams) {
this.customView = view;
}
@Override public void setCustomView(int resId) {
}
@Override public void setIcon(int resId) {
}
@Override public void setIcon(Drawable icon) {
}
@Override public void setLogo(int resId) {
}
@Override public void setLogo(Drawable logo) {
}
@Override
public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
}
@Override public void setSelectedNavigationItem(int position) {
}
@Override public int getSelectedNavigationIndex() {
return 0;
}
@Override public int getNavigationItemCount() {
return 0;
}
@Override public void setTitle(CharSequence title) {
this.title = (String) title;
}
@Override public void setTitle(int resId) {
title = realContext.getString(resId);
}
@Override public void setSubtitle(CharSequence newSubtitle) {
subtitle = (String) newSubtitle;
}
@Override public void setSubtitle(int resId) {
subtitle = realContext.getString(resId);
}
@Override public void setDisplayOptions(int options) {
}
@Override public void setDisplayOptions(int options, int mask) {
}
@Override public void setDisplayUseLogoEnabled(boolean useLogo) {
}
@Override public void setDisplayShowHomeEnabled(boolean showHome) {
}
@Override public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
}
@Override public void setDisplayShowTitleEnabled(boolean showTitle) {
}
@Override public void setDisplayShowCustomEnabled(boolean showCustom) {
}
@Override public void setBackgroundDrawable(Drawable d) {
}
@Override public View getCustomView() {
return customView;
}
@Override public CharSequence getTitle() {
return title;
}
@Override public CharSequence getSubtitle() {
return subtitle;
}
@Override public int getNavigationMode() {
return 0;
}
@Override public void setNavigationMode(int mode) {
}
@Override public int getDisplayOptions() {
return 0;
}
@Override public Tab newTab() {
return null;
}
@Override public void addTab(Tab tab) {
}
@Override public void addTab(Tab tab, boolean setSelected) {
}
@Override public void addTab(Tab tab, int position) {
}
@Override public void addTab(Tab tab, int position, boolean setSelected) {
}
@Override public void removeTab(Tab tab) {
}
@Override public void removeTabAt(int position) {
}
@Override public void removeAllTabs() {
}
@Override public void selectTab(Tab tab) {
}
@Override public Tab getSelectedTab() {
return null;
}
@Override public Tab getTabAt(int index) {
return null;
}
@Override public int getTabCount() {
return 0;
}
@Override public int getHeight() {
return 0;
}
@Override public void show() {
}
@Override public void hide() {
}
@Override public boolean isShowing() {
return false;
}
@Override public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
}
@Override
public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
}
}
// Copyright 2012 Square, Inc. License: Apache 2.
package com.squareup.test.actionbarsherlock;
import android.content.Context;
import android.util.AttributeSet;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.SubMenu;
import org.robolectric.internal.Implementation;
import org.robolectric.res.MenuNode;
import org.robolectric.res.ResName;
import org.robolectric.res.ResourceLoader;
import org.robolectric.util.I18nException;
import static org.robolectric.Robolectric.shadowOf;
/**
* Inflates menus that are part of ActionBarSherlock instead. Uses ABS custom {@link
* com.actionbarsherlock.view.Menu} instead of the stock one.
*/
public class SherlockMenuInflater extends MenuInflater {
private final Context context;
public SherlockMenuInflater(Context context) {
super(context);
this.context = context;
}
@Implementation
public void inflate(int resource, Menu root) {
String qualifiers = shadowOf(context.getResources().getConfiguration()).getQualifiers();
ResourceLoader resourceLoader = shadowOf(context).getResourceLoader();
ResName resName = shadowOf(context).getResName(resource);
MenuNode menuNode = resourceLoader.getMenuNode(resName, qualifiers);
try {
addChildrenInGroup(menuNode, 0, root);
} catch (I18nException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("error inflating " + resName, e);
}
}
private void addChildrenInGroup(MenuNode source, int groupId, Menu root) {
for (MenuNode child : source.getChildren()) {
String name = child.getName();
AttributeSet attributes = shadowOf(context).createAttributeSet(child.getAttributes(), null);
if (name.equals("item")) {
if (child.isSubMenuItem()) {
SubMenu sub = root.addSubMenu(groupId,
attributes.getAttributeResourceValue("android", "id", 0),
0, attributes.getAttributeValue("android", "title"));
MenuNode subMenuNode = child.getChildren().get(0);
addChildrenInGroup(subMenuNode, groupId, sub);
} else {
root.add(groupId,
attributes.getAttributeResourceValue("android", "id", 0),
0, attributes.getAttributeValue("android", "title"));
}
} else if (name.equals("group")) {
int newGroupId = attributes.getAttributeResourceValue("android", "id", 0);
addChildrenInGroup(child, newGroupId, root);
}
}
}
}

cwc commented Mar 12, 2013

So I'm having troubles with 2.0-alpha-2. I've setup a simple test app that uses Android Annotations, ABS, and Robolectric. My POM links to the latest release of the other two libraries, as well as API 17 of Android. I'm using the very simple test runner seen here: https://gist.github.com/cwc/5146505

I get the following exception when attempting to run a basic test with Maven:

java.lang.RuntimeException: java.lang.RuntimeException: Stub!
        at android.net.Uri.$$robo$$Uri_30fc_parse(Uri.java:53)
        at org.robolectric.bytecode.ShadowWrangler$InvocationPlan.callOriginal(ShadowWrangler.java:591)
        at android.net.Uri.parse(Uri.java)
        at org.robolectric.shadows.ShadowMediaStore.reset(ShadowMediaStore.java:27)
        at org.robolectric.Robolectric.resetStaticState(Robolectric.java:821)
        at org.robolectric.RobolectricTestRunner.resetStaticState(RobolectricTestRunner.java:224)
        at org.robolectric.RobolectricTestRunner.internalBeforeTest(RobolectricTestRunner.java:133)
        at org.robolectric.RobolectricTestRunner.methodBlock(RobolectricTestRunner.java:96)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
        at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
        at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray2(ReflectionUtils.java:208)
        at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:158)
        at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:86)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:95)

I'm running into a similar Uri_30fc_parse issue. Did you ever work out what was wrong here?

mag commented Jun 20, 2013

Christian, this code has a square copyright on it. Can you slap an open source license on it so we can integrate it without license uncertainty?

mag commented Aug 16, 2013

Christian, do you have a moment to change this to something like MIT or Apache license?

is this still needed for Robolectric 2.1.1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment