Push Root Matcher into ViewInteraction and share it across the graph via an
AtomicReference. This way alt root selection works with out an minor api break
(changing the storage type)
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=58351508
diff --git a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java
index c66f178..3ff0da0 100644
--- a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java
+++ b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java
@@ -47,8 +47,8 @@
* @param viewMatcher used to select the view.
* @see #onData
*/
- public static PartiallyScopedViewInteraction onView(final Matcher<View> viewMatcher) {
- return new PartiallyScopedViewInteraction(viewMatcher);
+ public static ViewInteraction onView(final Matcher<View> viewMatcher) {
+ return espressoGraph().plus(new ViewInteractionModule(viewMatcher)).get(ViewInteraction.class);
}
@@ -235,50 +235,5 @@
}
}
- /**
- * Represents a ViewInteraction which has not had a root matcher provided for it.
- *
- * By default Espresso uses a heuristic to choose the root window to operate on. Normally this
- * is sufficient, however certain UX patterns may require the user to explicitly control which
- * window Espresso operates upon.
- *
- * @see ViewInteraction
- */
- public static final class PartiallyScopedViewInteraction {
- private final Matcher<View> viewMatcher;
- private PartiallyScopedViewInteraction(Matcher<View> viewMatcher) {
- this.viewMatcher = checkNotNull(viewMatcher);
- }
- /**
- * Creates a ViewInteraction scoped to the root selected by the given root matcher.
- */
- public ViewInteraction inRoot(Matcher<Root> rootMatcher) {
- checkNotNull(rootMatcher);
- return espressoGraph().plus(new ViewInteractionModule(viewMatcher, rootMatcher))
- .get(ViewInteraction.class);
- }
-
- /**
- * Creates a ViewInteraction scoped to the the root selected by Espresso's heuristics
- * and performs the given ViewActions.
- *
- * @see ViewInteraction#perform(ViewAction...)
- */
- public ViewInteraction perform(ViewAction... actions) {
- return espressoGraph().plus(new ViewInteractionModule(viewMatcher))
- .get(ViewInteraction.class).perform(actions);
- }
-
- /**
- * Creates a ViewInteraction scoped to the the root selected by Espresso's heuristics
- * and performs the given ViewAssertion.
- *
- * @see ViewInteraction#check(ViewAssertion)
- */
- public ViewInteraction check(ViewAssertion viewAssert) {
- return espressoGraph().plus(new ViewInteractionModule(viewMatcher))
- .get(ViewInteraction.class).check(viewAssert);
- }
- }
}
diff --git a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java
index c6b13cf..a8a8d1d 100644
--- a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java
+++ b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java
@@ -19,6 +19,7 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
@@ -40,6 +41,7 @@
private final Executor mainThreadExecutor;
private final FailureHandler failureHandler;
private final Matcher<View> viewMatcher;
+ private final AtomicReference<Matcher<Root>> rootMatcherRef;
@Inject
ViewInteraction(
@@ -47,12 +49,14 @@
ViewFinder viewFinder,
@MainThread Executor mainThreadExecutor,
FailureHandler failureHandler,
- Matcher<View> viewMatcher) {
+ Matcher<View> viewMatcher,
+ AtomicReference<Matcher<Root>> rootMatcherRef) {
this.viewFinder = checkNotNull(viewFinder);
this.uiController = checkNotNull(uiController);
this.failureHandler = checkNotNull(failureHandler);
this.mainThreadExecutor = checkNotNull(mainThreadExecutor);
this.viewMatcher = checkNotNull(viewMatcher);
+ this.rootMatcherRef = checkNotNull(rootMatcherRef);
}
/**
@@ -71,6 +75,15 @@
return this;
}
+
+ /**
+ * Makes this ViewInteraction scoped to the root selected by the given root matcher.
+ */
+ public ViewInteraction inRoot(Matcher<Root> rootMatcher) {
+ this.rootMatcherRef.set(checkNotNull(rootMatcher));
+ return this;
+ }
+
private void doPerform(final ViewAction viewAction) {
checkNotNull(viewAction);
final Matcher<? extends View> constraints = checkNotNull(viewAction.getConstraints());
diff --git a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java
index fbdc0ea..d94ecef 100644
--- a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java
+++ b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java
@@ -12,6 +12,7 @@
import dagger.Provides;
import org.hamcrest.Matcher;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Adds the user interaction scope to the Espresso graph.
@@ -22,19 +23,15 @@
class ViewInteractionModule {
private final Matcher<View> viewMatcher;
- private final Matcher<Root> rootMatcher;
+ private final AtomicReference<Matcher<Root>> rootMatcher =
+ new AtomicReference<Matcher<Root>>(RootMatchers.DEFAULT);
ViewInteractionModule(Matcher<View> viewMatcher) {
- this(viewMatcher, RootMatchers.DEFAULT);
- }
-
- ViewInteractionModule(Matcher<View> viewMatcher, Matcher<Root> rootMatcher) {
this.viewMatcher = checkNotNull(viewMatcher);
- this.rootMatcher = checkNotNull(rootMatcher);
}
@Provides
- Matcher<Root> provideRootMatcher() {
+ AtomicReference<Matcher<Root>> provideRootMatcher() {
return rootMatcher;
}
diff --git a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java
index 8222973..087cd4a 100644
--- a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java
+++ b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java
@@ -24,6 +24,7 @@
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -42,22 +43,24 @@
private final Provider<List<Root>> rootsOracle;
private final UiController uiController;
private final ActivityLifecycleMonitor activityLifecycleMonitor;
- private final Matcher<Root> rootMatcher;
+ private final AtomicReference<Matcher<Root>> rootMatcherRef;
private List<Root> roots;
@Inject
RootViewPicker(Provider<List<Root>> rootsOracle, UiController uiController,
- ActivityLifecycleMonitor activityLifecycleMonitor, Matcher<Root> rootMatcher) {
+ ActivityLifecycleMonitor activityLifecycleMonitor,
+ AtomicReference<Matcher<Root>> rootMatcherRef) {
this.rootsOracle = rootsOracle;
this.uiController = uiController;
this.activityLifecycleMonitor = activityLifecycleMonitor;
- this.rootMatcher = rootMatcher;
+ this.rootMatcherRef = rootMatcherRef;
}
@Override
public View get() {
checkState(Looper.getMainLooper().equals(Looper.myLooper()), "must be called on main thread.");
+ Matcher<Root> rootMatcher = rootMatcherRef.get();
Root root = findRoot(rootMatcher);
diff --git a/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java b/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java
index 1333fc1..4a2d896 100644
--- a/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java
+++ b/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java
@@ -4,6 +4,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -11,6 +12,7 @@
import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitor;
import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry;
+import com.google.android.apps.common.testing.ui.espresso.matcher.RootMatchers;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.MoreExecutors;
@@ -22,6 +24,7 @@
import org.mockito.Mock;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
/** Unit tests for {@link ViewInteraction}. */
public class ViewInteractionTest extends AndroidTestCase {
@@ -44,6 +47,7 @@
private View targetView;
private Matcher<View> viewMatcher;
private Matcher<View> actionConstraint;
+ private AtomicReference<Matcher<Root>> rootMatcherRef;
@Override
public void setUp() throws Exception {
@@ -54,6 +58,7 @@
targetView = new View(getContext());
viewMatcher = is(targetView);
actionConstraint = Matchers.<View>notNullValue();
+ rootMatcherRef = new AtomicReference<Matcher<Root>>(RootMatchers.DEFAULT);
when(mockAction.getDescription()).thenReturn("A Mock!");
failureHandler = new FailureHandler() {
@Override
@@ -154,6 +159,22 @@
Optional.<NoMatchingViewException>absent());
}
+ public void testInRootUpdatesRef() {
+ initInteraction();
+ Matcher<Root> testMatcher = nullValue();
+ testInteraction.inRoot(testMatcher);
+ assertEquals(testMatcher, rootMatcherRef.get());
+ }
+
+ public void testInRoot_NullHandling() {
+ initInteraction();
+ try {
+ testInteraction.inRoot(null);
+ fail("should throw");
+ } catch (NullPointerException expected) {
+ }
+ }
+
public void testCheck_ViewCannotBeFound() {
NoMatchingViewException noViewException = new NoMatchingViewException.Builder()
.withViewMatcher(viewMatcher)
@@ -170,7 +191,7 @@
when(mockAction.getConstraints()).thenReturn(actionConstraint);
testInteraction = new ViewInteraction(mockUiController, mockViewFinder, testExecutor,
- failureHandler, viewMatcher);
+ failureHandler, viewMatcher, rootMatcherRef);
}
}
diff --git a/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/sample/MultipleWindowTest.java b/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/sample/MultipleWindowTest.java
index 28d2688..ecdb65d 100644
--- a/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/sample/MultipleWindowTest.java
+++ b/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/sample/MultipleWindowTest.java
@@ -19,6 +19,7 @@
import com.google.android.apps.common.testing.ui.testapp.R;
import com.google.android.apps.common.testing.ui.testapp.SendActivity;
+import android.os.Build;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
@@ -48,6 +49,10 @@
}
public void testInteractionsWithAutoCompletePopup() {
+ if (Build.VERSION.SDK_INT < 10) {
+ // Froyo's AutoCompleteTextBox is broken - do not bother testing with it.
+ return;
+ }
// Android's Window system allows multiple view hierarchies to layer on top of each other.
//
// A real world analogy would be an overhead projector with multiple transparencies placed