Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | package org.mozilla.gecko.tests; |
michael@0 | 6 | |
michael@0 | 7 | import java.util.HashSet; |
michael@0 | 8 | import java.util.Random; |
michael@0 | 9 | import java.util.concurrent.Callable; |
michael@0 | 10 | |
michael@0 | 11 | import org.mozilla.gecko.db.BrowserContract; |
michael@0 | 12 | import org.mozilla.gecko.db.BrowserContract.ReadingListItems; |
michael@0 | 13 | import org.mozilla.gecko.db.ReadingListProvider; |
michael@0 | 14 | |
michael@0 | 15 | import android.content.ContentProvider; |
michael@0 | 16 | import android.content.ContentUris; |
michael@0 | 17 | import android.content.ContentValues; |
michael@0 | 18 | import android.database.Cursor; |
michael@0 | 19 | import android.database.sqlite.SQLiteDatabase; |
michael@0 | 20 | import android.net.Uri; |
michael@0 | 21 | |
michael@0 | 22 | public class testReadingListProvider extends ContentProviderTest { |
michael@0 | 23 | |
michael@0 | 24 | private static final String DB_NAME = "browser.db"; |
michael@0 | 25 | |
michael@0 | 26 | // List of tests to be run sorted by dependency. |
michael@0 | 27 | private final TestCase[] TESTS_TO_RUN = { new TestInsertItems(), |
michael@0 | 28 | new TestDeleteItems(), |
michael@0 | 29 | new TestUpdateItems(), |
michael@0 | 30 | new TestBatchOperations(), |
michael@0 | 31 | new TestBrowserProviderNotifications() }; |
michael@0 | 32 | |
michael@0 | 33 | // Columns used to test for item equivalence. |
michael@0 | 34 | final String[] TEST_COLUMNS = { ReadingListItems.TITLE, |
michael@0 | 35 | ReadingListItems.URL, |
michael@0 | 36 | ReadingListItems.EXCERPT, |
michael@0 | 37 | ReadingListItems.LENGTH, |
michael@0 | 38 | ReadingListItems.DATE_CREATED }; |
michael@0 | 39 | |
michael@0 | 40 | // Indicates that insertions have been tested. ContentProvider.insert |
michael@0 | 41 | // has been proven to work. |
michael@0 | 42 | private boolean mContentProviderInsertTested = false; |
michael@0 | 43 | |
michael@0 | 44 | // Indicates that updates have been tested. ContentProvider.update |
michael@0 | 45 | // has been proven to work. |
michael@0 | 46 | private boolean mContentProviderUpdateTested = false; |
michael@0 | 47 | |
michael@0 | 48 | /** |
michael@0 | 49 | * Factory function that makes new ReadingListProvider instances. |
michael@0 | 50 | * <p> |
michael@0 | 51 | * We want a fresh provider each test, so this should be invoked in |
michael@0 | 52 | * <code>setUp</code> before each individual test. |
michael@0 | 53 | */ |
michael@0 | 54 | private static Callable<ContentProvider> sProviderFactory = new Callable<ContentProvider>() { |
michael@0 | 55 | @Override |
michael@0 | 56 | public ContentProvider call() { |
michael@0 | 57 | return new ReadingListProvider(); |
michael@0 | 58 | } |
michael@0 | 59 | }; |
michael@0 | 60 | |
michael@0 | 61 | @Override |
michael@0 | 62 | public void setUp() throws Exception { |
michael@0 | 63 | super.setUp(sProviderFactory, BrowserContract.READING_LIST_AUTHORITY, DB_NAME); |
michael@0 | 64 | for (TestCase test: TESTS_TO_RUN) { |
michael@0 | 65 | mTests.add(test); |
michael@0 | 66 | } |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | public void testReadingListProviderTests() throws Exception { |
michael@0 | 70 | for (Runnable test : mTests) { |
michael@0 | 71 | setTestName(test.getClass().getSimpleName()); |
michael@0 | 72 | ensureEmptyDatabase(); |
michael@0 | 73 | test.run(); |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | // Ensure browser initialization is complete before completing test, |
michael@0 | 77 | // so that the minidumps directory is consistently created. |
michael@0 | 78 | blockForGeckoReady(); |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | /** |
michael@0 | 82 | * Verify that we can insert a reading list item into the DB. |
michael@0 | 83 | */ |
michael@0 | 84 | private class TestInsertItems extends TestCase { |
michael@0 | 85 | @Override |
michael@0 | 86 | public void test() throws Exception { |
michael@0 | 87 | ContentValues b = createFillerReadingListItem(); |
michael@0 | 88 | long id = ContentUris.parseId(mProvider.insert(ReadingListItems.CONTENT_URI, b)); |
michael@0 | 89 | Cursor c = getItemById(id); |
michael@0 | 90 | |
michael@0 | 91 | try { |
michael@0 | 92 | mAsserter.ok(c.moveToFirst(), "Inserted item found", ""); |
michael@0 | 93 | assertRowEqualsContentValues(c, b); |
michael@0 | 94 | } finally { |
michael@0 | 95 | c.close(); |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | testInsertWithNullCol(ReadingListItems.GUID); |
michael@0 | 99 | mContentProviderInsertTested = true; |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | /** |
michael@0 | 103 | * Test that insertion fails when a required column |
michael@0 | 104 | * is null. |
michael@0 | 105 | */ |
michael@0 | 106 | private void testInsertWithNullCol(String colName) { |
michael@0 | 107 | ContentValues b = createFillerReadingListItem(); |
michael@0 | 108 | b.putNull(colName); |
michael@0 | 109 | |
michael@0 | 110 | try { |
michael@0 | 111 | ContentUris.parseId(mProvider.insert(ReadingListItems.CONTENT_URI, b)); |
michael@0 | 112 | // If we get to here, the flawed insertion succeeded. Fail the test. |
michael@0 | 113 | mAsserter.ok(false, "Insertion did not succeed with " + colName + " == null", ""); |
michael@0 | 114 | } catch (NullPointerException e) { |
michael@0 | 115 | // Indicates test was successful. |
michael@0 | 116 | } |
michael@0 | 117 | } |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | /** |
michael@0 | 121 | * Verify that we can remove a reading list item from the DB. |
michael@0 | 122 | */ |
michael@0 | 123 | private class TestDeleteItems extends TestCase { |
michael@0 | 124 | |
michael@0 | 125 | @Override |
michael@0 | 126 | public void test() throws Exception { |
michael@0 | 127 | long id = insertAnItemWithAssertion(); |
michael@0 | 128 | // Test that the item is only marked as deleted and |
michael@0 | 129 | // not removed from the database. |
michael@0 | 130 | testNonFirefoxSyncDelete(id); |
michael@0 | 131 | |
michael@0 | 132 | // Test that the item is removed from the database. |
michael@0 | 133 | testFirefoxSyncDelete(id); |
michael@0 | 134 | |
michael@0 | 135 | id = insertAnItemWithAssertion(); |
michael@0 | 136 | // Test that deleting works with only a URI. |
michael@0 | 137 | testDeleteWithItemURI(id); |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | /** |
michael@0 | 141 | * Delete an item with PARAM_IS_SYNC unset and verify that item was only marked |
michael@0 | 142 | * as deleted and not actually removed from the database. Also verify that the item |
michael@0 | 143 | * marked as deleted doesn't show up in a query. |
michael@0 | 144 | * |
michael@0 | 145 | * @param id of the item to be deleted |
michael@0 | 146 | */ |
michael@0 | 147 | private void testNonFirefoxSyncDelete(long id) { |
michael@0 | 148 | final int deleted = mProvider.delete(ReadingListItems.CONTENT_URI, |
michael@0 | 149 | ReadingListItems._ID + " = ?", |
michael@0 | 150 | new String[] { String.valueOf(id) }); |
michael@0 | 151 | |
michael@0 | 152 | mAsserter.is(deleted, 1, "Inserted item was deleted"); |
michael@0 | 153 | |
michael@0 | 154 | // PARAM_SHOW_DELETED in the URI allows items marked as deleted to be |
michael@0 | 155 | // included in the query. |
michael@0 | 156 | Uri uri = appendUriParam(ReadingListItems.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"); |
michael@0 | 157 | assertItemExistsByID(uri, id, "Deleted item was only marked as deleted"); |
michael@0 | 158 | |
michael@0 | 159 | // Test that the 'deleted' item does not show up in a query when PARAM_SHOW_DELETED |
michael@0 | 160 | // is not specified in the URI. |
michael@0 | 161 | assertItemDoesNotExistByID(id, "Inserted item can't be found after deletion"); |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | /** |
michael@0 | 165 | * Delete an item with PARAM_IS_SYNC=1 and verify that item |
michael@0 | 166 | * was actually removed from the database. |
michael@0 | 167 | * |
michael@0 | 168 | * @param id of the item to be deleted |
michael@0 | 169 | */ |
michael@0 | 170 | private void testFirefoxSyncDelete(long id) { |
michael@0 | 171 | final int deleted = mProvider.delete(appendUriParam(ReadingListItems.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"), |
michael@0 | 172 | ReadingListItems._ID + " = ?", |
michael@0 | 173 | new String[] { String.valueOf(id) }); |
michael@0 | 174 | |
michael@0 | 175 | mAsserter.is(deleted, 1, "Inserted item was deleted"); |
michael@0 | 176 | |
michael@0 | 177 | Uri uri = appendUriParam(ReadingListItems.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"); |
michael@0 | 178 | assertItemDoesNotExistByID(uri, id, "Inserted item is now actually deleted"); |
michael@0 | 179 | } |
michael@0 | 180 | |
michael@0 | 181 | /** |
michael@0 | 182 | * Delete an item with its URI and verify that the item |
michael@0 | 183 | * was actually removed from the database. |
michael@0 | 184 | * |
michael@0 | 185 | * @param id of the item to be deleted |
michael@0 | 186 | */ |
michael@0 | 187 | private void testDeleteWithItemURI(long id) { |
michael@0 | 188 | final int deleted = mProvider.delete(ContentUris.withAppendedId(ReadingListItems.CONTENT_URI, id), null, null); |
michael@0 | 189 | mAsserter.is(deleted, 1, "Inserted item was deleted using URI with id"); |
michael@0 | 190 | } |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | /** |
michael@0 | 194 | * Verify that we can update reading list items. |
michael@0 | 195 | */ |
michael@0 | 196 | private class TestUpdateItems extends TestCase { |
michael@0 | 197 | |
michael@0 | 198 | @Override |
michael@0 | 199 | public void test() throws Exception { |
michael@0 | 200 | // We should be able to insert into the DB. |
michael@0 | 201 | ensureCanInsert(); |
michael@0 | 202 | |
michael@0 | 203 | ContentValues original = createFillerReadingListItem(); |
michael@0 | 204 | long id = ContentUris.parseId(mProvider.insert(ReadingListItems.CONTENT_URI, original)); |
michael@0 | 205 | int updated = 0; |
michael@0 | 206 | Long originalDateCreated = null; |
michael@0 | 207 | Long originalDateModified = null; |
michael@0 | 208 | ContentValues updates = new ContentValues(); |
michael@0 | 209 | Cursor c = getItemById(id); |
michael@0 | 210 | try { |
michael@0 | 211 | mAsserter.ok(c.moveToFirst(), "Inserted item found", ""); |
michael@0 | 212 | |
michael@0 | 213 | originalDateCreated = c.getLong(c.getColumnIndex(ReadingListItems.DATE_CREATED)); |
michael@0 | 214 | originalDateModified = c.getLong(c.getColumnIndex(ReadingListItems.DATE_MODIFIED)); |
michael@0 | 215 | |
michael@0 | 216 | updates.put(ReadingListItems.TITLE, original.getAsString(ReadingListItems.TITLE) + "CHANGED"); |
michael@0 | 217 | updates.put(ReadingListItems.URL, original.getAsString(ReadingListItems.URL) + "/more/stuff"); |
michael@0 | 218 | updates.put(ReadingListItems.EXCERPT, original.getAsString(ReadingListItems.EXCERPT) + "CHANGED"); |
michael@0 | 219 | |
michael@0 | 220 | updated = mProvider.update(ReadingListItems.CONTENT_URI, updates, |
michael@0 | 221 | ReadingListItems._ID + " = ?", |
michael@0 | 222 | new String[] { String.valueOf(id) }); |
michael@0 | 223 | |
michael@0 | 224 | mAsserter.is(updated, 1, "Inserted item was updated"); |
michael@0 | 225 | } finally { |
michael@0 | 226 | c.close(); |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | // Name change for clarity. These values will be compared with the |
michael@0 | 230 | // current cursor row. |
michael@0 | 231 | ContentValues expectedValues = updates; |
michael@0 | 232 | c = getItemById(id); |
michael@0 | 233 | try { |
michael@0 | 234 | mAsserter.ok(c.moveToFirst(), "Updated item found", ""); |
michael@0 | 235 | mAsserter.isnot(c.getLong(c.getColumnIndex(ReadingListItems.DATE_MODIFIED)), |
michael@0 | 236 | originalDateModified, |
michael@0 | 237 | "Date modified should have changed"); |
michael@0 | 238 | |
michael@0 | 239 | // DATE_CREATED and LENGTH should equal old values since they weren't updated. |
michael@0 | 240 | expectedValues.put(ReadingListItems.DATE_CREATED, originalDateCreated); |
michael@0 | 241 | expectedValues.put(ReadingListItems.LENGTH, original.getAsString(ReadingListItems.LENGTH)); |
michael@0 | 242 | assertRowEqualsContentValues(c, expectedValues, /* compareDateModified */ false); |
michael@0 | 243 | } finally { |
michael@0 | 244 | c.close(); |
michael@0 | 245 | } |
michael@0 | 246 | |
michael@0 | 247 | // Test that updates on an item that doesn't exist does not modify any rows. |
michael@0 | 248 | testUpdateWithInvalidID(); |
michael@0 | 249 | |
michael@0 | 250 | // Test that update fails when a GUID is null. |
michael@0 | 251 | testUpdateWithNullCol(id, ReadingListItems.GUID); |
michael@0 | 252 | |
michael@0 | 253 | mContentProviderUpdateTested = true; |
michael@0 | 254 | } |
michael@0 | 255 | |
michael@0 | 256 | /** |
michael@0 | 257 | * Test that updates on an item that doesn't exist does |
michael@0 | 258 | * not modify any rows. |
michael@0 | 259 | * |
michael@0 | 260 | * @param id of the item to be deleted |
michael@0 | 261 | */ |
michael@0 | 262 | private void testUpdateWithInvalidID() { |
michael@0 | 263 | ensureEmptyDatabase(); |
michael@0 | 264 | final ContentValues b = createFillerReadingListItem(); |
michael@0 | 265 | final long id = ContentUris.parseId(mProvider.insert(ReadingListItems.CONTENT_URI, b)); |
michael@0 | 266 | final long INVALID_ID = id + 1; |
michael@0 | 267 | final ContentValues updates = new ContentValues(); |
michael@0 | 268 | updates.put(ReadingListItems.TITLE, b.getAsString(ReadingListItems.TITLE) + "CHANGED"); |
michael@0 | 269 | final int updated = mProvider.update(ReadingListItems.CONTENT_URI, updates, |
michael@0 | 270 | ReadingListItems._ID + " = ?", |
michael@0 | 271 | new String[] { String.valueOf(INVALID_ID) }); |
michael@0 | 272 | mAsserter.is(updated, 0, "Should not be able to update item with an invalid GUID"); |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | /** |
michael@0 | 276 | * Test that update fails when a required column is null. |
michael@0 | 277 | */ |
michael@0 | 278 | private int testUpdateWithNullCol(long id, String colName) { |
michael@0 | 279 | ContentValues updates = new ContentValues(); |
michael@0 | 280 | updates.putNull(colName); |
michael@0 | 281 | |
michael@0 | 282 | int updated = mProvider.update(ReadingListItems.CONTENT_URI, updates, |
michael@0 | 283 | ReadingListItems._ID + " = ?", |
michael@0 | 284 | new String[] { String.valueOf(id) }); |
michael@0 | 285 | |
michael@0 | 286 | mAsserter.is(updated, 0, "Should not be able to update item with " + colName + " == null "); |
michael@0 | 287 | return updated; |
michael@0 | 288 | } |
michael@0 | 289 | } |
michael@0 | 290 | |
michael@0 | 291 | private class TestBatchOperations extends TestCase { |
michael@0 | 292 | private static final int ITEM_COUNT = 10; |
michael@0 | 293 | |
michael@0 | 294 | /** |
michael@0 | 295 | * Insert a bunch of items into the DB with the bulkInsert |
michael@0 | 296 | * method and verify that they are there. |
michael@0 | 297 | */ |
michael@0 | 298 | private void testBulkInsert() { |
michael@0 | 299 | ensureEmptyDatabase(); |
michael@0 | 300 | final ContentValues allVals[] = new ContentValues[ITEM_COUNT]; |
michael@0 | 301 | final HashSet<String> urls = new HashSet<String>(); |
michael@0 | 302 | for (int i = 0; i < ITEM_COUNT; i++) { |
michael@0 | 303 | final String url = "http://www.test.org/" + i; |
michael@0 | 304 | allVals[i] = new ContentValues(); |
michael@0 | 305 | allVals[i].put(ReadingListItems.TITLE, "Test" + i); |
michael@0 | 306 | allVals[i].put(ReadingListItems.URL, url); |
michael@0 | 307 | allVals[i].put(ReadingListItems.EXCERPT, "EXCERPT" + i); |
michael@0 | 308 | allVals[i].put(ReadingListItems.LENGTH, i); |
michael@0 | 309 | urls.add(url); |
michael@0 | 310 | } |
michael@0 | 311 | |
michael@0 | 312 | int inserts = mProvider.bulkInsert(ReadingListItems.CONTENT_URI, allVals); |
michael@0 | 313 | mAsserter.is(inserts, ITEM_COUNT, "Excepted number of inserts matches"); |
michael@0 | 314 | |
michael@0 | 315 | Cursor c = mProvider.query(ReadingListItems.CONTENT_URI, null, |
michael@0 | 316 | null, |
michael@0 | 317 | null, |
michael@0 | 318 | null); |
michael@0 | 319 | try { |
michael@0 | 320 | while (c.moveToNext()) { |
michael@0 | 321 | final String url = c.getString(c.getColumnIndex(ReadingListItems.URL)); |
michael@0 | 322 | mAsserter.ok(urls.contains(url), "Bulk inserted item with url == " + url + " was found in the DB", ""); |
michael@0 | 323 | // We should only be seeing each item once. Remove from set to prevent dups. |
michael@0 | 324 | urls.remove(url); |
michael@0 | 325 | } |
michael@0 | 326 | } finally { |
michael@0 | 327 | c.close(); |
michael@0 | 328 | } |
michael@0 | 329 | } |
michael@0 | 330 | |
michael@0 | 331 | @Override |
michael@0 | 332 | public void test() { |
michael@0 | 333 | testBulkInsert(); |
michael@0 | 334 | } |
michael@0 | 335 | } |
michael@0 | 336 | |
michael@0 | 337 | /* |
michael@0 | 338 | * Verify that insert, update, delete, and bulkInsert operations |
michael@0 | 339 | * notify the ambient content resolver. Each operation calls the |
michael@0 | 340 | * content resolver notifyChange method synchronously, so it is |
michael@0 | 341 | * okay to test sequentially. |
michael@0 | 342 | */ |
michael@0 | 343 | private class TestBrowserProviderNotifications extends TestCase { |
michael@0 | 344 | |
michael@0 | 345 | @Override |
michael@0 | 346 | public void test() { |
michael@0 | 347 | // We should be able to insert into the DB. |
michael@0 | 348 | ensureCanInsert(); |
michael@0 | 349 | // We should be able to update the DB. |
michael@0 | 350 | ensureCanUpdate(); |
michael@0 | 351 | |
michael@0 | 352 | final String CONTENT_URI = ReadingListItems.CONTENT_URI.toString(); |
michael@0 | 353 | |
michael@0 | 354 | mResolver.notifyChangeList.clear(); |
michael@0 | 355 | |
michael@0 | 356 | // Insert |
michael@0 | 357 | final ContentValues h = createFillerReadingListItem(); |
michael@0 | 358 | long id = ContentUris.parseId(mProvider.insert(ReadingListItems.CONTENT_URI, h)); |
michael@0 | 359 | |
michael@0 | 360 | mAsserter.isnot(id, |
michael@0 | 361 | -1L, |
michael@0 | 362 | "Inserted item has valid id"); |
michael@0 | 363 | |
michael@0 | 364 | ensureOnlyChangeNotifiedStartsWith(CONTENT_URI, "insert"); |
michael@0 | 365 | |
michael@0 | 366 | // Update |
michael@0 | 367 | mResolver.notifyChangeList.clear(); |
michael@0 | 368 | h.put(ReadingListItems.TITLE, "http://newexample.com"); |
michael@0 | 369 | |
michael@0 | 370 | long numUpdated = mProvider.update(ReadingListItems.CONTENT_URI, h, |
michael@0 | 371 | ReadingListItems._ID + " = ?", |
michael@0 | 372 | new String[] { String.valueOf(id) }); |
michael@0 | 373 | |
michael@0 | 374 | mAsserter.is(numUpdated, |
michael@0 | 375 | 1L, |
michael@0 | 376 | "Correct number of items are updated"); |
michael@0 | 377 | |
michael@0 | 378 | ensureOnlyChangeNotifiedStartsWith(CONTENT_URI, "update"); |
michael@0 | 379 | |
michael@0 | 380 | // Delete |
michael@0 | 381 | mResolver.notifyChangeList.clear(); |
michael@0 | 382 | long numDeleted = mProvider.delete(ReadingListItems.CONTENT_URI, null, null); |
michael@0 | 383 | |
michael@0 | 384 | mAsserter.is(numDeleted, |
michael@0 | 385 | 1L, |
michael@0 | 386 | "Correct number of items are deleted"); |
michael@0 | 387 | |
michael@0 | 388 | ensureOnlyChangeNotifiedStartsWith(CONTENT_URI, "delete"); |
michael@0 | 389 | |
michael@0 | 390 | // Bulk insert |
michael@0 | 391 | mResolver.notifyChangeList.clear(); |
michael@0 | 392 | final ContentValues[] hs = { createFillerReadingListItem(), |
michael@0 | 393 | createFillerReadingListItem(), |
michael@0 | 394 | createFillerReadingListItem() }; |
michael@0 | 395 | |
michael@0 | 396 | long numBulkInserted = mProvider.bulkInsert(ReadingListItems.CONTENT_URI, hs); |
michael@0 | 397 | |
michael@0 | 398 | mAsserter.is(numBulkInserted, |
michael@0 | 399 | 3L, |
michael@0 | 400 | "Correct number of items are bulkInserted"); |
michael@0 | 401 | |
michael@0 | 402 | ensureOnlyChangeNotifiedStartsWith(CONTENT_URI, "bulkInsert"); |
michael@0 | 403 | } |
michael@0 | 404 | |
michael@0 | 405 | protected void ensureOnlyChangeNotifiedStartsWith(String expectedUri, String operation) { |
michael@0 | 406 | mAsserter.is(Long.valueOf(mResolver.notifyChangeList.size()), |
michael@0 | 407 | 1L, |
michael@0 | 408 | "Content observer was notified exactly once by " + operation); |
michael@0 | 409 | |
michael@0 | 410 | final Uri uri = mResolver.notifyChangeList.poll(); |
michael@0 | 411 | |
michael@0 | 412 | mAsserter.isnot(uri, |
michael@0 | 413 | null, |
michael@0 | 414 | "Notification from " + operation + " was valid"); |
michael@0 | 415 | |
michael@0 | 416 | mAsserter.ok(uri.toString().startsWith(expectedUri), |
michael@0 | 417 | "Content observer was notified exactly once by " + operation, |
michael@0 | 418 | ""); |
michael@0 | 419 | } |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | /** |
michael@0 | 423 | * Removes all items from the DB. |
michael@0 | 424 | */ |
michael@0 | 425 | private void ensureEmptyDatabase() { |
michael@0 | 426 | Uri uri = appendUriParam(ReadingListItems.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"); |
michael@0 | 427 | getWritableDatabase(uri).delete(ReadingListItems.TABLE_NAME, null, null); |
michael@0 | 428 | } |
michael@0 | 429 | |
michael@0 | 430 | |
michael@0 | 431 | private SQLiteDatabase getWritableDatabase(Uri uri) { |
michael@0 | 432 | Uri testUri = appendUriParam(uri, BrowserContract.PARAM_IS_TEST, "1"); |
michael@0 | 433 | DelegatingTestContentProvider delegateProvider = (DelegatingTestContentProvider) mProvider; |
michael@0 | 434 | ReadingListProvider readingListProvider = (ReadingListProvider) delegateProvider.getTargetProvider(); |
michael@0 | 435 | return readingListProvider.getWritableDatabaseForTesting(testUri); |
michael@0 | 436 | } |
michael@0 | 437 | |
michael@0 | 438 | /** |
michael@0 | 439 | * Checks that the values in the cursor's current row match those |
michael@0 | 440 | * in the ContentValues object. |
michael@0 | 441 | * |
michael@0 | 442 | * @param cursor over the row to be checked |
michael@0 | 443 | * @param values to be checked |
michael@0 | 444 | */ |
michael@0 | 445 | private void assertRowEqualsContentValues(Cursor cursorWithActual, ContentValues expectedValues, boolean compareDateModified) { |
michael@0 | 446 | for (String column: TEST_COLUMNS) { |
michael@0 | 447 | String expected = expectedValues.getAsString(column); |
michael@0 | 448 | String actual = cursorWithActual.getString(cursorWithActual.getColumnIndex(column)); |
michael@0 | 449 | mAsserter.is(actual, expected, "Item has correct " + column); |
michael@0 | 450 | } |
michael@0 | 451 | |
michael@0 | 452 | if (compareDateModified) { |
michael@0 | 453 | String expected = expectedValues.getAsString(ReadingListItems.DATE_MODIFIED); |
michael@0 | 454 | String actual = cursorWithActual.getString(cursorWithActual.getColumnIndex(ReadingListItems.DATE_MODIFIED)); |
michael@0 | 455 | mAsserter.is(actual, expected, "Item has correct " + ReadingListItems.DATE_MODIFIED); |
michael@0 | 456 | } |
michael@0 | 457 | } |
michael@0 | 458 | |
michael@0 | 459 | private void assertRowEqualsContentValues(Cursor cursorWithActual, ContentValues expectedValues) { |
michael@0 | 460 | assertRowEqualsContentValues(cursorWithActual, expectedValues, true); |
michael@0 | 461 | } |
michael@0 | 462 | |
michael@0 | 463 | private ContentValues fillContentValues(String title, String url, String excerpt) { |
michael@0 | 464 | ContentValues values = new ContentValues(); |
michael@0 | 465 | |
michael@0 | 466 | values.put(ReadingListItems.TITLE, title); |
michael@0 | 467 | values.put(ReadingListItems.URL, url); |
michael@0 | 468 | values.put(ReadingListItems.EXCERPT, excerpt); |
michael@0 | 469 | values.put(ReadingListItems.LENGTH, excerpt.length()); |
michael@0 | 470 | |
michael@0 | 471 | return values; |
michael@0 | 472 | } |
michael@0 | 473 | |
michael@0 | 474 | private ContentValues createFillerReadingListItem() { |
michael@0 | 475 | Random rand = new Random(); |
michael@0 | 476 | return fillContentValues("Example", "http://example.com/?num=" + rand.nextInt(), "foo bar"); |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | private Cursor getItemById(Uri uri, long id, String[] projection) { |
michael@0 | 480 | return mProvider.query(uri, projection, |
michael@0 | 481 | ReadingListItems._ID + " = ?", |
michael@0 | 482 | new String[] { String.valueOf(id) }, |
michael@0 | 483 | null); |
michael@0 | 484 | } |
michael@0 | 485 | |
michael@0 | 486 | private Cursor getItemById(long id) { |
michael@0 | 487 | return getItemById(ReadingListItems.CONTENT_URI, id, null); |
michael@0 | 488 | } |
michael@0 | 489 | |
michael@0 | 490 | private Cursor getItemById(Uri uri, long id) { |
michael@0 | 491 | return getItemById(uri, id, null); |
michael@0 | 492 | } |
michael@0 | 493 | |
michael@0 | 494 | /** |
michael@0 | 495 | * Verifies that ContentProvider insertions have been tested. |
michael@0 | 496 | */ |
michael@0 | 497 | private void ensureCanInsert() { |
michael@0 | 498 | if (!mContentProviderInsertTested) { |
michael@0 | 499 | mAsserter.ok(false, "ContentProvider insertions have not been tested yet.", ""); |
michael@0 | 500 | } |
michael@0 | 501 | } |
michael@0 | 502 | |
michael@0 | 503 | /** |
michael@0 | 504 | * Verifies that ContentProvider updates have been tested. |
michael@0 | 505 | */ |
michael@0 | 506 | private void ensureCanUpdate() { |
michael@0 | 507 | if (!mContentProviderUpdateTested) { |
michael@0 | 508 | mAsserter.ok(false, "ContentProvider updates have not been tested yet.", ""); |
michael@0 | 509 | } |
michael@0 | 510 | } |
michael@0 | 511 | |
michael@0 | 512 | private long insertAnItemWithAssertion() { |
michael@0 | 513 | // We should be able to insert into the DB. |
michael@0 | 514 | ensureCanInsert(); |
michael@0 | 515 | |
michael@0 | 516 | ContentValues v = createFillerReadingListItem(); |
michael@0 | 517 | long id = ContentUris.parseId(mProvider.insert(ReadingListItems.CONTENT_URI, v)); |
michael@0 | 518 | |
michael@0 | 519 | assertItemExistsByID(id, "Inserted item found"); |
michael@0 | 520 | return id; |
michael@0 | 521 | } |
michael@0 | 522 | |
michael@0 | 523 | private void assertItemExistsByID(Uri uri, long id, String msg) { |
michael@0 | 524 | Cursor c = getItemById(uri, id); |
michael@0 | 525 | try { |
michael@0 | 526 | mAsserter.ok(c.moveToFirst(), msg, ""); |
michael@0 | 527 | } finally { |
michael@0 | 528 | c.close(); |
michael@0 | 529 | } |
michael@0 | 530 | } |
michael@0 | 531 | |
michael@0 | 532 | private void assertItemExistsByID(long id, String msg) { |
michael@0 | 533 | Cursor c = getItemById(id); |
michael@0 | 534 | try { |
michael@0 | 535 | mAsserter.ok(c.moveToFirst(), msg, ""); |
michael@0 | 536 | } finally { |
michael@0 | 537 | c.close(); |
michael@0 | 538 | } |
michael@0 | 539 | } |
michael@0 | 540 | |
michael@0 | 541 | private void assertItemDoesNotExistByID(long id, String msg) { |
michael@0 | 542 | Cursor c = getItemById(id); |
michael@0 | 543 | try { |
michael@0 | 544 | mAsserter.ok(!c.moveToFirst(), msg, ""); |
michael@0 | 545 | } finally { |
michael@0 | 546 | c.close(); |
michael@0 | 547 | } |
michael@0 | 548 | } |
michael@0 | 549 | |
michael@0 | 550 | private void assertItemDoesNotExistByID(Uri uri, long id, String msg) { |
michael@0 | 551 | Cursor c = getItemById(uri, id); |
michael@0 | 552 | try { |
michael@0 | 553 | mAsserter.ok(!c.moveToFirst(), msg, ""); |
michael@0 | 554 | } finally { |
michael@0 | 555 | c.close(); |
michael@0 | 556 | } |
michael@0 | 557 | } |
michael@0 | 558 | } |