summaryrefslogtreecommitdiffstats
path: root/TestCommon
diff options
context:
space:
mode:
authorChiao Cheng <chiaocheng@google.com>2012-08-17 16:06:16 -0700
committerChiao Cheng <chiaocheng@google.com>2012-08-17 16:06:16 -0700
commitd6ee8ee8ff25334a6544570d3f0c454bec955908 (patch)
tree3662962fe10dac42f79dce36442b8211d1d7f926 /TestCommon
parent6f0954c3483fab42ee29b4ba342d3401dd843372 (diff)
downloadandroid_packages_apps_ContactsCommon-d6ee8ee8ff25334a6544570d3f0c454bec955908.tar.gz
android_packages_apps_ContactsCommon-d6ee8ee8ff25334a6544570d3f0c454bec955908.tar.bz2
android_packages_apps_ContactsCommon-d6ee8ee8ff25334a6544570d3f0c454bec955908.zip
Adding common test classes for dialer and contacts.
Bug: 6993891 Change-Id: I4bd6fc38be1723e8f33c88041d0d459d43cac6a5
Diffstat (limited to 'TestCommon')
-rw-r--r--TestCommon/Android.mk28
-rw-r--r--TestCommon/src/com/android/contacts/common/test/FragmentTestActivity.java47
-rw-r--r--TestCommon/src/com/android/contacts/common/test/IntegrationTestUtils.java187
3 files changed, 262 insertions, 0 deletions
diff --git a/TestCommon/Android.mk b/TestCommon/Android.mk
new file mode 100644
index 00000000..77853421
--- /dev/null
+++ b/TestCommon/Android.mk
@@ -0,0 +1,28 @@
+# Copyright 2012, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# This has to be LOCAL_JAVA instead of LOCAL_STATIC since this test util is installed in the same
+# vm as the packages to be tested. Otherwise you will get error
+# "Class ref in pre-verified class resolved to unexpected implementation"
+# when running the unit tests.
+LOCAL_JAVA_LIBRARIES := guava
+
+LOCAL_MODULE := com.android.contacts.common.test
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/TestCommon/src/com/android/contacts/common/test/FragmentTestActivity.java b/TestCommon/src/com/android/contacts/common/test/FragmentTestActivity.java
new file mode 100644
index 00000000..5ae2d956
--- /dev/null
+++ b/TestCommon/src/com/android/contacts/common/test/FragmentTestActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.common.test;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+/**
+ * An activity that is used for testing fragments. A unit test starts this
+ * activity, adds a fragment and then tests the fragment.
+ */
+public class FragmentTestActivity extends Activity {
+
+ public final static int LAYOUT_ID = 1;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Normally fragment/activity onStart() methods will not be called when screen is locked.
+ // Use the following flags to ensure that activities can be show for testing.
+ final Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
+ WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+
+ final FrameLayout layout = new FrameLayout(this);
+ layout.setId(LAYOUT_ID);
+ setContentView(layout);
+ }
+}
diff --git a/TestCommon/src/com/android/contacts/common/test/IntegrationTestUtils.java b/TestCommon/src/com/android/contacts/common/test/IntegrationTestUtils.java
new file mode 100644
index 00000000..060edd15
--- /dev/null
+++ b/TestCommon/src/com/android/contacts/common/test/IntegrationTestUtils.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.common.test;
+
+import static android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP;
+import static android.os.PowerManager.FULL_WAKE_LOCK;
+import static android.os.PowerManager.ON_AFTER_RELEASE;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.PowerManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.google.common.base.Preconditions;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.ThreadSafe;
+
+/** Some utility methods for making integration testing smoother. */
+@ThreadSafe
+public class IntegrationTestUtils {
+ private static final String TAG = "IntegrationTestUtils";
+
+ private final Instrumentation mInstrumentation;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock") private PowerManager.WakeLock mWakeLock;
+
+ public IntegrationTestUtils(Instrumentation instrumentation) {
+ mInstrumentation = instrumentation;
+ }
+
+ /**
+ * Find a view by a given resource id, from the given activity, and click it, iff it is
+ * enabled according to {@link View#isEnabled()}.
+ */
+ public void clickButton(final Activity activity, final int buttonResourceId) throws Throwable {
+ runOnUiThreadAndGetTheResult(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ View view = activity.findViewById(buttonResourceId);
+ Assert.assertNotNull(view);
+ if (view.isEnabled()) {
+ view.performClick();
+ }
+ return null;
+ }
+ });
+ }
+
+ /** Returns the result of running {@link TextView#getText()} on the ui thread. */
+ public CharSequence getText(final TextView view) throws Throwable {
+ return runOnUiThreadAndGetTheResult(new Callable<CharSequence>() {
+ @Override
+ public CharSequence call() {
+ return view.getText();
+ }
+ });
+ }
+
+ // TODO: Move this class and the appropriate documentation into a test library, having checked
+ // first to see if exactly this code already exists or not.
+ /**
+ * Execute a callable on the ui thread, returning its result synchronously.
+ * <p>
+ * Waits for an idle sync on the main thread (see {@link Instrumentation#waitForIdle(Runnable)})
+ * before executing this callable.
+ */
+ public <T> T runOnUiThreadAndGetTheResult(Callable<T> callable) throws Throwable {
+ FutureTask<T> future = new FutureTask<T>(callable);
+ mInstrumentation.waitForIdle(future);
+ try {
+ return future.get();
+ } catch (ExecutionException e) {
+ // Unwrap the cause of the exception and re-throw it.
+ throw e.getCause();
+ }
+ }
+
+ /**
+ * Wake up the screen, useful in tests that want or need the screen to be on.
+ * <p>
+ * This is usually called from setUp() for tests that require it. After calling this method,
+ * {@link #releaseScreenWakeLock()} must be called, this is usually done from tearDown().
+ */
+ public void acquireScreenWakeLock(Context context) {
+ synchronized (mLock) {
+ Preconditions.checkState(mWakeLock == null, "mWakeLock was already held");
+ mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE))
+ .newWakeLock(
+ PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE | PowerManager.FULL_WAKE_LOCK, TAG);
+ mWakeLock.acquire();
+ }
+ }
+
+ /** Release the wake lock previously acquired with {@link #acquireScreenWakeLock(Context)}. */
+ public void releaseScreenWakeLock() {
+ synchronized (mLock) {
+ // We don't use Preconditions to force you to have acquired before release.
+ // This is because we don't want unnecessary exceptions in tearDown() since they'll
+ // typically mask the actual exception that happened during the test.
+ // The other reason is that this method is most likely to be called from tearDown(),
+ // which is invoked within a finally block, so it's not infrequently the case that
+ // the setUp() method fails before getting the lock, at which point we don't want
+ // to fail in tearDown().
+ if (mWakeLock != null) {
+ mWakeLock.release();
+ mWakeLock = null;
+ }
+ }
+ }
+
+ /**
+ * Gets all {@link TextView} objects whose {@link TextView#getText()} contains the given text as
+ * a substring.
+ */
+ public List<TextView> getTextViewsWithString(final Activity activity, final String text)
+ throws Throwable {
+ return runOnUiThreadAndGetTheResult(new Callable<List<TextView>>() {
+ @Override
+ public List<TextView> call() throws Exception {
+ List<TextView> matchingViews = new ArrayList<TextView>();
+ for (TextView textView : getAllViews(TextView.class, getRootView(activity))) {
+ if (textView.getText().toString().contains(text)) {
+ matchingViews.add(textView);
+ }
+ }
+ return matchingViews;
+ }
+ });
+ }
+
+ /** Find the root view for a given activity. */
+ public static View getRootView(Activity activity) {
+ return activity.findViewById(android.R.id.content).getRootView();
+ }
+
+ /**
+ * Gets a list of all views of a given type, rooted at the given parent.
+ * <p>
+ * This method will recurse down through all {@link ViewGroup} instances looking for
+ * {@link View} instances of the supplied class type. Specifically it will use the
+ * {@link Class#isAssignableFrom(Class)} method as the test for which views to add to the list,
+ * so if you provide {@code View.class} as your type, you will get every view. The parent itself
+ * will be included also, should it be of the right type.
+ * <p>
+ * This call manipulates the ui, and as such should only be called from the application's main
+ * thread.
+ */
+ private static <T extends View> List<T> getAllViews(final Class<T> clazz, final View parent) {
+ List<T> results = new ArrayList<T>();
+ if (parent.getClass().equals(clazz)) {
+ results.add(clazz.cast(parent));
+ }
+ if (parent instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) parent;
+ for (int i = 0; i < viewGroup.getChildCount(); ++i) {
+ results.addAll(getAllViews(clazz, viewGroup.getChildAt(i)));
+ }
+ }
+ return results;
+ }
+}