summaryrefslogtreecommitdiffstats
path: root/tests/src/com/android
diff options
context:
space:
mode:
authorPaul Miller <paulmiller@google.com>2015-03-16 17:22:30 -0700
committerPaul Miller <paulmiller@google.com>2015-03-18 13:37:15 -0700
commit2ed4f50286b888c7c366923f35dd0f8e893d255e (patch)
treeb9fb07de8b5fb24c85fcd8fc02d59453f3fc852f /tests/src/com/android
parent01a22a729f76117a9df1767fb484a24813478009 (diff)
downloadandroid_packages_providers_BookmarkProvider-2ed4f50286b888c7c366923f35dd0f8e893d255e.tar.gz
android_packages_providers_BookmarkProvider-2ed4f50286b888c7c366923f35dd0f8e893d255e.tar.bz2
android_packages_providers_BookmarkProvider-2ed4f50286b888c7c366923f35dd0f8e893d255e.zip
Create BrowserProvider
BookmarkProvider is the provider code from the legacy Browser, refactored into its own app. It can be used as a ContentProvider for bookmarks. BUG:19351071 Change-Id: I52a2581b4944859fa91fdc277440855c829c6c3e
Diffstat (limited to 'tests/src/com/android')
-rw-r--r--tests/src/com/android/bookmarkstore/BrowserProviderTests.java163
-rw-r--r--tests/src/com/android/bookmarkstore/tests/BP2ProviderTests.java138
-rw-r--r--tests/src/com/android/bookmarkstore/tests/BookmarksTests.java85
-rw-r--r--tests/src/com/android/bookmarkstore/tests/utils/BP2TestCaseHelper.java99
-rw-r--r--tests/src/com/android/bookmarkstore/tests/utils/MockContentResolver2.java115
-rw-r--r--tests/src/com/android/bookmarkstore/tests/utils/MockObserverNode.java169
-rw-r--r--tests/src/com/android/bookmarkstore/tests/utils/ProviderTestCase3.java186
7 files changed, 955 insertions, 0 deletions
diff --git a/tests/src/com/android/bookmarkstore/BrowserProviderTests.java b/tests/src/com/android/bookmarkstore/BrowserProviderTests.java
new file mode 100644
index 0000000..e746890
--- /dev/null
+++ b/tests/src/com/android/bookmarkstore/BrowserProviderTests.java
@@ -0,0 +1,163 @@
+/*
+ * 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.bookmarkprovider;
+
+import com.android.bookmarkprovider.BookmarkProvider;
+import com.android.bookmarkprovider.tests.utils.ProviderTestCase3;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.BrowserContract;
+import android.provider.BrowserContract.Bookmarks;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link BookmarkProvider}.
+ */
+@MediumTest
+public class BrowserProviderTests extends ProviderTestCase3<BookmarkProvider> {
+
+ private ArrayList<Uri> mDeleteUris;
+
+ public BrowserProviderTests() {
+ super(BookmarkProvider.class,
+ BrowserContract.AUTHORITY, BookmarkProvider.LEGACY_AUTHORITY);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ mDeleteUris = new ArrayList<Uri>();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ for (Uri uri : mDeleteUris) {
+ deleteUri(uri);
+ }
+ super.tearDown();
+ }
+
+ public void testHasDefaultBookmarks() {
+ Cursor c = getBookmarksByPrefix("");
+ try {
+ assertTrue("No default bookmarks", c.getCount() > 0);
+ } finally {
+ c.close();
+ }
+ }
+
+ public void testPartialFirstTitleWord() {
+ assertInsertQuery("http://www.example.com/rasdfe", "nfgjra sdfywe", "nfgj");
+ }
+
+ public void testFullFirstTitleWord() {
+ assertInsertQuery("http://www.example.com/", "nfgjra dfger", "nfgjra");
+ }
+
+ public void testFullFirstTitleWordPartialSecond() {
+ assertInsertQuery("http://www.example.com/", "nfgjra dfger", "nfgjra df");
+ }
+
+ public void testFullTitle() {
+ assertInsertQuery("http://www.example.com/", "nfgjra dfger", "nfgjra dfger");
+ }
+
+ public void testFullTitleJapanese() {
+ String title = "\u30ae\u30e3\u30e9\u30ea\u30fc\u30fcGoogle\u691c\u7d22";
+ assertInsertQuery("http://www.example.com/sdaga", title, title);
+ }
+
+ public void testPartialTitleJapanese() {
+ String title = "\u30ae\u30e3\u30e9\u30ea\u30fc\u30fcGoogle\u691c\u7d22";
+ String query = "\u30ae\u30e3\u30e9\u30ea\u30fc";
+ assertInsertQuery("http://www.example.com/sdaga", title, query);
+ }
+
+ //
+ // Utilities
+ //
+
+ private void assertInsertQuery(String url, String title, String query) {
+ addBookmark(url, title);
+ assertQueryReturns(url, title, query);
+ }
+
+ private void assertQueryReturns(String url, String title, String query) {
+ Cursor c = getBookmarksByPrefix(query);
+ try {
+ assertTrue(title + " not matched by " + query, c.getCount() > 0);
+ assertTrue("More than one result for " + query, c.getCount() == 1);
+ while (c.moveToNext()) {
+ String gotUrl = getCol(c, Bookmarks.URL);
+ assertNotNull(gotUrl);
+ assertEquals("Bad URL", url, gotUrl);
+
+ String gotTitle = getCol(c, Bookmarks.TITLE);
+ assertNotNull(gotTitle);
+ assertEquals("Bad title", title, gotTitle);
+ }
+ } finally {
+ c.close();
+ }
+ }
+
+ private Cursor getBookmarksByPrefix(String query) {
+ Uri suggestUri = Uri.parse("content://browser/bookmarks");
+ String[] selectionArgs = { query + "%" };
+ Cursor c = getMockContentResolver().query(suggestUri, null, "title LIKE ?",
+ selectionArgs, null);
+ assertNotNull(c);
+ return c;
+ }
+
+ private void addBookmark(String url, String title) {
+ Uri uri = insertBookmark(url, title);
+ assertNotNull(uri);
+ assertFalse(android.provider.Browser.BOOKMARKS_URI.equals(uri));
+ mDeleteUris.add(uri);
+ }
+
+ private Uri insertBookmark(String url, String title) {
+ ContentValues values = new ContentValues();
+ values.put("title", title);
+ values.put("url", url);
+ values.put("visits", 0);
+ values.put("date", 0);
+ values.put("created", 0);
+ values.put("bookmark", 1);
+ return getMockContentResolver().insert(android.provider.Browser.BOOKMARKS_URI,
+ values);
+ }
+
+ private void deleteUri(Uri uri) {
+ int count = getMockContentResolver().delete(uri, null, null);
+ assertEquals("Failed to delete " + uri, 1, count);
+ }
+
+ private static String getCol(Cursor c, String name) {
+ int col = c.getColumnIndex(name);
+ String msg = "Column " + name + " not found, columns: "
+ + Arrays.toString(c.getColumnNames());
+ assertTrue(msg, col >= 0);
+ return c.getString(col);
+ }
+}
diff --git a/tests/src/com/android/bookmarkstore/tests/BP2ProviderTests.java b/tests/src/com/android/bookmarkstore/tests/BP2ProviderTests.java
new file mode 100644
index 0000000..ff31109
--- /dev/null
+++ b/tests/src/com/android/bookmarkstore/tests/BP2ProviderTests.java
@@ -0,0 +1,138 @@
+/*
+ * 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;
+
+import com.android.bookmarkprovider.tests.utils.BP2TestCaseHelper;
+
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.net.Uri;
+import android.provider.BrowserContract;
+import android.provider.BrowserContract.Images;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.ByteArrayOutputStream;
+
+@SmallTest
+public class BP2ProviderTests extends BP2TestCaseHelper {
+
+ static final String[] PROJECTION = new String[] {
+ BrowserContract.Bookmarks.PARENT,
+ BrowserContract.Bookmarks.ACCOUNT_NAME,
+ BrowserContract.Bookmarks.ACCOUNT_TYPE,
+ };
+ static final int INDEX_PARENT = 0;
+ static final int INDEX_ACCOUNT_NAME = 1;
+ static final int INDEX_ACCOUNT_TYPE = 2;
+
+ public void testUpdateImage() {
+ String url = "http://stub1.com";
+ insertBookmark(url, "stub 1");
+ ContentValues values = new ContentValues();
+ values.put(Images.URL, url);
+ Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
+ values.put(Images.THUMBNAIL, os.toByteArray());
+ // Use updateBookmarks because the bookmarks URI observer should
+ // be triggered, even though we aren't giving it a bookmarks URI
+ assertTrue(updateBookmark(Images.CONTENT_URI, values));
+ }
+
+ public void testIsValidParentNullAccount() {
+ doTestIsValidParent(null, null);
+ }
+
+ public void testIsValidParentWithAccount() {
+ doTestIsValidParent("test@gmail.com", "com.google");
+ }
+
+ private void doTestIsValidParent(String accountName, String accountType) {
+ // Create the folder
+ ContentValues values = new ContentValues();
+ values.put(BrowserContract.Bookmarks.TITLE, "New Folder");
+ values.put(BrowserContract.Bookmarks.IS_FOLDER, 1);
+ values.put(BrowserContract.Bookmarks.ACCOUNT_NAME, accountName);
+ values.put(BrowserContract.Bookmarks.ACCOUNT_TYPE, accountType);
+ Uri folderUri = insertBookmark(values);
+ assertNotNull(folderUri);
+ long folderId = ContentUris.parseId(folderUri);
+ assertTrue("Failed to parse folder id!", folderId > 0);
+ // Insert a bookmark with the same ACCOUNT_* info as parent
+ values.put(BrowserContract.Bookmarks.TITLE, "google");
+ values.put(BrowserContract.Bookmarks.URL, "http://google.com");
+ values.put(BrowserContract.Bookmarks.IS_FOLDER, 0);
+ values.put(BrowserContract.Bookmarks.PARENT, folderId);
+ Uri insertedUri = insertBookmark(values);
+ assertNotNull(insertedUri);
+ Cursor c = getMockContentResolver().query(insertedUri,
+ PROJECTION, null, null, null);
+ try {
+ assertNotNull(c);
+ assertTrue(c.moveToFirst());
+ long insertedParentId = c.getLong(INDEX_PARENT);
+ String insertedAccountName = c.getString(INDEX_ACCOUNT_NAME);
+ String insertedAccountType = c.getString(INDEX_ACCOUNT_TYPE);
+ assertEquals(folderId, insertedParentId);
+ assertEquals(accountName, insertedAccountName);
+ assertEquals(accountType, insertedAccountType);
+
+ // Insert a bookmark with no ACCOUNT_* set, BUT with a valid parent
+ // The inserted should end up with the ACCOUNT_* of the parent
+ values.remove(BrowserContract.Bookmarks.ACCOUNT_NAME);
+ values.remove(BrowserContract.Bookmarks.ACCOUNT_TYPE);
+ insertedUri = insertBookmark(values);
+ assertNotNull(insertedUri);
+ c.close();
+ c = getMockContentResolver().query(insertedUri,
+ PROJECTION, null, null, null);
+ assertNotNull(c);
+ assertTrue(c.moveToFirst());
+ insertedParentId = c.getLong(INDEX_PARENT);
+ insertedAccountName = c.getString(INDEX_ACCOUNT_NAME);
+ insertedAccountType = c.getString(INDEX_ACCOUNT_TYPE);
+ assertEquals(folderId, insertedParentId);
+ assertEquals(accountName, insertedAccountName);
+ assertEquals(accountType, insertedAccountType);
+
+ // Insert a bookmark with a different ACCOUNT_* than it's parent
+ // ACCOUNT_* should override parent
+ accountName = accountName + "@something.else";
+ accountType = "com.google";
+ values.put(BrowserContract.Bookmarks.ACCOUNT_NAME, accountName);
+ values.put(BrowserContract.Bookmarks.ACCOUNT_TYPE, accountType);
+ insertedUri = insertBookmark(values);
+ assertNotNull(insertedUri);
+ c.close();
+ c = getMockContentResolver().query(insertedUri,
+ PROJECTION, null, null, null);
+ assertNotNull(c);
+ assertTrue(c.moveToFirst());
+ insertedParentId = c.getLong(INDEX_PARENT);
+ insertedAccountName = c.getString(INDEX_ACCOUNT_NAME);
+ insertedAccountType = c.getString(INDEX_ACCOUNT_TYPE);
+ assertNotSame(folderId, insertedParentId);
+ assertEquals(accountName, insertedAccountName);
+ assertEquals(accountType, insertedAccountType);
+ } finally {
+ c.close();
+ }
+ }
+}
diff --git a/tests/src/com/android/bookmarkstore/tests/BookmarksTests.java b/tests/src/com/android/bookmarkstore/tests/BookmarksTests.java
new file mode 100644
index 0000000..e6a6b90
--- /dev/null
+++ b/tests/src/com/android/bookmarkstore/tests/BookmarksTests.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import com.android.bookmarkprovider.tests.utils.BP2TestCaseHelper;
+
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.provider.BrowserContract.Combined;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Extends from BP2TestCaseHelper for the helper methods
+ * and to get the mock database
+ */
+@SmallTest
+public class BookmarksTests extends BP2TestCaseHelper {
+ private static final String QUERY_BOOKMARKS_WHERE =
+ Combined.URL + " == ? OR " +
+ Combined.URL + " == ?";
+
+ private static Cursor queryCombinedForUrl(ContentResolver cr,
+ String originalUrl, String url) {
+ if (cr == null || url == null) {
+ return null;
+ }
+
+ // If originalUrl is null, just set it to url.
+ if (originalUrl == null) {
+ originalUrl = url;
+ }
+
+ // Look for both the original url and the actual url. This takes in to
+ // account redirects.
+
+ final String[] selArgs = new String[] { originalUrl, url };
+ final String[] projection = new String[] { Combined.URL };
+ return cr.query(Combined.CONTENT_URI, projection, QUERY_BOOKMARKS_WHERE, selArgs, null);
+ }
+
+ public void testQueryCombinedForUrl() {
+ // First, add some bookmarks
+ assertNotNull(insertBookmark(
+ "http://google.com/search?q=test", "Test search"));
+ assertNotNull(insertBookmark(
+ "http://google.com/search?q=mustang", "Mustang search"));
+ assertNotNull(insertBookmark(
+ "http://google.com/search?q=aliens", "Aliens search"));
+ ContentResolver cr = getMockContentResolver();
+
+ Cursor c = null;
+ try {
+ // First, search for a match
+ String url = "http://google.com/search?q=test";
+ c = queryCombinedForUrl(cr, null, url);
+ assertEquals(1, c.getCount());
+ assertTrue(c.moveToFirst());
+ assertEquals(url, c.getString(0));
+ c.close();
+
+ // Next, search for no match
+ url = "http://google.com/search";
+ c = queryCombinedForUrl(cr, null, url);
+ assertEquals(0, c.getCount());
+ assertFalse(c.moveToFirst());
+ c.close();
+ } finally {
+ if (c != null) c.close();
+ }
+ }
+}
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);
+ }
+
+}