OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.bookmarkimport; |
| 6 |
| 7 import android.content.ContentValues; |
| 8 import android.content.Context; |
| 9 import android.database.Cursor; |
| 10 import android.database.MatrixCursor; |
| 11 import android.net.Uri; |
| 12 import android.provider.Browser.BookmarkColumns; |
| 13 import android.test.mock.MockContentProvider; |
| 14 import android.test.mock.MockContentResolver; |
| 15 import android.test.suitebuilder.annotation.MediumTest; |
| 16 import android.util.Log; |
| 17 |
| 18 import org.chromium.base.test.util.Feature; |
| 19 import org.chromium.chrome.browser.ChromeBrowserProvider; |
| 20 import org.chromium.chrome.test.util.ApplicationData; |
| 21 import org.chromium.chrome.test.util.BookmarkTestUtils; |
| 22 import org.chromium.content.browser.test.NativeLibraryTestBase; |
| 23 import org.chromium.content.browser.test.util.CallbackHelper; |
| 24 |
| 25 import java.util.HashMap; |
| 26 import java.util.HashSet; |
| 27 import java.util.concurrent.TimeoutException; |
| 28 |
| 29 /** |
| 30 * Tests importing bookmarks from Android Browser. |
| 31 */ |
| 32 public class AndroidBrowserImporterTest extends NativeLibraryTestBase { |
| 33 private static final String TAG = "BookmarkImporterTest"; |
| 34 |
| 35 private static final String PUBLIC_PROVIDER = "browser"; |
| 36 |
| 37 private static final String IS_BOOKMARK = "bookmark=1"; |
| 38 private static final String HAS_URL = "url=?"; |
| 39 private static final String BOOKMARK_MATCHES = IS_BOOKMARK + " AND " |
| 40 + BookmarkColumns.URL + "=? AND " + BookmarkColumns.TITLE + "=?"; |
| 41 |
| 42 private static final String[] COLUMN_NAMES = new String[] { |
| 43 BookmarkColumns.BOOKMARK, |
| 44 BookmarkColumns.URL, |
| 45 BookmarkColumns.TITLE, |
| 46 BookmarkColumns.DATE, |
| 47 BookmarkColumns.CREATED, |
| 48 BookmarkColumns.VISITS, |
| 49 BookmarkColumns.FAVICON |
| 50 }; |
| 51 |
| 52 // Bookmark source to mock. |
| 53 private enum BookmarksSource { |
| 54 NONE, |
| 55 PUBLIC_API |
| 56 } |
| 57 |
| 58 // Data of the mock bookmarks used for testing. |
| 59 private static class MockBookmark { |
| 60 public boolean isFolder; |
| 61 public String url; |
| 62 public String title; |
| 63 public Long lastVisit; |
| 64 public Long created; |
| 65 public Long visits; |
| 66 public byte[] favicon; |
| 67 |
| 68 public MockBookmark() {} |
| 69 |
| 70 public MockBookmark(boolean isFolder, String url, String title, Long las
tVisit, |
| 71 Long created, Long visits, byte[] favicon) { |
| 72 this.isFolder = isFolder; |
| 73 this.url = url; |
| 74 this.title = title; |
| 75 this.lastVisit = lastVisit; |
| 76 this.created = created; |
| 77 this.visits = visits; |
| 78 this.favicon = favicon; |
| 79 } |
| 80 } |
| 81 |
| 82 private boolean mImportSucceeded; |
| 83 |
| 84 @Override |
| 85 public void tearDown() throws Exception { |
| 86 super.tearDown(); |
| 87 ApplicationData.clearAppData(getInstrumentation().getTargetContext()); |
| 88 } |
| 89 |
| 90 @Override |
| 91 public void setUp() { |
| 92 loadNativeLibraryAndInitBrowserProcess(); |
| 93 } |
| 94 |
| 95 private AndroidBrowserImporter getBookmarkImporter(MockBookmark[] mockBookma
rks, |
| 96 BookmarksSource source) { |
| 97 AndroidBrowserImporter importer = |
| 98 new AndroidBrowserImporter(getInstrumentation().getTargetContext
()); |
| 99 importer.setInputResolver(createMockResolver(mockBookmarks, source)); |
| 100 if (source != BookmarksSource.NONE) { |
| 101 importer.setIgnoreAvailableProvidersForTestPurposes(true); |
| 102 } |
| 103 return importer; |
| 104 } |
| 105 |
| 106 private boolean importNewBookmarks(MockBookmark[] mockBookmarks, BookmarksSo
urce source) |
| 107 throws InterruptedException { |
| 108 BookmarkImporter importer = getBookmarkImporter(mockBookmarks, source); |
| 109 |
| 110 // Note: the UI doesn't require any new bookmarks to consider the import
as successful. |
| 111 // For testing purposes we do. |
| 112 final CallbackHelper importFinishedEvent = new CallbackHelper(); |
| 113 importer.importBookmarks(new BookmarkImporter.OnBookmarksImportedListene
r() { |
| 114 @Override |
| 115 public void onBookmarksImported(BookmarkImporter.ImportResults resul
ts) { |
| 116 mImportSucceeded = results != null && results.newBookmarks > 0 |
| 117 && results.numImported == results.newBookmarks; |
| 118 importFinishedEvent.notifyCalled(); |
| 119 } |
| 120 }); |
| 121 try { |
| 122 importFinishedEvent.waitForCallback(0); |
| 123 } catch (TimeoutException e) { |
| 124 fail("Never received import finished event"); |
| 125 } |
| 126 return mImportSucceeded; |
| 127 } |
| 128 |
| 129 private int countImportedNonFolderBookmarks() { |
| 130 Cursor cursor = getInstrumentation().getTargetContext().getContentResolv
er().query( |
| 131 ChromeBrowserProvider.getBookmarksApiUri(getInstrumentation().ge
tTargetContext()), |
| 132 null, IS_BOOKMARK, null, null); |
| 133 int count = cursor.getCount(); |
| 134 cursor.close(); |
| 135 return count; |
| 136 } |
| 137 |
| 138 // TODO(leandrogracia): add support for hierarchical matching. This is likel
y to require changes |
| 139 // in ChromeBrowserProvider that should be addressed by a later patch. |
| 140 private boolean matchFlattenedImportedBookmarks(MockBookmark[] mockBookmarks
) { |
| 141 Cursor cursor = getInstrumentation().getTargetContext().getContentResolv
er().query( |
| 142 ChromeBrowserProvider.getBookmarksApiUri(getInstrumentation().ge
tTargetContext()), |
| 143 null, IS_BOOKMARK, null, null); |
| 144 if (mockBookmarks == null && cursor == null) return true; |
| 145 |
| 146 // Read all the imports to avoid problems with their order. |
| 147 HashMap<String, MockBookmark> importedBookmarks = new HashMap<String, Mo
ckBookmark>(); |
| 148 assertTrue(cursor != null); |
| 149 while (cursor.moveToNext()) { |
| 150 MockBookmark bookmark = new MockBookmark(); |
| 151 int index = cursor.getColumnIndex(BookmarkColumns.URL); |
| 152 if (index != -1 && !cursor.isNull(index)) bookmark.url = cursor.getS
tring(index); |
| 153 |
| 154 index = cursor.getColumnIndex(BookmarkColumns.TITLE); |
| 155 if (index != -1 && !cursor.isNull(index)) bookmark.title = cursor.ge
tString(index); |
| 156 |
| 157 index = cursor.getColumnIndex(BookmarkColumns.CREATED); |
| 158 if (index != -1 && !cursor.isNull(index)) bookmark.created = cursor.
getLong(index); |
| 159 |
| 160 index = cursor.getColumnIndex(BookmarkColumns.DATE); |
| 161 if (index != -1 && !cursor.isNull(index)) bookmark.lastVisit = curso
r.getLong(index); |
| 162 |
| 163 index = cursor.getColumnIndex(BookmarkColumns.VISITS); |
| 164 if (index != -1 && !cursor.isNull(index)) bookmark.visits = cursor.g
etLong(index); |
| 165 |
| 166 index = cursor.getColumnIndex(BookmarkColumns.FAVICON); |
| 167 if (index != -1 && !cursor.isNull(index)) bookmark.favicon = cursor.
getBlob(index); |
| 168 |
| 169 // URLs should be unique in our model. |
| 170 assertFalse(importedBookmarks.containsKey(bookmark.url)); |
| 171 importedBookmarks.put(bookmark.url, bookmark); |
| 172 } |
| 173 cursor.close(); |
| 174 |
| 175 // Auxiliary class to get bookmark mismatch errors. |
| 176 class BookmarkMatchingException extends Exception { |
| 177 public BookmarkMatchingException(String message) { |
| 178 super(message); |
| 179 } |
| 180 } |
| 181 |
| 182 HashSet<String> matchingBookmarks = new HashSet<String>(); |
| 183 final long now = System.currentTimeMillis(); |
| 184 try { |
| 185 for (MockBookmark expected : mockBookmarks) { |
| 186 // Folders are not returned by our provider (not part of the pub
lic API yet). |
| 187 if (expected.isFolder) continue; |
| 188 |
| 189 // Matching can't be performed if the expectation doesn't have a
URL. |
| 190 if (expected.url == null) { |
| 191 throw new BookmarkMatchingException("Expected bookmark witho
ut a URL found."); |
| 192 } |
| 193 |
| 194 // Get the corresponding imported bookmark by its URL. If multip
le entries in the |
| 195 // mock bookmarks with the same URL are found, all but the first
will be skipped. |
| 196 if (matchingBookmarks.contains(expected.url)) continue; |
| 197 |
| 198 MockBookmark imported = importedBookmarks.get(expected.url); |
| 199 if (imported == null) { |
| 200 throw new BookmarkMatchingException("Bookmark with URL " + e
xpected.url |
| 201 + " not found"); |
| 202 } |
| 203 |
| 204 // Imported data must have a valid title despite what the expect
ation says. |
| 205 if (imported.title == null) { |
| 206 throw new BookmarkMatchingException("Bookmark without title
found: " |
| 207 + imported.url); |
| 208 } else if (!imported.title.equals(expected.title)) { |
| 209 throw new BookmarkMatchingException("Title doesn't match: "
+ expected.title |
| 210 + " != " + imported.title); |
| 211 } |
| 212 |
| 213 // If not explicitely set in the expectations, the creation date
should be available |
| 214 // after importing with a value not in the future. |
| 215 if (expected.created != null) { |
| 216 if (!expected.created.equals(imported.created)) { |
| 217 throw new BookmarkMatchingException("Creation timestamp
doesn't match: " |
| 218 + expected.created.toString() + " != " |
| 219 + (imported.created != null ? imported.created.t
oString() |
| 220 : "null")); |
| 221 } |
| 222 } else { |
| 223 if (imported.created == null) { |
| 224 throw new BookmarkMatchingException("Creation date not i
nitialised."); |
| 225 } else if (imported.created.longValue() > now) { |
| 226 throw new BookmarkMatchingException("Creation set in the
future"); |
| 227 } |
| 228 } |
| 229 |
| 230 // If not explicitely set in the expectations, the last visit sh
ould be available |
| 231 // after importing with a value not in the future. |
| 232 if (expected.lastVisit != null) { |
| 233 if (!expected.lastVisit.equals(imported.lastVisit)) { |
| 234 throw new BookmarkMatchingException("Last visit timestam
p doesn't match: " |
| 235 + expected.lastVisit.toString() + " != " |
| 236 + (imported.lastVisit != null ? imported.lastVis
it.toString() |
| 237 : "null")); |
| 238 } |
| 239 } else { |
| 240 if (imported.lastVisit == null) { |
| 241 throw new BookmarkMatchingException("Last visit date not
initialised."); |
| 242 } else if (imported.lastVisit.longValue() > now) { |
| 243 throw new BookmarkMatchingException("Last visit set in t
he future"); |
| 244 } |
| 245 } |
| 246 |
| 247 // Visits should be 1 if not explicitly set in the mock bookmark
. |
| 248 if (expected.visits != null) { |
| 249 if (!expected.visits.equals(imported.visits)) { |
| 250 throw new BookmarkMatchingException("Number of visits do
esn't match: " |
| 251 + expected.visits.toString() + " != " |
| 252 + (imported.visits != null ? imported.visits.toS
tring() : "null")); |
| 253 } |
| 254 } else { |
| 255 if (imported.visits == null) { |
| 256 throw new BookmarkMatchingException("Visit count not ini
tialised."); |
| 257 } else if (imported.visits.longValue() != 0) { |
| 258 throw new BookmarkMatchingException("Invalid visit count
initialization"); |
| 259 } |
| 260 } |
| 261 |
| 262 // If set, the favicons should be binary equals. |
| 263 if (!BookmarkTestUtils.byteArrayEqual(expected.favicon, imported
.favicon)) { |
| 264 throw new BookmarkMatchingException("Favicon doesn't match")
; |
| 265 } |
| 266 |
| 267 matchingBookmarks.add(expected.url); |
| 268 } |
| 269 |
| 270 // At the end the map and the set should have the same size. |
| 271 if (importedBookmarks.size() != matchingBookmarks.size()) { |
| 272 throw new BookmarkMatchingException( |
| 273 "Not match could be found for all imported bookmarks: " |
| 274 + matchingBookmarks.size() + " matched, should be " |
| 275 + importedBookmarks.size()); |
| 276 } |
| 277 } catch (BookmarkMatchingException e) { |
| 278 Log.w(TAG, e.getMessage()); |
| 279 return false; |
| 280 } |
| 281 |
| 282 return true; |
| 283 } |
| 284 |
| 285 private void internalTestBookmarkFields(BookmarksSource source) throws Inter
ruptedException { |
| 286 // Load a favicon for testing. |
| 287 byte[] favicon = BookmarkTestUtils.getIcon("chrome/test/data/android/fav
icon.png"); |
| 288 assertTrue(favicon != null); |
| 289 |
| 290 // Create mock bookmark data to import. Test all non-hierarchy fields. |
| 291 final long now = System.currentTimeMillis(); |
| 292 MockBookmark[] mockBookmarks = new MockBookmark[] { |
| 293 new MockBookmark(false, "http://www.google.com/", "Google", Long.val
ueOf(now), Long.valueOf(now - 100 * 60 * 60), |
| 294 Long.valueOf(100), favicon), |
| 295 new MockBookmark(false, "http://maps.google.com/", "Google Maps", Lo
ng.valueOf(now - 10 * 60), Long.valueOf(now - 5 * 60 * 60), |
| 296 Long.valueOf(20), null), |
| 297 new MockBookmark(false, "http://mail.google.com/", "Google Mail", nu
ll, null, |
| 298 null, null) |
| 299 }; |
| 300 |
| 301 // Import bookmarks and match the contents. |
| 302 assertTrue(importNewBookmarks(mockBookmarks, source)); |
| 303 assertTrue(matchFlattenedImportedBookmarks(mockBookmarks)); |
| 304 } |
| 305 |
| 306 private void internalTestIncompleteBookmarks(BookmarksSource source) |
| 307 throws InterruptedException { |
| 308 // Create incomplete mock bookmark data. |
| 309 MockBookmark[] mockBookmarks = new MockBookmark[] { |
| 310 new MockBookmark(false, "http://www.google.com/", null, null, null,
null, null), |
| 311 new MockBookmark(false, null, "Google Maps", null, null, null, null) |
| 312 }; |
| 313 |
| 314 // Should fail importing bookmarks. |
| 315 assertFalse(importNewBookmarks(mockBookmarks, source)); |
| 316 } |
| 317 |
| 318 private void internalTestImportExisting(BookmarksSource source) throws Inter
ruptedException { |
| 319 // One simple mock bookmark. |
| 320 MockBookmark[] mockBookmarks = new MockBookmark[] { |
| 321 new MockBookmark(false, "http://mail.google.com/", "Google Mail", nu
ll, null, null, |
| 322 null) |
| 323 }; |
| 324 |
| 325 // Import bookmarks. There should only be one imported. |
| 326 assertTrue(importNewBookmarks(mockBookmarks, source)); |
| 327 assertEquals(1, countImportedNonFolderBookmarks()); |
| 328 |
| 329 // Import the same bookmarks again. It should fail becase there aren't a
ny new bookmarks. |
| 330 assertFalse(importNewBookmarks(mockBookmarks, source)); |
| 331 assertEquals(1, countImportedNonFolderBookmarks()); |
| 332 |
| 333 // Let's try adding something else. |
| 334 MockBookmark[] mockBookmarksExtra = new MockBookmark[] { |
| 335 new MockBookmark(false, "http://mail.google.com/", "Google Mail", nu
ll, null, null, |
| 336 null), |
| 337 new MockBookmark(false, "http://maps.google.com/", "Google Maps", nu
ll, null, null, |
| 338 null) |
| 339 }; |
| 340 |
| 341 // The new bookmark should have been added. |
| 342 assertTrue(importNewBookmarks(mockBookmarksExtra, source)); |
| 343 assertEquals(2, countImportedNonFolderBookmarks()); |
| 344 } |
| 345 |
| 346 private void internalTestNoBookmarks(BookmarksSource source) throws Interrup
tedException { |
| 347 MockBookmark[] mockBookmarks = new MockBookmark[] {}; |
| 348 assertFalse(importNewBookmarks(mockBookmarks, source)); |
| 349 } |
| 350 |
| 351 @MediumTest |
| 352 @Feature({"Bookmarks", "Import"}) |
| 353 public void testBookmarkFieldsFromPublicAPI() throws InterruptedException { |
| 354 internalTestBookmarkFields(BookmarksSource.PUBLIC_API); |
| 355 } |
| 356 |
| 357 @MediumTest |
| 358 @Feature({"Bookmarks", "Import"}) |
| 359 public void testIncompleteBookmarksFromPublicAPI() throws InterruptedExcepti
on { |
| 360 internalTestIncompleteBookmarks(BookmarksSource.PUBLIC_API); |
| 361 } |
| 362 |
| 363 @MediumTest |
| 364 @Feature({"Bookmarks", "Import"}) |
| 365 public void testImportExistingFromPublicAPI() throws InterruptedException { |
| 366 internalTestImportExisting(BookmarksSource.PUBLIC_API); |
| 367 } |
| 368 |
| 369 @MediumTest |
| 370 @Feature({"Bookmarks", "Import"}) |
| 371 public void testNoBookmarksInPublicAPI() throws InterruptedException { |
| 372 internalTestNoBookmarks(BookmarksSource.PUBLIC_API); |
| 373 } |
| 374 |
| 375 @MediumTest |
| 376 @Feature({"Bookmarks", "Import"}) |
| 377 public void testBookmarksAreAccessible() { |
| 378 MockBookmark[] mockBookmarks = new MockBookmark[] { |
| 379 new MockBookmark(false, "http://www.google.com/", "Google", null, nu
ll, null, null), |
| 380 }; |
| 381 |
| 382 // Should not be accessible if no provider is reachable. |
| 383 assertFalse(getBookmarkImporter(mockBookmarks, BookmarksSource.NONE) |
| 384 .areBookmarksAccessible()); |
| 385 |
| 386 // Should be accessible in all other cases. |
| 387 assertTrue(getBookmarkImporter(mockBookmarks, BookmarksSource.PUBLIC_API
) |
| 388 .areBookmarksAccessible()); |
| 389 } |
| 390 |
| 391 @MediumTest |
| 392 @Feature({"Bookmarks", "Import"}) |
| 393 public void testTimestampCorrection() throws InterruptedException { |
| 394 // Set the past and the future 1 hour away from now. |
| 395 final long lapse = 3600000; |
| 396 final Long now = Long.valueOf(System.currentTimeMillis()); |
| 397 final Long past = Long.valueOf(Math.max(now.longValue() - lapse, 0)); |
| 398 final Long future = Long.valueOf(now.longValue() + lapse); |
| 399 |
| 400 // Setting a maximum of 10 visits. Each visit means a database row |
| 401 // insertion in the provider, so very high values will make the test |
| 402 // fail because of the importing event timeout. |
| 403 final long maxVisits = 10; |
| 404 final Long pastForVisits = Long.valueOf(now.longValue() - maxVisits); |
| 405 final Long visitsValue = Long.valueOf(maxVisits * 100); |
| 406 |
| 407 MockBookmark[] mockBookmarks = new MockBookmark[] { |
| 408 // Last visit is in the future. |
| 409 new MockBookmark(false, "http://www.someweb1.com/", "Foo", future, n
ull, |
| 410 null, null), |
| 411 // Creation date is in the future. |
| 412 new MockBookmark(false, "http://www.someweb2.com/", "Foo", null, fut
ure, |
| 413 null, null), |
| 414 // Creation date after last visit, both valid. |
| 415 new MockBookmark(false, "http://www.someweb3.com/", "Foo", past, now
, |
| 416 null, null), |
| 417 // Invalid number of visits for the lapse between creation and last
visit. |
| 418 new MockBookmark(false, "http://www.someweb4.com/", "Foo", now, past
ForVisits, |
| 419 visitsValue, null), |
| 420 }; |
| 421 |
| 422 // Timestamp correction should be independent to the source. |
| 423 assertTrue(importNewBookmarks(mockBookmarks, BookmarksSource.PUBLIC_API)
); |
| 424 assertEquals(mockBookmarks.length, countImportedNonFolderBookmarks()); |
| 425 assertFalse(matchFlattenedImportedBookmarks(mockBookmarks)); |
| 426 } |
| 427 |
| 428 @MediumTest |
| 429 @Feature({"Bookmarks", "Import"}) |
| 430 public void testVisitCountZeroAdjustment() throws InterruptedException { |
| 431 final Long now = Long.valueOf(System.currentTimeMillis()); |
| 432 |
| 433 MockBookmark[] mockBookmarks = new MockBookmark[] { |
| 434 // Visit count is set to zero (required to be supported by the Brows
erTest CTS). |
| 435 new MockBookmark(false, "http://www.zerovisits.com/", "Foo", now, no
w, |
| 436 0L, null), |
| 437 }; |
| 438 |
| 439 assertTrue(importNewBookmarks(mockBookmarks, BookmarksSource.PUBLIC_API)
); |
| 440 assertEquals(mockBookmarks.length, countImportedNonFolderBookmarks()); |
| 441 // The imported bookmark should differ from mockBookmarks as visit count
was ignored. |
| 442 assertFalse(matchFlattenedImportedBookmarks(mockBookmarks)); |
| 443 } |
| 444 |
| 445 @MediumTest |
| 446 @Feature({"Bookmarks", "Import"}) |
| 447 public void testVisitCountOneAdjustment() throws InterruptedException { |
| 448 final Long now = Long.valueOf(System.currentTimeMillis()); |
| 449 |
| 450 MockBookmark[] mockBookmarks = new MockBookmark[] { |
| 451 // Visit count is set to one (will be ignored). |
| 452 // See http://crbug.com/149376 for more details. |
| 453 new MockBookmark(false, "http://www.onevisit.com/", "Foo", now, now, |
| 454 1L, null), |
| 455 }; |
| 456 |
| 457 assertTrue(importNewBookmarks(mockBookmarks, BookmarksSource.PUBLIC_API)
); |
| 458 assertEquals(mockBookmarks.length, countImportedNonFolderBookmarks()); |
| 459 assertTrue(matchFlattenedImportedBookmarks(mockBookmarks)); |
| 460 } |
| 461 |
| 462 @MediumTest |
| 463 @Feature({"Bookmarks", "Import"}) |
| 464 public void testVisitCountTwoAdjustment() throws InterruptedException { |
| 465 final Long now = Long.valueOf(System.currentTimeMillis()); |
| 466 |
| 467 MockBookmark[] mockBookmarks = new MockBookmark[] { |
| 468 // Visit count is set to one (will be ignored). |
| 469 // See http://crbug.com/149376 for more details. |
| 470 new MockBookmark(false, "http://www.onevisit.com/", "Foo", now + 100
, now, |
| 471 1L, null), |
| 472 }; |
| 473 |
| 474 assertTrue(importNewBookmarks(mockBookmarks, BookmarksSource.PUBLIC_API)
); |
| 475 assertEquals(mockBookmarks.length, countImportedNonFolderBookmarks()); |
| 476 // The imported bookmark should differ from mockBookmarks as visit count
was ignored. |
| 477 assertFalse(matchFlattenedImportedBookmarks(mockBookmarks)); |
| 478 } |
| 479 |
| 480 private static class ImportMockContentProvider extends MockContentProvider { |
| 481 private final MockBookmark[] mMockData; |
| 482 private final boolean mFlatten; |
| 483 |
| 484 ImportMockContentProvider(Context context, MockBookmark[] data, boolean
flatten) { |
| 485 super(context); |
| 486 mMockData = data; |
| 487 mFlatten = flatten; |
| 488 } |
| 489 |
| 490 @Override |
| 491 public Cursor query(Uri uri, String[] projection, String selection, |
| 492 String[] selectionArgs, String sortOrder) { |
| 493 // Provide a new cursor with the mock data. |
| 494 MatrixCursor cursor = new MatrixCursor(COLUMN_NAMES); |
| 495 for (MockBookmark bookmark : mMockData) { |
| 496 if (mFlatten && bookmark.isFolder) continue; |
| 497 |
| 498 // There are 3 kinds of queries performed by the iterators: |
| 499 // 1. Retrieving all bookmarks. |
| 500 // 2. Querying a specific URL in history. |
| 501 // 3. Looking for matching bookmarks (url and title) in the publ
ic API. |
| 502 if (selection.equals(HAS_URL)) { |
| 503 assertTrue(selectionArgs != null); |
| 504 assertEquals(1, selectionArgs.length); |
| 505 if (bookmark.url != null && !bookmark.url.equals(selectionAr
gs[0])) { |
| 506 continue; |
| 507 } |
| 508 } else if (selection.equals(BOOKMARK_MATCHES)) { |
| 509 assertTrue(selectionArgs != null); |
| 510 assertEquals(2, selectionArgs.length); |
| 511 if ((bookmark.url != null && !bookmark.url.equals(selectionA
rgs[0])) |
| 512 || (bookmark.title != null |
| 513 && !bookmark.title.equals(selectionArgs[1]))
) { |
| 514 continue; |
| 515 } |
| 516 } |
| 517 |
| 518 cursor.addRow(new Object[] { |
| 519 1, bookmark.url, bookmark.title, bookmark.lastVisit, |
| 520 bookmark.created, bookmark.visits, bookmark.favicon |
| 521 }); |
| 522 |
| 523 // Should there be only one history URL result. No need to look
for more. |
| 524 if (selection.equals(HAS_URL)) break; |
| 525 } |
| 526 cursor.move(0); |
| 527 return cursor; |
| 528 } |
| 529 |
| 530 @Override |
| 531 public Uri insert(Uri uri, ContentValues values) { |
| 532 // Proxy to the original content resolver. |
| 533 return getContext().getContentResolver().insert(uri, values); |
| 534 } |
| 535 } |
| 536 |
| 537 private MockContentResolver createMockResolver(MockBookmark[] mockBookmarks, |
| 538 BookmarksSource source) { |
| 539 MockContentResolver mockResolver = new MockContentResolver(); |
| 540 switch (source) { |
| 541 case NONE: |
| 542 // No provider added. Used to test bookmark availability. |
| 543 break; |
| 544 |
| 545 case PUBLIC_API: |
| 546 mockResolver.addProvider(PUBLIC_PROVIDER, |
| 547 new ImportMockContentProvider(getInstrumentation().getTa
rgetContext(), |
| 548 mockBookmarks, true)); |
| 549 break; |
| 550 } |
| 551 return mockResolver; |
| 552 } |
| 553 } |
OLD | NEW |