package roboguice.activity; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.robolectric.Robolectric.shadowOf; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import roboguice.RoboGuice; import roboguice.activity.SherlockActivityInjectionTest.ModuleA.A; import roboguice.activity.SherlockActivityInjectionTest.ModuleB.B; import roboguice.activity.SherlockActivityInjectionTest.ModuleC.C; import roboguice.activity.SherlockActivityInjectionTest.ModuleD.D; import roboguice.inject.ContextScopedProvider; import roboguice.inject.ContextSingleton; import roboguice.inject.InjectExtra; import roboguice.inject.InjectPreference; import roboguice.inject.InjectResource; import roboguice.inject.InjectView; import roboguice.inject.NullProvider; import com.actionbarsherlock.ActionBarSherlock; import com.actionbarsherlock.internal.ActionBarSherlockNative; import com.google.inject.ConfigurationException; import com.google.inject.Inject; import com.google.inject.Key; import com.google.inject.Stage; import com.google.inject.TypeLiteral; import android.R; import android.app.Activity; import android.app.Application; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.preference.Preference; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; @RunWith(RobolectricTestRunner.class) public class SherlockActivityInjectionTest { protected DummySherlockActivity activity; @Before public void setup() { RoboGuice .getOrCreateBaseApplicationInjector(Robolectric.application, Stage.DEVELOPMENT, RoboGuice.newDefaultRoboModule(Robolectric.application), new ModuleA()); ActionBarSherlock.registerImplementation(ActionBarSherlockRobolectric.class); Intent intent = new Intent(Robolectric.application, DummySherlockActivity.class).putExtra("foobar", "goober"); activity = Robolectric.buildActivity(DummySherlockActivity.class).withIntent(intent).create().get(); } @Test public void shouldInjectUsingDefaultConstructor() { assertThat(activity.emptyString, is("")); } @Test public void shouldInjectView() { assertThat(activity.text1, is(activity.findViewById(R.id.text1))); } @Test public void shouldInjectStringResource() { assertThat(activity.cancel, is("Cancel")); } @Test public void shouldInjectExtras() { assertThat(activity.foobar, is("goober")); } @Test public void shouldStaticallyInject() { assertThat(A.t, equalTo("")); } @Test public void shouldInjectActivityAndRoboSherlockActivity() { assertEquals(activity, activity.activity); assertEquals(activity, activity.roboSherlockActivity); } @Test(expected = ConfigurationException.class) public void shouldNotStaticallyInjectViews() { RoboGuice .getOrCreateBaseApplicationInjector(Robolectric.application, Stage.DEVELOPMENT, RoboGuice.newDefaultRoboModule(Robolectric.application), new ModuleB()); @SuppressWarnings("unused") final B b = Robolectric.buildActivity(B.class).create().get(); } @Test(expected = ConfigurationException.class) public void shouldNotStaticallyInjectExtras() { RoboGuice .getOrCreateBaseApplicationInjector(Robolectric.application, Stage.DEVELOPMENT, RoboGuice.newDefaultRoboModule(Robolectric.application), new ModuleD()); @SuppressWarnings("unused") final D d = Robolectric.buildActivity(D.class).create().get(); } @Test(expected = ConfigurationException.class) public void shouldNotStaticallyInjectPreferenceViews() { RoboGuice .getOrCreateBaseApplicationInjector(Robolectric.application, Stage.DEVELOPMENT, RoboGuice.newDefaultRoboModule(Robolectric.application), new ModuleC()); @SuppressWarnings("unused") final C c = Robolectric.buildActivity(C.class).create().get(); } @Test public void shouldInjectApplication() { final G g = Robolectric.buildActivity(G.class).create().get(); assertThat(g.application, equalTo(Robolectric.application)); } @Test public void shouldAllowBackgroundThreadsToFinishUsingContextAfterOnDestroy() throws Exception { final SoftReference<F> ref = new SoftReference<F>(Robolectric.buildActivity(F.class).create().get()); final BlockingQueue<Context> queue = new ArrayBlockingQueue<Context>(1); new Thread() { final Context context = RoboGuice.getInjector(ref.get()).getInstance(Context.class); @Override public void run() { queue.add(context); } }.start(); ref.get().onDestroy(); // Force an OoM // http://stackoverflow.com/questions/3785713/how-to-make-the-java-system-release-soft-references/3810234 boolean oomHappened = false; try { @SuppressWarnings({ "MismatchedQueryAndUpdateOfCollection" }) final ArrayList<Object[]> allocations = new ArrayList<Object[]>(); int size; while ((size = Math.min(Math.abs((int) Runtime.getRuntime().freeMemory()), Integer.MAX_VALUE)) > 0) allocations.add(new Object[size]); } catch (OutOfMemoryError e) { // Yeah! oomHappened = true; } assertTrue(oomHappened); assertNotNull(queue.poll(10, TimeUnit.SECONDS)); } @Test public void shouldBeAbleToGetContextProvidersInBackgroundThreads() throws Exception { final F f = Robolectric.buildActivity(F.class).create().get(); final FutureTask<Context> future = new FutureTask<Context>(new Callable<Context>() { final ContextScopedProvider<Context> contextProvider = RoboGuice.getInjector(f).getInstance( Key.get(new TypeLiteral<ContextScopedProvider<Context>>() { })); @Override public Context call() throws Exception { return contextProvider.get(f); } }); Executors.newSingleThreadExecutor().execute(future); future.get(); } public static class DummySherlockActivity extends RoboSherlockActivity { @Inject protected String emptyString; @Inject protected Activity activity; @Inject protected RoboSherlockActivity roboSherlockActivity; @InjectView(R.id.text1) protected TextView text1; @InjectResource(R.string.cancel) protected String cancel; @InjectExtra("foobar") protected String foobar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final LinearLayout root = new LinearLayout(this); final TextView text1 = new TextView(this); root.addView(text1); text1.setId(R.id.text1); final LinearLayout included1 = addIncludedView(R.id.summary, R.string.ok); root.addView(included1); final LinearLayout included2 = addIncludedView(R.id.title, R.string.no); root.addView(included2); setContentView(root); } protected LinearLayout addIncludedView(int includedRootId, int stringResId) { LinearLayout container = new LinearLayout(this); container.setId(includedRootId); TextView textView = new TextView(this); container.addView(textView); textView.setId(R.id.text2); textView.setText(stringResId); return container; } } public static class BaseModule extends com.google.inject.AbstractModule { @Override protected void configure() { bind(RoboSherlockActivity.class).toProvider(Key.get(new TypeLiteral<NullProvider<RoboSherlockActivity>>() { })).in(ContextSingleton.class); } } public static class ModuleA extends BaseModule { @Override protected void configure() { super.configure(); requestStaticInjection(A.class); } public static class A { @InjectResource(R.string.cancel) static String s; @Inject static String t; } } public static class ModuleB extends BaseModule { @Override protected void configure() { super.configure(); requestStaticInjection(B.class); } public static class B extends RoboSherlockActivity { @InjectView(0) static View v; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } } } public static class ModuleC extends BaseModule { @Override public void configure() { super.configure(); requestStaticInjection(C.class); } public static class C extends RoboSherlockActivity { @InjectPreference("xxx") static Preference v; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } } } public static class ModuleD extends BaseModule { @Override public void configure() { super.configure(); requestStaticInjection(D.class); } public static class D extends RoboSherlockActivity { @InjectExtra("xxx") static String s; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } } } public static class F extends RoboSherlockActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onDestroy() { super.onDestroy(); } } public static class G extends RoboSherlockActivity { @Inject Application application; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } } @ActionBarSherlock.Implementation(api = 0) public static class ActionBarSherlockRobolectric extends ActionBarSherlockNative { public ActionBarSherlockRobolectric(Activity activity, int flags) { super(activity, flags); } @Override public void setContentView(int layoutResId) { LayoutInflater layoutInflater = LayoutInflater.from(mActivity); View contentView = layoutInflater.inflate(layoutResId, null); shadowOf(mActivity).getWindow().setContentView(contentView); } @Override public void setContentView(View view) { shadowOf(mActivity).getWindow().setContentView(view); } } }