diff options
Diffstat (limited to 'tests/src/com/android/bookmarkstore/tests/utils')
4 files changed, 569 insertions, 0 deletions
diff --git a/tests/src/com/android/bookmarkstore/tests/utils/BP2TestCaseHelper.java b/tests/src/com/android/bookmarkstore/tests/utils/BP2TestCaseHelper.java new file mode 100644 index 0000000..57ce669 --- /dev/null +++ b/tests/src/com/android/bookmarkstore/tests/utils/BP2TestCaseHelper.java @@ -0,0 +1,99 @@ +/* + * 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.bookmarkprovider.tests.utils; + +import com.android.bookmarkprovider.BookmarkProvider; + +import java.io.File; +import java.io.FilenameFilter; + +import android.content.ContentValues; +import android.net.Uri; +import android.provider.BrowserContract; +import android.provider.BrowserContract.Bookmarks; + +/** + * This is a replacement for ProviderTestCase2 that can handle notifyChange testing. + * It also has helper methods specifically for testing BookmarkProvider + */ +public abstract class BP2TestCaseHelper extends ProviderTestCase3<BookmarkProvider> { + + // Tag for potential performance impacts + private static final String PERFTAG = "BP2-PerfCheck"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + public BP2TestCaseHelper() { + super(BookmarkProvider.class, + BrowserContract.AUTHORITY, BookmarkProvider.LEGACY_AUTHORITY); + } + + Uri mockInsert(Uri uri, ContentValues values) { + return getMockContentResolver().insert(uri, values); + } + + int mockUpdate(Uri uri, ContentValues values, String where, + String[] selectionArgs) { + return getMockContentResolver().update(uri, values, where, selectionArgs); + } + + public Uri insertBookmark(String url, String title) { + ContentValues values = new ContentValues(); + values.put(BrowserContract.Bookmarks.TITLE, title); + values.put(BrowserContract.Bookmarks.URL, url); + values.put(BrowserContract.Bookmarks.IS_FOLDER, 0); + return insertBookmark(values); + } + + public Uri insertBookmark(ContentValues values) { + return mockInsert(Bookmarks.CONTENT_URI, values); + } + + public boolean updateBookmark(Uri uri, String url, String title) { + ContentValues values = new ContentValues(); + values.put(BrowserContract.Bookmarks.TITLE, title); + values.put(BrowserContract.Bookmarks.URL, url); + return updateBookmark(uri, values); + } + + public boolean updateBookmark(Uri uri, ContentValues values) { + int modifyCount = mockUpdate(uri, values, null, null); + assertTrue("UpdatedBookmark modified too much! " + uri, modifyCount <= 1); + return modifyCount == 1; + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + // Delete the test databases so that subsequent runs have a clean slate + File f = getMockContext().getDatabasePath("test"); + File dir = f.getParentFile(); + File testFiles[] = dir.listFiles(new FilenameFilter() { + + @Override + public boolean accept(File dir, String filename) { + return filename.startsWith(ProviderTestCase3.FILENAME_PREFIX); + } + }); + for (File testFile : testFiles) { + testFile.delete(); + } + } +} diff --git a/tests/src/com/android/bookmarkstore/tests/utils/MockContentResolver2.java b/tests/src/com/android/bookmarkstore/tests/utils/MockContentResolver2.java new file mode 100644 index 0000000..2d91425 --- /dev/null +++ b/tests/src/com/android/bookmarkstore/tests/utils/MockContentResolver2.java @@ -0,0 +1,115 @@ +/* + * 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.bookmarkprovider.tests.utils; + +import com.google.android.collect.Maps; + +import android.content.ContentProvider; +import android.content.ContentResolver; +import android.content.Context; +import android.content.IContentProvider; +import android.database.ContentObserver; +import android.net.Uri; + +import java.util.Map; + +public class MockContentResolver2 extends ContentResolver { + + Map<String, ContentProvider> mProviders; + private final MockObserverNode mRootNode = new MockObserverNode(""); + + /* + * Creates a local map of providers. This map is used instead of the global map when an + * API call tries to acquire a provider. + */ + public MockContentResolver2() { + super(null); + mProviders = Maps.newHashMap(); + } + + /** + * Adds access to a provider based on its authority + * + * @param name The authority name associated with the provider. + * @param provider An instance of {@link android.content.ContentProvider} or one of its + * subclasses, or null. + */ + public void addProvider(String name, ContentProvider provider) { + /* + * Maps the authority to the provider locally. + */ + mProviders.put(name, provider); + } + + /** @hide */ + @Override + protected IContentProvider acquireProvider(Context context, String name) { + return acquireExistingProvider(context, name); + } + + /** @hide */ + @Override + protected IContentProvider acquireExistingProvider(Context context, String name) { + + /* + * Gets the content provider from the local map + */ + final ContentProvider provider = mProviders.get(name); + + if (provider != null) { + return provider.getIContentProvider(); + } else { + return null; + } + } + + /** @hide */ + @Override + public boolean releaseProvider(IContentProvider provider) { + return true; + } + + /** @hide */ + protected IContentProvider acquireUnstableProvider(Context c, String name) { + return acquireProvider(c, name); + } + + /** @hide */ + public boolean releaseUnstableProvider(IContentProvider icp) { + return releaseProvider(icp); + } + + /** @hide */ + public void unstableProviderDied(IContentProvider icp) { + } + + @Override + public void notifyChange(Uri uri, ContentObserver observer, + boolean syncToNetwork) { + mRootNode.notifyMyObservers(uri, 0, observer, false); + } + + public void safeRegisterContentObserver(Uri uri, boolean notifyForDescendents, + ContentObserver observer) { + mRootNode.addObserver(uri, observer, notifyForDescendents); + } + + public void safeUnregisterContentObserver(ContentObserver observer) { + mRootNode.removeObserver(observer); + } + +} diff --git a/tests/src/com/android/bookmarkstore/tests/utils/MockObserverNode.java b/tests/src/com/android/bookmarkstore/tests/utils/MockObserverNode.java new file mode 100644 index 0000000..996b3b3 --- /dev/null +++ b/tests/src/com/android/bookmarkstore/tests/utils/MockObserverNode.java @@ -0,0 +1,169 @@ +/* + * 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.bookmarkprovider.tests.utils; + +import android.database.ContentObserver; +import android.net.Uri; + +import java.util.ArrayList; + +public final class MockObserverNode { + private class MockObserverEntry { + public final ContentObserver observer; + public final boolean notifyForDescendents; + + public MockObserverEntry(ContentObserver o, boolean n) { + observer = o; + notifyForDescendents = n; + } + } + + public static final int INSERT_TYPE = 0; + public static final int UPDATE_TYPE = 1; + public static final int DELETE_TYPE = 2; + + private String mName; + private ArrayList<MockObserverNode> mChildren = new ArrayList<MockObserverNode>(); + private ArrayList<MockObserverEntry> mObservers = new ArrayList<MockObserverEntry>(); + + public MockObserverNode(String name) { + mName = name; + } + + private String getUriSegment(Uri uri, int index) { + if (uri != null) { + if (index == 0) { + return uri.getAuthority(); + } else { + return uri.getPathSegments().get(index - 1); + } + } else { + return null; + } + } + + private int countUriSegments(Uri uri) { + if (uri == null) { + return 0; + } + return uri.getPathSegments().size() + 1; + } + + public void addObserver(Uri uri, ContentObserver observer, + boolean notifyForDescendents) { + addObserver(uri, 0, observer, notifyForDescendents); + } + + private void addObserver(Uri uri, int index, ContentObserver observer, + boolean notifyForDescendents) { + // If this is the leaf node add the observer + if (index == countUriSegments(uri)) { + mObservers.add(new MockObserverEntry(observer, notifyForDescendents)); + return; + } + + // Look to see if the proper child already exists + String segment = getUriSegment(uri, index); + if (segment == null) { + throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer"); + } + int N = mChildren.size(); + for (int i = 0; i < N; i++) { + MockObserverNode node = mChildren.get(i); + if (node.mName.equals(segment)) { + node.addObserver(uri, index + 1, observer, notifyForDescendents); + return; + } + } + + // No child found, create one + MockObserverNode node = new MockObserverNode(segment); + mChildren.add(node); + node.addObserver(uri, index + 1, observer, notifyForDescendents); + } + + public boolean removeObserver(ContentObserver observer) { + int size = mChildren.size(); + for (int i = 0; i < size; i++) { + boolean empty = mChildren.get(i).removeObserver(observer); + if (empty) { + mChildren.remove(i); + i--; + size--; + } + } + + size = mObservers.size(); + for (int i = 0; i < size; i++) { + MockObserverEntry entry = mObservers.get(i); + if (entry.observer == observer) { + mObservers.remove(i); + break; + } + } + + if (mChildren.size() == 0 && mObservers.size() == 0) { + return true; + } + return false; + } + + private void notifyMyObservers(boolean leaf, ContentObserver observer, + boolean selfNotify) { + int N = mObservers.size(); + for (int i = 0; i < N; i++) { + MockObserverEntry entry = mObservers.get(i); + + // Don't notify the observer if it sent the notification and isn't interesed + // in self notifications + if (entry.observer == observer && !selfNotify) { + continue; + } + + // Make sure the observer is interested in the notification + if (leaf || (!leaf && entry.notifyForDescendents)) { + entry.observer.onChange(selfNotify); + } + } + } + + public void notifyMyObservers(Uri uri, int index, ContentObserver observer, + boolean selfNotify) { + String segment = null; + int segmentCount = countUriSegments(uri); + if (index >= segmentCount) { + // This is the leaf node, notify all observers + notifyMyObservers(true, observer, selfNotify); + } else if (index < segmentCount){ + segment = getUriSegment(uri, index); + // Notify any observers at this level who are interested in descendents + notifyMyObservers(false, observer, selfNotify); + } + + int N = mChildren.size(); + for (int i = 0; i < N; i++) { + MockObserverNode node = mChildren.get(i); + if (segment == null || node.mName.equals(segment)) { + // We found the child, + node.notifyMyObservers(uri, index + 1, observer, selfNotify); + if (segment != null) { + break; + } + } + } + } +} diff --git a/tests/src/com/android/bookmarkstore/tests/utils/ProviderTestCase3.java b/tests/src/com/android/bookmarkstore/tests/utils/ProviderTestCase3.java new file mode 100644 index 0000000..f8eb161 --- /dev/null +++ b/tests/src/com/android/bookmarkstore/tests/utils/ProviderTestCase3.java @@ -0,0 +1,186 @@ +/* + * 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.bookmarkprovider.tests.utils; + +import android.content.ContentProvider; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.net.Uri; +import android.test.AndroidTestCase; +import android.test.IsolatedContext; +import android.test.RenamingDelegatingContext; +import android.test.mock.MockContext; + +import java.io.File; + +import android.content.pm.ProviderInfo; + +/** + * Replacement for ProviderTestCase2 that keeps calls to ContentResolver.notifyChanged + * internal to observers registered with ProviderTestCase3.registerContentObserver + */ +public abstract class ProviderTestCase3<T extends ContentProvider> extends AndroidTestCase { + + public static final String FILENAME_PREFIX = "test."; + + private static final String BROWSER_AUTHORITIES = "com.android.browser;browser"; + + Class<T> mProviderClass; + String[] mProviderAuthority; + + private IsolatedContext mProviderContext; + private MockContentResolver2 mResolver; + + private class MockContext2 extends MockContext { + + @Override + public Resources getResources() { + return getContext().getResources(); + } + + @Override + public File getDir(String name, int mode) { + // name the directory so the directory will be separated from + // one created through the regular Context + return getContext().getDir("mockcontext2_" + name, mode); + } + + @Override + public String getPackageName() { + return getContext().getPackageName(); + } + + @Override + public SharedPreferences getSharedPreferences(String name, int mode) { + return getContext().getSharedPreferences("mockcontext2_" + name, mode); + } + + @Override + public Context getApplicationContext() { + return this; + } + + @Override + public Object getSystemService(String name) { + return null; + } + } + /** + * Constructor. + * + * @param providerClass The class name of the provider under test + * @param providerAuthorities The provider's authority string + */ + public ProviderTestCase3(Class<T> providerClass, String... providerAuthorities) { + mProviderClass = providerClass; + mProviderAuthority = providerAuthorities; + } + + private T mProvider; + + /** + * Returns the content provider created by this class in the {@link #setUp()} method. + * @return T An instance of the provider class given as a parameter to the test case class. + */ + public T getProvider() { + return mProvider; + } + + /** + * Sets up the environment for the test fixture. + * <p> + * Creates a new + * {@link com.android.bookmarkprovider.tests.utils.MockContentResolver2}, a new IsolatedContext + * that isolates the provider's file operations, and a new instance of + * the provider under test within the isolated environment. + * </p> + * + * @throws Exception + */ + @Override + protected void setUp() throws Exception { + super.setUp(); + + mResolver = new MockContentResolver2(); + RenamingDelegatingContext targetContextWrapper = new + RenamingDelegatingContext( + new MockContext2(), // The context that most methods are + //delegated to + getContext(), // The context that file methods are delegated to + FILENAME_PREFIX); + // The default IsolatedContext has a mock AccountManager that doesn't + // work for us, so override getSystemService to always return null + mProviderContext = new IsolatedContext(mResolver, targetContextWrapper) { + + @Override + public Object getSystemService(String name) { + return null; + } + }; + + mProvider = mProviderClass.newInstance(); + ProviderInfo info = new ProviderInfo(); + info.authority = BROWSER_AUTHORITIES; + mProvider.attachInfoForTesting(mProviderContext, info); + assertNotNull(mProvider); + for (String auth : mProviderAuthority) { + mResolver.addProvider(auth, getProvider()); + } + } + + /** + * Tears down the environment for the test fixture. + * <p> + * Calls {@link android.content.ContentProvider#shutdown()} on the + * {@link android.content.ContentProvider} represented by mProvider. + */ + @Override + protected void tearDown() throws Exception { + mProvider.shutdown(); + super.tearDown(); + } + + /** + * Gets the {@link MockContentResolver2} created by this class during initialization. You + * must use the methods of this resolver to access the provider under test. + * + * @return A {@link MockContentResolver2} instance. + */ + public MockContentResolver2 getMockContentResolver() { + return mResolver; + } + + /** + * Gets the {@link IsolatedContext} created by this class during initialization. + * @return The {@link IsolatedContext} instance + */ + public IsolatedContext getMockContext() { + return mProviderContext; + } + + public void registerContentObserver(Uri uri, boolean notifyForDescendents, + ContentObserver observer) { + mResolver.safeRegisterContentObserver(uri, notifyForDescendents, observer); + } + + public void unregisterContentObserver(ContentObserver observer) { + mResolver.safeUnregisterContentObserver(observer); + } + +} |