ProviderTests.java revision d072f9905d8572f454be1f2ea5d7ba173d2b57d1
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.email.provider; 18 19import com.android.email.Snippet; 20import com.android.email.Utility; 21import com.android.email.provider.EmailContent.Account; 22import com.android.email.provider.EmailContent.AccountColumns; 23import com.android.email.provider.EmailContent.Attachment; 24import com.android.email.provider.EmailContent.AttachmentColumns; 25import com.android.email.provider.EmailContent.Body; 26import com.android.email.provider.EmailContent.BodyColumns; 27import com.android.email.provider.EmailContent.HostAuth; 28import com.android.email.provider.EmailContent.Mailbox; 29import com.android.email.provider.EmailContent.MailboxColumns; 30import com.android.email.provider.EmailContent.Message; 31import com.android.email.provider.EmailContent.MessageColumns; 32 33import android.content.ContentResolver; 34import android.content.ContentUris; 35import android.content.ContentValues; 36import android.content.Context; 37import android.database.Cursor; 38import android.database.sqlite.SQLiteDatabase; 39import android.net.Uri; 40import android.os.Bundle; 41import android.os.Environment; 42import android.os.Parcel; 43import android.test.MoreAsserts; 44import android.test.ProviderTestCase2; 45 46import java.io.File; 47import java.io.IOException; 48import java.util.ArrayList; 49 50/** 51 * Tests of the Email provider. 52 * 53 * You can run this entire test case with: 54 * runtest -c com.android.email.provider.ProviderTests email 55 * 56 * TODO: Add tests for cursor notification mechanism. (setNotificationUri and notifyChange) 57 * We can't test the entire notification mechanism with a mock content resolver, because which URI 58 * to notify when notifyChange() is called is in the actual content resolver. 59 * Implementing the same mechanism in a mock one is pointless. Instead what we could do is check 60 * what notification URI each cursor has, and with which URI is notified when 61 * inserting/updating/deleting. (The former require a new method from AbstractCursor) 62 */ 63public class ProviderTests extends ProviderTestCase2<EmailProvider> { 64 65 private EmailProvider mProvider; 66 private Context mMockContext; 67 68 public ProviderTests() { 69 super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY); 70 } 71 72 @Override 73 public void setUp() throws Exception { 74 super.setUp(); 75 mMockContext = getMockContext(); 76 mProvider = getProvider(); 77 // Invalidate all caches, since we reset the database for each test 78 ContentCache.invalidateAllCachesForTest(); 79 } 80 81 @Override 82 public void tearDown() throws Exception { 83 super.tearDown(); 84 } 85 86 /** 87 * TODO: Database upgrade tests 88 */ 89 90 /** 91 * Test simple account save/retrieve 92 */ 93 public void testAccountSave() { 94 Account account1 = ProviderTestUtils.setupAccount("account-save", true, mMockContext); 95 long account1Id = account1.mId; 96 97 Account account2 = EmailContent.Account.restoreAccountWithId(mMockContext, account1Id); 98 99 ProviderTestUtils.assertAccountEqual("testAccountSave", account1, account2); 100 } 101 102 /** 103 * Test simple account save/retrieve with predefined hostauth records 104 */ 105 public void testAccountSaveHostAuth() { 106 Account account1 = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext); 107 // add hostauth data, which should be saved the first time 108 account1.mHostAuthRecv = ProviderTestUtils.setupHostAuth("account-hostauth-recv", -1, false, 109 mMockContext); 110 account1.mHostAuthSend = ProviderTestUtils.setupHostAuth("account-hostauth-send", -1, false, 111 mMockContext); 112 account1.save(mMockContext); 113 long account1Id = account1.mId; 114 115 // Confirm account reads back correctly 116 Account account1get = EmailContent.Account.restoreAccountWithId(mMockContext, account1Id); 117 ProviderTestUtils.assertAccountEqual("testAccountSave", account1, account1get); 118 119 // Confirm hostauth fields can be accessed & read back correctly 120 HostAuth hostAuth1get = EmailContent.HostAuth.restoreHostAuthWithId(mMockContext, 121 account1get.mHostAuthKeyRecv); 122 ProviderTestUtils.assertHostAuthEqual("testAccountSaveHostAuth-recv", 123 account1.mHostAuthRecv, hostAuth1get); 124 HostAuth hostAuth2get = EmailContent.HostAuth.restoreHostAuthWithId(mMockContext, 125 account1get.mHostAuthKeySend); 126 ProviderTestUtils.assertHostAuthEqual("testAccountSaveHostAuth-send", 127 account1.mHostAuthSend, hostAuth2get); 128 } 129 130 /** 131 * Simple test of account parceling. The rather tortuous path is to ensure that the 132 * account is really flattened all the way down to a parcel and back. 133 */ 134 public void testAccountParcel() { 135 Account account1 = ProviderTestUtils.setupAccount("parcel", false, mMockContext); 136 Bundle b = new Bundle(); 137 b.putParcelable("account", account1); 138 Parcel p = Parcel.obtain(); 139 b.writeToParcel(p, 0); 140 p.setDataPosition(0); // rewind it for reading 141 Bundle b2 = new Bundle(Account.class.getClassLoader()); 142 b2.readFromParcel(p); 143 Account account2 = (Account) b2.getParcelable("account"); 144 p.recycle(); 145 146 ProviderTestUtils.assertAccountEqual("testAccountParcel", account1, account2); 147 } 148 149 /** 150 * Test for {@link Account#getShortcutSafeUri()} and 151 * {@link Account#getAccountIdForShortcutSafeUri}. 152 */ 153 public void testAccountShortcutSafeUri() { 154 final Account account1 = ProviderTestUtils.setupAccount("account-1", true, mMockContext); 155 final Account account2 = ProviderTestUtils.setupAccount("account-2", true, mMockContext); 156 final long account1Id = account1.mId; 157 final long account2Id = account2.mId; 158 159 final Uri uri1 = account1.getShortcutSafeUri(); 160 final Uri uri2 = account2.getShortcutSafeUri(); 161 162 // Check the path part of the URIs. 163 MoreAsserts.assertEquals(new String[] {"account", account1.mCompatibilityUuid}, 164 uri1.getPathSegments().toArray()); 165 MoreAsserts.assertEquals(new String[] {"account", account2.mCompatibilityUuid}, 166 uri2.getPathSegments().toArray()); 167 168 assertEquals(account1Id, Account.getAccountIdFromShortcutSafeUri(mMockContext, uri1)); 169 assertEquals(account2Id, Account.getAccountIdFromShortcutSafeUri(mMockContext, uri2)); 170 171 // Test for the Eclair(2.0-2.1) style URI. 172 assertEquals(account1Id, Account.getAccountIdFromShortcutSafeUri(mMockContext, 173 getEclairStyleShortcutUri(account1))); 174 assertEquals(account2Id, Account.getAccountIdFromShortcutSafeUri(mMockContext, 175 getEclairStyleShortcutUri(account2))); 176 } 177 178 private static Uri getEclairStyleShortcutUri(Account account) { 179 // We used _id instead of UUID only on Eclair(2.0-2.1). 180 return Account.CONTENT_URI.buildUpon().appendEncodedPath("" + account.mId).build(); 181 } 182 183 public void testGetProtocol() { 184 Account account1 = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext); 185 // add hostauth data, with protocol 186 account1.mHostAuthRecv = ProviderTestUtils.setupHostAuth("eas", "account-hostauth-recv", -1, 187 false, mMockContext); 188 // Note that getProtocol uses the receive host auth, so the protocol here shouldn't matter 189 // to the test result 190 account1.mHostAuthSend = ProviderTestUtils.setupHostAuth("foo", "account-hostauth-send", -1, 191 false, mMockContext); 192 account1.save(mMockContext); 193 assertEquals("eas", Account.getProtocol(mMockContext, account1.mId)); 194 assertEquals("eas", account1.getProtocol(mMockContext)); 195 Account account2 = ProviderTestUtils.setupAccount("account-nohostauth", false, 196 mMockContext); 197 account2.save(mMockContext); 198 // Make sure that we return null when there's no host auth 199 assertNull(Account.getProtocol(mMockContext, account2.mId)); 200 assertNull(account2.getProtocol(mMockContext)); 201 // And when there's no account 202 assertNull(Account.getProtocol(mMockContext, 0)); 203 } 204 205 public void testAccountIsValidId() { 206 final Account account1 = ProviderTestUtils.setupAccount("account-1", true, mMockContext); 207 final Account account2 = ProviderTestUtils.setupAccount("account-2", true, mMockContext); 208 209 assertTrue(Account.isValidId(mMockContext, account1.mId)); 210 assertTrue(Account.isValidId(mMockContext, account2.mId)); 211 212 assertFalse(Account.isValidId(mMockContext, 1234567)); // Some random ID 213 assertFalse(Account.isValidId(mMockContext, -1)); 214 assertFalse(Account.isValidId(mMockContext, -500)); 215 } 216 217 private final static String[] MAILBOX_UNREAD_COUNT_PROJECTION = new String [] { 218 MailboxColumns.UNREAD_COUNT 219 }; 220 private final static int MAILBOX_UNREAD_COUNT_COLMUN = 0; 221 222 /** 223 * Get the value of the unread count in the mailbox of the account. 224 * This can be different from the actual number of unread messages in that mailbox. 225 * @param accountId 226 * @param mailboxId 227 * @return 228 */ 229 private int getUnreadCount(long mailboxId) { 230 String text = null; 231 Cursor c = null; 232 try { 233 c = mMockContext.getContentResolver().query( 234 Mailbox.CONTENT_URI, 235 MAILBOX_UNREAD_COUNT_PROJECTION, 236 EmailContent.RECORD_ID + "=?", 237 new String[] { String.valueOf(mailboxId) }, 238 null); 239 c.moveToFirst(); 240 text = c.getString(MAILBOX_UNREAD_COUNT_COLMUN); 241 } finally { 242 c.close(); 243 } 244 return Integer.valueOf(text); 245 } 246 247 /** 248 * TODO: HostAuth tests 249 */ 250 251 /** 252 * Test the various combinations of SSL, TLS, and trust-certificates encoded as Uris 253 */ 254 @SuppressWarnings("deprecation") 255 public void testHostAuthSecurityUri() { 256 HostAuth ha = ProviderTestUtils.setupHostAuth("uri-security", 1, false, mMockContext); 257 258 final int MASK = 259 HostAuth.FLAG_SSL | HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL_CERTIFICATES; 260 261 // Set various URIs and check the resulting flags 262 ha.setStoreUri("protocol://user:password@server:123"); 263 assertEquals(0, ha.mFlags & MASK); 264 ha.setStoreUri("protocol+ssl+://user:password@server:123"); 265 assertEquals(HostAuth.FLAG_SSL, ha.mFlags & MASK); 266 ha.setStoreUri("protocol+ssl+trustallcerts://user:password@server:123"); 267 assertEquals(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL_CERTIFICATES, ha.mFlags & MASK); 268 ha.setStoreUri("protocol+tls+://user:password@server:123"); 269 assertEquals(HostAuth.FLAG_TLS, ha.mFlags & MASK); 270 ha.setStoreUri("protocol+tls+trustallcerts://user:password@server:123"); 271 assertEquals(HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL_CERTIFICATES, ha.mFlags & MASK); 272 273 // Now check the retrival method (building URI from flags) 274 ha.mFlags &= ~MASK; 275 String uriString = ha.getStoreUri(); 276 assertTrue(uriString.startsWith("protocol://")); 277 ha.mFlags |= HostAuth.FLAG_SSL; 278 uriString = ha.getStoreUri(); 279 assertTrue(uriString.startsWith("protocol+ssl+://")); 280 ha.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES; 281 uriString = ha.getStoreUri(); 282 assertTrue(uriString.startsWith("protocol+ssl+trustallcerts://")); 283 ha.mFlags &= ~MASK; 284 ha.mFlags |= HostAuth.FLAG_TLS; 285 uriString = ha.getStoreUri(); 286 assertTrue(uriString.startsWith("protocol+tls+://")); 287 ha.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES; 288 uriString = ha.getStoreUri(); 289 assertTrue(uriString.startsWith("protocol+tls+trustallcerts://")); 290 } 291 292 /** 293 * Test port assignments made from Uris 294 */ 295 @SuppressWarnings("deprecation") 296 public void testHostAuthPortAssignments() { 297 HostAuth ha = ProviderTestUtils.setupHostAuth("uri-port", 1, false, mMockContext); 298 299 // Set various URIs and check the resulting flags 300 // Hardwired port 301 ha.setStoreUri("imap://user:password@server:123"); 302 assertEquals(123, ha.mPort); 303 // Auto-assigned ports 304 ha.setStoreUri("imap://user:password@server"); 305 assertEquals(143, ha.mPort); 306 ha.setStoreUri("imap+ssl://user:password@server"); 307 assertEquals(993, ha.mPort); 308 ha.setStoreUri("imap+ssl+trustallcerts://user:password@server"); 309 assertEquals(993, ha.mPort); 310 ha.setStoreUri("imap+tls://user:password@server"); 311 assertEquals(143, ha.mPort); 312 ha.setStoreUri("imap+tls+trustallcerts://user:password@server"); 313 assertEquals(143, ha.mPort); 314 315 // Hardwired port 316 ha.setStoreUri("pop3://user:password@server:123"); 317 assertEquals(123, ha.mPort); 318 // Auto-assigned ports 319 ha.setStoreUri("pop3://user:password@server"); 320 assertEquals(110, ha.mPort); 321 ha.setStoreUri("pop3+ssl://user:password@server"); 322 assertEquals(995, ha.mPort); 323 ha.setStoreUri("pop3+ssl+trustallcerts://user:password@server"); 324 assertEquals(995, ha.mPort); 325 ha.setStoreUri("pop3+tls://user:password@server"); 326 assertEquals(110, ha.mPort); 327 ha.setStoreUri("pop3+tls+trustallcerts://user:password@server"); 328 assertEquals(110, ha.mPort); 329 330 // Hardwired port 331 ha.setStoreUri("eas://user:password@server:123"); 332 assertEquals(123, ha.mPort); 333 // Auto-assigned ports 334 ha.setStoreUri("eas://user:password@server"); 335 assertEquals(80, ha.mPort); 336 ha.setStoreUri("eas+ssl://user:password@server"); 337 assertEquals(443, ha.mPort); 338 ha.setStoreUri("eas+ssl+trustallcerts://user:password@server"); 339 assertEquals(443, ha.mPort); 340 341 // Hardwired port 342 ha.setStoreUri("smtp://user:password@server:123"); 343 assertEquals(123, ha.mPort); 344 // Auto-assigned ports 345 ha.setStoreUri("smtp://user:password@server"); 346 assertEquals(587, ha.mPort); 347 ha.setStoreUri("smtp+ssl://user:password@server"); 348 assertEquals(465, ha.mPort); 349 ha.setStoreUri("smtp+ssl+trustallcerts://user:password@server"); 350 assertEquals(465, ha.mPort); 351 ha.setStoreUri("smtp+tls://user:password@server"); 352 assertEquals(587, ha.mPort); 353 ha.setStoreUri("smtp+tls+trustallcerts://user:password@server"); 354 assertEquals(587, ha.mPort); 355 } 356 357 /** 358 * Test simple mailbox save/retrieve 359 */ 360 public void testMailboxSave() { 361 Account account1 = ProviderTestUtils.setupAccount("mailbox-save", true, mMockContext); 362 long account1Id = account1.mId; 363 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, 364 mMockContext); 365 long box1Id = box1.mId; 366 367 Mailbox box2 = EmailContent.Mailbox.restoreMailboxWithId(mMockContext, box1Id); 368 369 ProviderTestUtils.assertMailboxEqual("testMailboxSave", box1, box2); 370 } 371 372 private static String[] expectedAttachmentNames = 373 new String[] {"attachment1.doc", "attachment2.xls", "attachment3"}; 374 // The lengths need to be kept in ascending order 375 private static long[] expectedAttachmentSizes = new long[] {31415L, 97701L, 151213L}; 376 377 /* 378 * Returns null if the message has no body. 379 */ 380 private Body loadBodyForMessageId(long messageId) { 381 Cursor c = null; 382 try { 383 c = mMockContext.getContentResolver().query( 384 EmailContent.Body.CONTENT_URI, 385 EmailContent.Body.CONTENT_PROJECTION, 386 EmailContent.Body.MESSAGE_KEY + "=?", 387 new String[] {String.valueOf(messageId)}, 388 null); 389 int numBodies = c.getCount(); 390 assertTrue("at most one body", numBodies < 2); 391 return c.moveToFirst() ? EmailContent.getContent(c, Body.class) : null; 392 } finally { 393 c.close(); 394 } 395 } 396 397 /** 398 * Test simple message save/retrieve 399 * 400 * TODO: serverId vs. serverIntId 401 */ 402 public void testMessageSave() { 403 Account account1 = ProviderTestUtils.setupAccount("message-save", true, mMockContext); 404 long account1Id = account1.mId; 405 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 406 long box1Id = box1.mId; 407 408 // Test a simple message (saved with no body) 409 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 410 true, mMockContext); 411 long message1Id = message1.mId; 412 Message message1get = EmailContent.Message.restoreMessageWithId(mMockContext, message1Id); 413 ProviderTestUtils.assertMessageEqual("testMessageSave", message1, message1get); 414 415 // Test a message saved with a body 416 // Note that it will read back w/o the text & html so we must extract those 417 Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true, 418 true, mMockContext); 419 long message2Id = message2.mId; 420 String text2 = message2.mText; 421 String html2 = message2.mHtml; 422 String textReply2 = message2.mTextReply; 423 String htmlReply2 = message2.mHtmlReply; 424 long sourceKey2 = message2.mSourceKey; 425 String introText2 = message2.mIntroText; 426 message2.mText = null; 427 message2.mHtml = null; 428 message2.mTextReply = null; 429 message2.mHtmlReply = null; 430 message2.mSourceKey = 0; 431 message2.mIntroText = null; 432 Message message2get = EmailContent.Message.restoreMessageWithId(mMockContext, message2Id); 433 ProviderTestUtils.assertMessageEqual("testMessageSave", message2, message2get); 434 435 // Now see if there's a body saved with the right stuff 436 Body body2 = loadBodyForMessageId(message2Id); 437 assertEquals("body text", text2, body2.mTextContent); 438 assertEquals("body html", html2, body2.mHtmlContent); 439 assertEquals("reply text", textReply2, body2.mTextReply); 440 assertEquals("reply html", htmlReply2, body2.mHtmlReply); 441 assertEquals("source key", sourceKey2, body2.mSourceKey); 442 assertEquals("intro text", introText2, body2.mIntroText); 443 444 // Message with attachments and body 445 Message message3 = ProviderTestUtils.setupMessage("message3", account1Id, box1Id, true, 446 false, mMockContext); 447 ArrayList<Attachment> atts = new ArrayList<Attachment>(); 448 for (int i = 0; i < 3; i++) { 449 atts.add(ProviderTestUtils.setupAttachment( 450 -1, expectedAttachmentNames[i], expectedAttachmentSizes[i], 451 false, mMockContext)); 452 } 453 message3.mAttachments = atts; 454 message3.save(mMockContext); 455 long message3Id = message3.mId; 456 457 // Now check the attachments; there should be three and they should match name and size 458 Cursor c = null; 459 try { 460 // Note that there is NO guarantee of the order of returned records in the general case, 461 // so we specifically ask for ordering by size. The expectedAttachmentSizes array must 462 // be kept sorted by size (ascending) for this test to work properly 463 c = mMockContext.getContentResolver().query( 464 Attachment.CONTENT_URI, 465 Attachment.CONTENT_PROJECTION, 466 Attachment.MESSAGE_KEY + "=?", 467 new String[] { 468 String.valueOf(message3Id) 469 }, 470 Attachment.SIZE); 471 int numAtts = c.getCount(); 472 assertEquals(3, numAtts); 473 int i = 0; 474 while (c.moveToNext()) { 475 Attachment actual = EmailContent.getContent(c, Attachment.class); 476 ProviderTestUtils.assertAttachmentEqual("save-message3", atts.get(i), actual); 477 i++; 478 } 479 } finally { 480 c.close(); 481 } 482 483 // Message with attachments but no body 484 Message message4 = ProviderTestUtils.setupMessage("message4", account1Id, box1Id, false, 485 false, mMockContext); 486 atts = new ArrayList<Attachment>(); 487 for (int i = 0; i < 3; i++) { 488 atts.add(ProviderTestUtils.setupAttachment( 489 -1, expectedAttachmentNames[i], expectedAttachmentSizes[i], 490 false, mMockContext)); 491 } 492 message4.mAttachments = atts; 493 message4.save(mMockContext); 494 long message4Id = message4.mId; 495 496 // Now check the attachments; there should be three and they should match name and size 497 c = null; 498 499 try { 500 // Note that there is NO guarantee of the order of returned records in the general case, 501 // so we specifically ask for ordering by size. The expectedAttachmentSizes array must 502 // be kept sorted by size (ascending) for this test to work properly 503 c = mMockContext.getContentResolver().query( 504 Attachment.CONTENT_URI, 505 Attachment.CONTENT_PROJECTION, 506 Attachment.MESSAGE_KEY + "=?", 507 new String[] { 508 String.valueOf(message4Id) 509 }, 510 Attachment.SIZE); 511 int numAtts = c.getCount(); 512 assertEquals(3, numAtts); 513 int i = 0; 514 while (c.moveToNext()) { 515 Attachment actual = EmailContent.getContent(c, Attachment.class); 516 ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), actual); 517 i++; 518 } 519 } finally { 520 c.close(); 521 } 522 523 // test EmailContent.restoreAttachmentsWitdMessageId() 524 Attachment[] attachments = 525 Attachment.restoreAttachmentsWithMessageId(mMockContext, message4Id); 526 int size = attachments.length; 527 assertEquals(3, size); 528 for (int i = 0; i < size; ++i) { 529 ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), attachments[i]); 530 } 531 } 532 533 /** 534 * Test that saving a message creates the proper snippet for that message 535 */ 536 public void testMessageSaveAddsSnippet() { 537 Account account = ProviderTestUtils.setupAccount("message-snippet", true, mMockContext); 538 Mailbox box = ProviderTestUtils.setupMailbox("box1", account.mId, true, mMockContext); 539 540 // Create a message without a body, unsaved 541 Message message = ProviderTestUtils.setupMessage("message", account.mId, box.mId, false, 542 false, mMockContext); 543 message.mText = "This is some text"; 544 message.mHtml = "<html>This is some text</html>"; 545 message.save(mMockContext); 546 Message restoredMessage = Message.restoreMessageWithId(mMockContext, message.mId); 547 // We should have the plain text as the snippet 548 assertEquals(restoredMessage.mSnippet, Snippet.fromPlainText(message.mText)); 549 550 // Start again 551 message = ProviderTestUtils.setupMessage("message", account.mId, box.mId, false, 552 false, mMockContext); 553 message.mText = null; 554 message.mHtml = "<html>This is some text</html>"; 555 message.save(mMockContext); 556 restoredMessage = Message.restoreMessageWithId(mMockContext, message.mId); 557 // We should have the plain text as the snippet 558 assertEquals(restoredMessage.mSnippet, Snippet.fromHtmlText(message.mHtml)); 559 } 560 561 /** 562 * TODO: update account 563 */ 564 565 /** 566 * TODO: update mailbox 567 */ 568 569 /** 570 * TODO: update message 571 */ 572 573 /** 574 * Test delete account 575 * TODO: hostauth 576 */ 577 public void testAccountDelete() { 578 Account account1 = ProviderTestUtils.setupAccount("account-delete-1", true, mMockContext); 579 long account1Id = account1.mId; 580 Account account2 = ProviderTestUtils.setupAccount("account-delete-2", true, mMockContext); 581 long account2Id = account2.mId; 582 583 // make sure there are two accounts 584 int numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 585 assertEquals(2, numBoxes); 586 587 // now delete one of them 588 Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id); 589 mMockContext.getContentResolver().delete(uri, null, null); 590 591 // make sure there's only one account now 592 numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 593 assertEquals(1, numBoxes); 594 595 // now delete the other one 596 uri = ContentUris.withAppendedId(Account.CONTENT_URI, account2Id); 597 mMockContext.getContentResolver().delete(uri, null, null); 598 599 // make sure there are no accounts now 600 numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 601 assertEquals(0, numBoxes); 602 } 603 604 /** 605 * Test for Body.lookupBodyIdWithMessageId() 606 * Verifies that: 607 * - for a message without body, -1 is returned. 608 * - for a mesage with body, the id matches the one from loadBodyForMessageId. 609 */ 610 public void testLookupBodyIdWithMessageId() { 611 final ContentResolver resolver = mMockContext.getContentResolver(); 612 Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext); 613 long account1Id = account1.mId; 614 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 615 long box1Id = box1.mId; 616 617 // 1. create message with no body, check that returned bodyId is -1 618 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 619 true, mMockContext); 620 long message1Id = message1.mId; 621 long bodyId1 = Body.lookupBodyIdWithMessageId(mMockContext, message1Id); 622 assertEquals(bodyId1, -1); 623 624 // 2. create message with body, check that returned bodyId is correct 625 Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true, 626 true, mMockContext); 627 long message2Id = message2.mId; 628 long bodyId2 = Body.lookupBodyIdWithMessageId(mMockContext, message2Id); 629 Body body = loadBodyForMessageId(message2Id); 630 assertNotNull(body); 631 assertEquals(body.mId, bodyId2); 632 } 633 634 /** 635 * Test for Body.updateBodyWithMessageId(). 636 * 1. - create message without body, 637 * - update its body (set TEXT_CONTENT) 638 * - check correct updated body is read back 639 * 640 * 2. - create message with body, 641 * - update body (set TEXT_CONTENT) 642 * - check correct updated body is read back 643 */ 644 public void testUpdateBodyWithMessageId() { 645 Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext); 646 long account1Id = account1.mId; 647 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 648 long box1Id = box1.mId; 649 650 final String textContent = "foobar some odd text"; 651 final String htmlContent = "and some html"; 652 final String textReply = "plain text reply"; 653 final String htmlReply = "or the html reply"; 654 final String introText = "fred wrote:"; 655 656 ContentValues values = new ContentValues(); 657 values.put(BodyColumns.TEXT_CONTENT, textContent); 658 values.put(BodyColumns.HTML_CONTENT, htmlContent); 659 values.put(BodyColumns.TEXT_REPLY, textReply); 660 values.put(BodyColumns.HTML_REPLY, htmlReply); 661 values.put(BodyColumns.SOURCE_MESSAGE_KEY, 17); 662 values.put(BodyColumns.INTRO_TEXT, introText); 663 664 // 1 665 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 666 true, mMockContext); 667 long message1Id = message1.mId; 668 Body body1 = loadBodyForMessageId(message1Id); 669 assertNull(body1); 670 Body.updateBodyWithMessageId(mMockContext, message1Id, values); 671 body1 = loadBodyForMessageId(message1Id); 672 assertNotNull(body1); 673 assertEquals(body1.mTextContent, textContent); 674 assertEquals(body1.mHtmlContent, htmlContent); 675 assertEquals(body1.mTextReply, textReply); 676 assertEquals(body1.mHtmlReply, htmlReply); 677 assertEquals(body1.mSourceKey, 17); 678 assertEquals(body1.mIntroText, introText); 679 680 // 2 681 Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true, 682 true, mMockContext); 683 long message2Id = message2.mId; 684 Body body2 = loadBodyForMessageId(message2Id); 685 assertNotNull(body2); 686 assertTrue(!body2.mTextContent.equals(textContent)); 687 Body.updateBodyWithMessageId(mMockContext, message2Id, values); 688 body2 = loadBodyForMessageId(message1Id); 689 assertNotNull(body2); 690 assertEquals(body2.mTextContent, textContent); 691 assertEquals(body2.mHtmlContent, htmlContent); 692 assertEquals(body2.mTextReply, textReply); 693 assertEquals(body2.mHtmlReply, htmlReply); 694 assertEquals(body2.mSourceKey, 17); 695 assertEquals(body2.mIntroText, introText); 696 } 697 698 /** 699 * Test body retrieve methods 700 */ 701 public void testBodyRetrieve() { 702 // No account needed 703 // No mailbox needed 704 Message message1 = ProviderTestUtils.setupMessage("bodyretrieve", 1, 1, true, 705 true, mMockContext); 706 long messageId = message1.mId; 707 708 assertEquals(message1.mText, 709 Body.restoreBodyTextWithMessageId(mMockContext, messageId)); 710 assertEquals(message1.mHtml, 711 Body.restoreBodyHtmlWithMessageId(mMockContext, messageId)); 712 assertEquals(message1.mTextReply, 713 Body.restoreReplyTextWithMessageId(mMockContext, messageId)); 714 assertEquals(message1.mHtmlReply, 715 Body.restoreReplyHtmlWithMessageId(mMockContext, messageId)); 716 assertEquals(message1.mIntroText, 717 Body.restoreIntroTextWithMessageId(mMockContext, messageId)); 718 assertEquals(message1.mSourceKey, 719 Body.restoreBodySourceKey(mMockContext, messageId)); 720 } 721 722 /** 723 * Test delete body. 724 * 1. create message without body (message id 1) 725 * 2. create message with body (message id 2. The body has _id 1 and messageKey 2). 726 * 3. delete first message. 727 * 4. verify that body for message 2 has not been deleted. 728 * 5. delete message 2, verify body is deleted. 729 */ 730 public void testDeleteBody() { 731 final ContentResolver resolver = mMockContext.getContentResolver(); 732 733 // Create account and mailboxes 734 Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext); 735 long account1Id = account1.mId; 736 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 737 long box1Id = box1.mId; 738 739 // 1. create message without body 740 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 741 true, mMockContext); 742 long message1Id = message1.mId; 743 744 // 2. create message with body 745 Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true, 746 true, mMockContext); 747 long message2Id = message2.mId; 748 // verify body is there 749 assertNotNull(loadBodyForMessageId(message2Id)); 750 751 // 3. delete first message 752 resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null); 753 754 // 4. verify body for second message wasn't deleted 755 assertNotNull(loadBodyForMessageId(message2Id)); 756 757 // 5. delete second message, check its body is deleted 758 resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message2Id), null, null); 759 assertNull(loadBodyForMessageId(message2Id)); 760 } 761 762 /** 763 * Test delete orphan bodies. 764 * 1. create message without body (message id 1) 765 * 2. create message with body (message id 2. Body has _id 1 and messageKey 2). 766 * 3. delete first message. 767 * 4. delete some other mailbox -- this triggers delete orphan bodies. 768 * 5. verify that body for message 2 has not been deleted. 769 */ 770 public void testDeleteOrphanBodies() { 771 final ContentResolver resolver = mMockContext.getContentResolver(); 772 773 // Create account and two mailboxes 774 Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext); 775 long account1Id = account1.mId; 776 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 777 long box1Id = box1.mId; 778 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mMockContext); 779 long box2Id = box2.mId; 780 781 // 1. create message without body 782 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 783 true, mMockContext); 784 long message1Id = message1.mId; 785 786 // 2. create message with body 787 Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true, 788 true, mMockContext); 789 long message2Id = message2.mId; 790 //verify body is there 791 assertNotNull(loadBodyForMessageId(message2Id)); 792 793 // 3. delete first message 794 resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null); 795 796 // 4. delete some mailbox (because it triggers "delete orphan bodies") 797 resolver.delete(ContentUris.withAppendedId(Mailbox.CONTENT_URI, box2Id), null, null); 798 799 // 5. verify body for second message wasn't deleted during "delete orphan bodies" 800 assertNotNull(loadBodyForMessageId(message2Id)); 801 } 802 803 /** 804 * Note that we can't use EmailContent.count() here because it uses a projection including 805 * count(*), and count(*) is incompatible with a LIMIT (i.e. the limit would be applied to the 806 * single column returned with count(*), rather than to the query itself) 807 */ 808 private int count(Context context, Uri uri, String selection, String[] selectionArgs) { 809 Cursor c = context.getContentResolver().query(uri, EmailContent.ID_PROJECTION, selection, 810 selectionArgs, null); 811 try { 812 return c.getCount(); 813 } finally { 814 c.close(); 815 } 816 } 817 818 public void testMessageQueryWithLimit() { 819 final Context context = mMockContext; 820 821 // Create account and two mailboxes 822 Account acct = ProviderTestUtils.setupAccount("orphaned body", true, context); 823 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context); 824 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context); 825 826 // Create 4 messages in box1 827 ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, false, true, context); 828 ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, false, true, context); 829 ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, false, true, context); 830 ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, false, true, context); 831 832 // Create 4 messages in box2 833 ProviderTestUtils.setupMessage("message1", acct.mId, box2.mId, false, true, context); 834 ProviderTestUtils.setupMessage("message2", acct.mId, box2.mId, false, true, context); 835 ProviderTestUtils.setupMessage("message3", acct.mId, box2.mId, false, true, context); 836 ProviderTestUtils.setupMessage("message4", acct.mId, box2.mId, false, true, context); 837 838 // Check normal case, special case (limit 1), and arbitrary limits 839 assertEquals(8, count(mMockContext, Message.CONTENT_URI, null, null)); 840 assertEquals(1, count(mMockContext, EmailContent.uriWithLimit(Message.CONTENT_URI, 1), 841 null, null)); 842 assertEquals(3, count(mMockContext, EmailContent.uriWithLimit(Message.CONTENT_URI, 3), 843 null, null)); 844 assertEquals(8, count(mMockContext, EmailContent.uriWithLimit(Message.CONTENT_URI, 100), 845 null, null)); 846 847 // Check that it works with selection/selection args 848 String[] args = new String[] {Long.toString(box1.mId)}; 849 assertEquals(4, count(mMockContext, Message.CONTENT_URI, 850 MessageColumns.MAILBOX_KEY + "=?", args)); 851 assertEquals(1, count(mMockContext, 852 EmailContent.uriWithLimit(Message.CONTENT_URI, 1), 853 MessageColumns.MAILBOX_KEY + "=?", args)); 854 } 855 856 /** 857 * Test delete orphan messages 858 * 1. create message without body (message id 1) 859 * 2. create message with body (message id 2. Body has _id 1 and messageKey 2). 860 * 3. delete first message. 861 * 4. delete some other mailbox -- this triggers delete orphan bodies. 862 * 5. verify that body for message 2 has not been deleted. 863 */ 864 public void testDeleteOrphanMessages() { 865 final ContentResolver resolver = mMockContext.getContentResolver(); 866 final Context context = mMockContext; 867 868 // Create account and two mailboxes 869 Account acct = ProviderTestUtils.setupAccount("orphaned body", true, context); 870 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context); 871 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context); 872 873 // Create 4 messages in box1 874 Message msg1_1 = 875 ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, false, true, context); 876 Message msg1_2 = 877 ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, false, true, context); 878 Message msg1_3 = 879 ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, false, true, context); 880 Message msg1_4 = 881 ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, false, true, context); 882 883 // Create 4 messages in box2 884 Message msg2_1 = 885 ProviderTestUtils.setupMessage("message1", acct.mId, box2.mId, false, true, context); 886 Message msg2_2 = 887 ProviderTestUtils.setupMessage("message2", acct.mId, box2.mId, false, true, context); 888 Message msg2_3 = 889 ProviderTestUtils.setupMessage("message3", acct.mId, box2.mId, false, true, context); 890 Message msg2_4 = 891 ProviderTestUtils.setupMessage("message4", acct.mId, box2.mId, false, true, context); 892 893 // Delete 2 from each mailbox 894 resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_1.mId), 895 null, null); 896 resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_2.mId), 897 null, null); 898 resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_1.mId), 899 null, null); 900 resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_2.mId), 901 null, null); 902 903 // There should be 4 items in the deleted item table 904 assertEquals(4, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null)); 905 906 // Update 2 from each mailbox 907 ContentValues v = new ContentValues(); 908 v.put(MessageColumns.DISPLAY_NAME, "--updated--"); 909 resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_3.mId), 910 v, null, null); 911 resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_4.mId), 912 v, null, null); 913 resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_3.mId), 914 v, null, null); 915 resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_4.mId), 916 v, null, null); 917 918 // There should be 4 items in the updated item table 919 assertEquals(4, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null)); 920 921 // Manually add 2 messages from a "deleted" mailbox to deleted and updated tables 922 // Use a value > 2 for the deleted box id 923 long delBoxId = 10; 924 // Create 4 messages in the "deleted" mailbox 925 Message msgX_A = 926 ProviderTestUtils.setupMessage("messageA", acct.mId, delBoxId, false, false, context); 927 Message msgX_B = 928 ProviderTestUtils.setupMessage("messageB", acct.mId, delBoxId, false, false, context); 929 Message msgX_C = 930 ProviderTestUtils.setupMessage("messageC", acct.mId, delBoxId, false, false, context); 931 Message msgX_D = 932 ProviderTestUtils.setupMessage("messageD", acct.mId, delBoxId, false, false, context); 933 934 ContentValues cv; 935 // We have to assign id's manually because there are no autoincrement id's for these tables 936 // Start with an id that won't exist, since id's in these tables must be unique 937 long msgId = 10; 938 // It's illegal to manually insert these, so we need to catch the exception 939 // NOTE: The insert succeeds, and then throws the exception 940 try { 941 cv = msgX_A.toContentValues(); 942 cv.put(EmailContent.RECORD_ID, msgId++); 943 resolver.insert(Message.DELETED_CONTENT_URI, cv); 944 } catch (IllegalArgumentException e) { 945 } 946 try { 947 cv = msgX_B.toContentValues(); 948 cv.put(EmailContent.RECORD_ID, msgId++); 949 resolver.insert(Message.DELETED_CONTENT_URI, cv); 950 } catch (IllegalArgumentException e) { 951 } 952 try { 953 cv = msgX_C.toContentValues(); 954 cv.put(EmailContent.RECORD_ID, msgId++); 955 resolver.insert(Message.UPDATED_CONTENT_URI, cv); 956 } catch (IllegalArgumentException e) { 957 } 958 try { 959 cv = msgX_D.toContentValues(); 960 cv.put(EmailContent.RECORD_ID, msgId++); 961 resolver.insert(Message.UPDATED_CONTENT_URI, cv); 962 } catch (IllegalArgumentException e) { 963 } 964 965 // There should be 6 items in the deleted and updated tables 966 assertEquals(6, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null)); 967 assertEquals(6, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null)); 968 969 // Delete the orphans 970 EmailProvider.deleteOrphans(EmailProvider.getReadableDatabase(context), 971 Message.DELETED_TABLE_NAME); 972 EmailProvider.deleteOrphans(EmailProvider.getReadableDatabase(context), 973 Message.UPDATED_TABLE_NAME); 974 975 // There should now be 4 messages in each of the deleted and updated tables again 976 assertEquals(4, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null)); 977 assertEquals(4, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null)); 978 } 979 980 /** 981 * Test delete mailbox 982 */ 983 public void testMailboxDelete() { 984 Account account1 = ProviderTestUtils.setupAccount("mailbox-delete", true, mMockContext); 985 long account1Id = account1.mId; 986 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 987 long box1Id = box1.mId; 988 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mMockContext); 989 long box2Id = box2.mId; 990 991 String selection = EmailContent.MailboxColumns.ACCOUNT_KEY + "=?"; 992 String[] selArgs = new String[] { String.valueOf(account1Id) }; 993 994 // make sure there are two mailboxes 995 int numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs); 996 assertEquals(2, numBoxes); 997 998 // now delete one of them 999 Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box1Id); 1000 mMockContext.getContentResolver().delete(uri, null, null); 1001 1002 // make sure there's only one mailbox now 1003 numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs); 1004 assertEquals(1, numBoxes); 1005 1006 // now delete the other one 1007 uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box2Id); 1008 mMockContext.getContentResolver().delete(uri, null, null); 1009 1010 // make sure there are no mailboxes now 1011 numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs); 1012 assertEquals(0, numBoxes); 1013 } 1014 1015 /** 1016 * Test delete message 1017 * TODO: body 1018 * TODO: attachments 1019 */ 1020 public void testMessageDelete() { 1021 Account account1 = ProviderTestUtils.setupAccount("message-delete", true, mMockContext); 1022 long account1Id = account1.mId; 1023 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1024 long box1Id = box1.mId; 1025 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 1026 true, mMockContext); 1027 long message1Id = message1.mId; 1028 Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false, 1029 true, mMockContext); 1030 long message2Id = message2.mId; 1031 1032 String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " + 1033 EmailContent.MessageColumns.MAILBOX_KEY + "=?"; 1034 String[] selArgs = new String[] { String.valueOf(account1Id), String.valueOf(box1Id) }; 1035 1036 // make sure there are two messages 1037 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1038 assertEquals(2, numMessages); 1039 1040 // now delete one of them 1041 Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id); 1042 mMockContext.getContentResolver().delete(uri, null, null); 1043 1044 // make sure there's only one message now 1045 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1046 assertEquals(1, numMessages); 1047 1048 // now delete the other one 1049 uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id); 1050 mMockContext.getContentResolver().delete(uri, null, null); 1051 1052 // make sure there are no messages now 1053 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1054 assertEquals(0, numMessages); 1055 } 1056 1057 /** 1058 * Test delete synced message 1059 * TODO: body 1060 * TODO: attachments 1061 */ 1062 public void testSyncedMessageDelete() { 1063 Account account1 = ProviderTestUtils.setupAccount("synced-message-delete", true, 1064 mMockContext); 1065 long account1Id = account1.mId; 1066 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1067 long box1Id = box1.mId; 1068 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 1069 true, mMockContext); 1070 long message1Id = message1.mId; 1071 Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false, 1072 true, mMockContext); 1073 long message2Id = message2.mId; 1074 1075 String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " 1076 + EmailContent.MessageColumns.MAILBOX_KEY + "=?"; 1077 String[] selArgs = new String[] { 1078 String.valueOf(account1Id), String.valueOf(box1Id) 1079 }; 1080 1081 // make sure there are two messages 1082 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1083 assertEquals(2, numMessages); 1084 1085 // make sure we start with no synced deletions 1086 numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, 1087 selArgs); 1088 assertEquals(0, numMessages); 1089 1090 // now delete one of them SYNCED 1091 Uri uri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message1Id); 1092 mMockContext.getContentResolver().delete(uri, null, null); 1093 1094 // make sure there's only one message now 1095 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1096 assertEquals(1, numMessages); 1097 1098 // make sure there's one synced deletion now 1099 numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, 1100 selArgs); 1101 assertEquals(1, numMessages); 1102 1103 // now delete the other one NOT SYNCED 1104 uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id); 1105 mMockContext.getContentResolver().delete(uri, null, null); 1106 1107 // make sure there are no messages now 1108 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1109 assertEquals(0, numMessages); 1110 1111 // make sure there's still one deletion now 1112 numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, 1113 selArgs); 1114 assertEquals(1, numMessages); 1115 } 1116 1117 /** 1118 * Test message update 1119 * TODO: body 1120 * TODO: attachments 1121 */ 1122 public void testMessageUpdate() { 1123 Account account1 = ProviderTestUtils.setupAccount("message-update", true, mMockContext); 1124 long account1Id = account1.mId; 1125 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1126 long box1Id = box1.mId; 1127 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 1128 true, mMockContext); 1129 long message1Id = message1.mId; 1130 Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false, 1131 true, mMockContext); 1132 long message2Id = message2.mId; 1133 ContentResolver cr = mMockContext.getContentResolver(); 1134 1135 String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " 1136 + EmailContent.MessageColumns.MAILBOX_KEY + "=?"; 1137 String[] selArgs = new String[] { 1138 String.valueOf(account1Id), String.valueOf(box1Id) 1139 }; 1140 1141 // make sure there are two messages 1142 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1143 assertEquals(2, numMessages); 1144 1145 // change the first one 1146 Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id); 1147 ContentValues cv = new ContentValues(); 1148 cv.put(MessageColumns.FROM_LIST, "from-list"); 1149 cr.update(uri, cv, null, null); 1150 1151 // make sure there's no updated message 1152 numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, 1153 selArgs); 1154 assertEquals(0, numMessages); 1155 1156 // get the message back from the provider, make sure the change "stuck" 1157 Message restoredMessage = Message.restoreMessageWithId(mMockContext, message1Id); 1158 assertEquals("from-list", restoredMessage.mFrom); 1159 1160 // change the second one 1161 uri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2Id); 1162 cv = new ContentValues(); 1163 cv.put(MessageColumns.FROM_LIST, "from-list"); 1164 cr.update(uri, cv, null, null); 1165 1166 // make sure there's one updated message 1167 numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, 1168 selArgs); 1169 assertEquals(1, numMessages); 1170 1171 // get the message back from the provider, make sure the change "stuck", 1172 // as before 1173 restoredMessage = Message.restoreMessageWithId(mMockContext, message2Id); 1174 assertEquals("from-list", restoredMessage.mFrom); 1175 1176 // get the original message back from the provider 1177 Cursor c = cr.query(Message.UPDATED_CONTENT_URI, Message.CONTENT_PROJECTION, null, null, 1178 null); 1179 try { 1180 assertTrue(c.moveToFirst()); 1181 Message originalMessage = EmailContent.getContent(c, Message.class); 1182 // make sure this has the original value 1183 assertEquals("from message2", originalMessage.mFrom); 1184 // Should only be one 1185 assertFalse(c.moveToNext()); 1186 } finally { 1187 c.close(); 1188 } 1189 1190 // delete the second message 1191 cr.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2Id), null, null); 1192 1193 // hey, presto! the change should be gone 1194 numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, 1195 selArgs); 1196 assertEquals(0, numMessages); 1197 1198 // and there should now be a deleted record 1199 numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, 1200 selArgs); 1201 assertEquals(1, numMessages); 1202 } 1203 1204 /** 1205 * TODO: cascaded delete account 1206 * TODO: hostauth 1207 * TODO: body 1208 * TODO: attachments 1209 * TODO: create other account, mailbox & messages and confirm the right objects were deleted 1210 */ 1211 public void testCascadeDeleteAccount() { 1212 Account account1 = ProviderTestUtils.setupAccount("account-delete-cascade", true, 1213 mMockContext); 1214 long account1Id = account1.mId; 1215 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1216 long box1Id = box1.mId; 1217 /* Message message1 = */ ProviderTestUtils.setupMessage("message1", account1Id, box1Id, 1218 false, true, mMockContext); 1219 /* Message message2 = */ ProviderTestUtils.setupMessage("message2", account1Id, box1Id, 1220 false, true, mMockContext); 1221 1222 // make sure there is one account, one mailbox, and two messages 1223 int numAccounts = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 1224 assertEquals(1, numAccounts); 1225 int numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, null, null); 1226 assertEquals(1, numBoxes); 1227 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1228 assertEquals(2, numMessages); 1229 1230 // delete the account 1231 Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id); 1232 mMockContext.getContentResolver().delete(uri, null, null); 1233 1234 // make sure there are no accounts, mailboxes, or messages 1235 numAccounts = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 1236 assertEquals(0, numAccounts); 1237 numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, null, null); 1238 assertEquals(0, numBoxes); 1239 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1240 assertEquals(0, numMessages); 1241 } 1242 1243 /** 1244 * Test cascaded delete mailbox 1245 * TODO: body 1246 * TODO: attachments 1247 * TODO: create other mailbox & messages and confirm the right objects were deleted 1248 */ 1249 public void testCascadeDeleteMailbox() { 1250 Account account1 = ProviderTestUtils.setupAccount("mailbox-delete-cascade", true, 1251 mMockContext); 1252 long account1Id = account1.mId; 1253 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1254 long box1Id = box1.mId; 1255 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, 1256 false, true, mMockContext); 1257 Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, 1258 false, true, mMockContext); 1259 Message message3 = ProviderTestUtils.setupMessage("message3", account1Id, box1Id, 1260 false, true, mMockContext); 1261 Message message4 = ProviderTestUtils.setupMessage("message4", account1Id, box1Id, 1262 false, true, mMockContext); 1263 ProviderTestUtils.setupMessage("message5", account1Id, box1Id, false, true, mMockContext); 1264 ProviderTestUtils.setupMessage("message6", account1Id, box1Id, false, true, mMockContext); 1265 1266 String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " + 1267 EmailContent.MessageColumns.MAILBOX_KEY + "=?"; 1268 String[] selArgs = new String[] { String.valueOf(account1Id), String.valueOf(box1Id) }; 1269 1270 // make sure there are six messages 1271 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1272 assertEquals(6, numMessages); 1273 1274 ContentValues cv = new ContentValues(); 1275 cv.put(Message.SERVER_ID, "SERVER_ID"); 1276 ContentResolver resolver = mMockContext.getContentResolver(); 1277 1278 // Update two messages 1279 resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message1.mId), 1280 cv, null, null); 1281 resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2.mId), 1282 cv, null, null); 1283 // Delete two messages 1284 resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message3.mId), 1285 null, null); 1286 resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message4.mId), 1287 null, null); 1288 1289 // There should now be two messages in updated/deleted, and 4 in messages 1290 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1291 assertEquals(4, numMessages); 1292 numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, 1293 selArgs); 1294 assertEquals(2, numMessages); 1295 numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, 1296 selArgs); 1297 assertEquals(2, numMessages); 1298 1299 // now delete the mailbox 1300 Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box1Id); 1301 resolver.delete(uri, null, null); 1302 1303 // there should now be zero messages in all three tables 1304 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1305 assertEquals(0, numMessages); 1306 numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, 1307 selArgs); 1308 assertEquals(0, numMessages); 1309 numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, 1310 selArgs); 1311 assertEquals(0, numMessages); 1312 } 1313 1314 /** 1315 * Test cascaded delete message 1316 * Confirms that deleting a message will also delete its body & attachments 1317 */ 1318 public void testCascadeMessageDelete() { 1319 Account account1 = ProviderTestUtils.setupAccount("message-cascade", true, mMockContext); 1320 long account1Id = account1.mId; 1321 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1322 long box1Id = box1.mId; 1323 1324 // Each message has a body, and also give each 2 attachments 1325 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true, 1326 false, mMockContext); 1327 ArrayList<Attachment> atts = new ArrayList<Attachment>(); 1328 for (int i = 0; i < 2; i++) { 1329 atts.add(ProviderTestUtils.setupAttachment( 1330 -1, expectedAttachmentNames[i], expectedAttachmentSizes[i], 1331 false, mMockContext)); 1332 } 1333 message1.mAttachments = atts; 1334 message1.save(mMockContext); 1335 long message1Id = message1.mId; 1336 1337 Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, true, 1338 false, mMockContext); 1339 atts = new ArrayList<Attachment>(); 1340 for (int i = 0; i < 2; i++) { 1341 atts.add(ProviderTestUtils.setupAttachment( 1342 -1, expectedAttachmentNames[i], expectedAttachmentSizes[i], 1343 false, mMockContext)); 1344 } 1345 message2.mAttachments = atts; 1346 message2.save(mMockContext); 1347 long message2Id = message2.mId; 1348 1349 // Set up to test total counts of bodies & attachments for our test messages 1350 String bodySelection = BodyColumns.MESSAGE_KEY + " IN (?,?)"; 1351 String attachmentSelection = AttachmentColumns.MESSAGE_KEY + " IN (?,?)"; 1352 String[] selArgs = new String[] { String.valueOf(message1Id), String.valueOf(message2Id) }; 1353 1354 // make sure there are two bodies 1355 int numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs); 1356 assertEquals(2, numBodies); 1357 1358 // make sure there are four attachments 1359 int numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI, 1360 attachmentSelection, selArgs); 1361 assertEquals(4, numAttachments); 1362 1363 // now delete one of the messages 1364 Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id); 1365 mMockContext.getContentResolver().delete(uri, null, null); 1366 1367 // there should be one body and two attachments 1368 numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs); 1369 assertEquals(1, numBodies); 1370 1371 numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI, 1372 attachmentSelection, selArgs); 1373 assertEquals(2, numAttachments); 1374 1375 // now delete the other message 1376 uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id); 1377 mMockContext.getContentResolver().delete(uri, null, null); 1378 1379 // make sure there are no bodies or attachments 1380 numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs); 1381 assertEquals(0, numBodies); 1382 1383 numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI, 1384 attachmentSelection, selArgs); 1385 assertEquals(0, numAttachments); 1386 } 1387 1388 /** 1389 * Test that our unique file name algorithm works as expected. Since this test requires an 1390 * SD card, we check the environment first, and return immediately if none is mounted. 1391 * @throws IOException 1392 */ 1393 public void testCreateUniqueFile() throws IOException { 1394 // Delete existing files, if they exist 1395 if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 1396 return; 1397 } 1398 try { 1399 String fileName = "A11achm3n1.doc"; 1400 File uniqueFile = Attachment.createUniqueFile(fileName); 1401 assertEquals(fileName, uniqueFile.getName()); 1402 if (uniqueFile.createNewFile()) { 1403 uniqueFile = Attachment.createUniqueFile(fileName); 1404 assertEquals("A11achm3n1-2.doc", uniqueFile.getName()); 1405 if (uniqueFile.createNewFile()) { 1406 uniqueFile = Attachment.createUniqueFile(fileName); 1407 assertEquals("A11achm3n1-3.doc", uniqueFile.getName()); 1408 } 1409 } 1410 fileName = "A11achm3n1"; 1411 uniqueFile = Attachment.createUniqueFile(fileName); 1412 assertEquals(fileName, uniqueFile.getName()); 1413 if (uniqueFile.createNewFile()) { 1414 uniqueFile = Attachment.createUniqueFile(fileName); 1415 assertEquals("A11achm3n1-2", uniqueFile.getName()); 1416 } 1417 } finally { 1418 File directory = Environment.getExternalStorageDirectory(); 1419 // These are the files that should be created earlier in the test. Make sure 1420 // they are deleted for the next go-around 1421 String[] fileNames = new String[] {"A11achm3n1.doc", "A11achm3n1-2.doc", "A11achm3n1"}; 1422 int length = fileNames.length; 1423 for (int i = 0; i < length; i++) { 1424 File file = new File(directory, fileNames[i]); 1425 if (file.exists()) { 1426 file.delete(); 1427 } 1428 } 1429 } 1430 } 1431 1432 /** 1433 * Test retrieving attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI) 1434 */ 1435 public void testGetAttachmentByMessageIdUri() { 1436 1437 // Note, we don't strictly need accounts, mailboxes or messages to run this test. 1438 Attachment a1 = ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext); 1439 Attachment a2 = ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext); 1440 ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext); 1441 ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext); 1442 1443 // Now ask for the attachments of message id=1 1444 // Note: Using the "sort by size" trick to bring them back in expected order 1445 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1); 1446 Cursor c = mMockContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION, 1447 null, null, Attachment.SIZE); 1448 assertEquals(2, c.getCount()); 1449 1450 try { 1451 c.moveToFirst(); 1452 Attachment a1Get = EmailContent.getContent(c, Attachment.class); 1453 ProviderTestUtils.assertAttachmentEqual("getAttachByUri-1", a1, a1Get); 1454 c.moveToNext(); 1455 Attachment a2Get = EmailContent.getContent(c, Attachment.class); 1456 ProviderTestUtils.assertAttachmentEqual("getAttachByUri-2", a2, a2Get); 1457 } finally { 1458 c.close(); 1459 } 1460 } 1461 1462 /** 1463 * Test deleting attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI) 1464 */ 1465 public void testDeleteAttachmentByMessageIdUri() { 1466 ContentResolver mockResolver = mMockContext.getContentResolver(); 1467 1468 // Note, we don't strictly need accounts, mailboxes or messages to run this test. 1469 ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext); 1470 ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext); 1471 Attachment a3 = ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext); 1472 Attachment a4 = ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext); 1473 1474 // Delete all attachments for message id=1 1475 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1); 1476 mockResolver.delete(uri, null, null); 1477 1478 // Read back all attachments and confirm that we have the expected remaining attachments 1479 // (the attachments that are set for message id=2). Note order-by size to simplify test. 1480 Cursor c = mockResolver.query(Attachment.CONTENT_URI, Attachment.CONTENT_PROJECTION, 1481 null, null, Attachment.SIZE); 1482 assertEquals(2, c.getCount()); 1483 1484 try { 1485 c.moveToFirst(); 1486 Attachment a3Get = EmailContent.getContent(c, Attachment.class); 1487 ProviderTestUtils.assertAttachmentEqual("getAttachByUri-3", a3, a3Get); 1488 c.moveToNext(); 1489 Attachment a4Get = EmailContent.getContent(c, Attachment.class); 1490 ProviderTestUtils.assertAttachmentEqual("getAttachByUri-4", a4, a4Get); 1491 } finally { 1492 c.close(); 1493 } 1494 } 1495 1496 /** 1497 * Tests of default account behavior 1498 * 1499 * 1. Simple set/get 1500 * 2. Moving default between 3 accounts 1501 * 3. Delete default, make sure another becomes default 1502 */ 1503 public void testSetGetDefaultAccount() { 1504 // There should be no default account if there are no accounts 1505 long defaultAccountId = Account.getDefaultAccountId(mMockContext); 1506 assertEquals(-1, defaultAccountId); 1507 1508 Account account1 = ProviderTestUtils.setupAccount("account-default-1", true, mMockContext); 1509 long account1Id = account1.mId; 1510 Account account2 = ProviderTestUtils.setupAccount("account-default-2", true, mMockContext); 1511 long account2Id = account2.mId; 1512 Account account3 = ProviderTestUtils.setupAccount("account-default-3", true, mMockContext); 1513 long account3Id = account3.mId; 1514 1515 // With three accounts, but none marked default, confirm that some default account 1516 // is returned. Which one is undefined here. 1517 defaultAccountId = Account.getDefaultAccountId(mMockContext); 1518 assertTrue(defaultAccountId == account1Id 1519 || defaultAccountId == account2Id 1520 || defaultAccountId == account3Id); 1521 1522 updateIsDefault(account1, true); 1523 defaultAccountId = Account.getDefaultAccountId(mMockContext); 1524 assertEquals(account1Id, defaultAccountId); 1525 1526 updateIsDefault(account2, true); 1527 defaultAccountId = Account.getDefaultAccountId(mMockContext); 1528 assertEquals(account2Id, defaultAccountId); 1529 1530 updateIsDefault(account3, true); 1531 defaultAccountId = Account.getDefaultAccountId(mMockContext); 1532 assertEquals(account3Id, defaultAccountId); 1533 1534 // Now delete a non-default account and confirm no change 1535 Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id); 1536 mMockContext.getContentResolver().delete(uri, null, null); 1537 1538 defaultAccountId = Account.getDefaultAccountId(mMockContext); 1539 assertEquals(account3Id, defaultAccountId); 1540 1541 // Now confirm deleting the default account and it switches to another one 1542 uri = ContentUris.withAppendedId(Account.CONTENT_URI, account3Id); 1543 mMockContext.getContentResolver().delete(uri, null, null); 1544 1545 defaultAccountId = Account.getDefaultAccountId(mMockContext); 1546 assertEquals(account2Id, defaultAccountId); 1547 1548 // Now delete the final account and confirm there are no default accounts again 1549 uri = ContentUris.withAppendedId(Account.CONTENT_URI, account2Id); 1550 mMockContext.getContentResolver().delete(uri, null, null); 1551 1552 defaultAccountId = Account.getDefaultAccountId(mMockContext); 1553 assertEquals(-1, defaultAccountId); 1554 } 1555 1556 private void updateIsDefault(Account account, boolean newState) { 1557 account.setDefaultAccount(newState); 1558 ContentValues cv = new ContentValues(); 1559 cv.put(AccountColumns.IS_DEFAULT, account.mIsDefault); 1560 account.update(mMockContext, cv); 1561 } 1562 1563 public static Message setupUnreadMessage(String name, long accountId, long mailboxId, 1564 boolean addBody, boolean saveIt, Context context) { 1565 Message msg = 1566 ProviderTestUtils.setupMessage(name, accountId, mailboxId, addBody, false, context); 1567 msg.mFlagRead = false; 1568 if (saveIt) { 1569 msg.save(context); 1570 } 1571 return msg; 1572 } 1573 1574 public void testUnreadCountTriggers() { 1575 // Start with one account and three mailboxes 1576 Account account = ProviderTestUtils.setupAccount("triggers", true, mMockContext); 1577 Mailbox boxA = ProviderTestUtils.setupMailbox("boxA", account.mId, true, mMockContext); 1578 Mailbox boxB = ProviderTestUtils.setupMailbox("boxB", account.mId, true, mMockContext); 1579 Mailbox boxC = ProviderTestUtils.setupMailbox("boxC", account.mId, true, mMockContext); 1580 1581 // Make sure there are no unreads 1582 assertEquals(0, getUnreadCount(boxA.mId)); 1583 assertEquals(0, getUnreadCount(boxB.mId)); 1584 assertEquals(0, getUnreadCount(boxC.mId)); 1585 1586 // Create 4 unread messages (only 3 named) in boxA 1587 Message message1 = setupUnreadMessage("message1", account.mId, boxA.mId, 1588 false, true, mMockContext); 1589 Message message2= setupUnreadMessage("message2", account.mId, boxA.mId, 1590 false, true, mMockContext); 1591 Message message3 = setupUnreadMessage("message3", account.mId, boxA.mId, 1592 false, true, mMockContext); 1593 setupUnreadMessage("message4", account.mId, boxC.mId, false, true, mMockContext); 1594 1595 // Make sure the unreads are where we expect them 1596 assertEquals(3, getUnreadCount(boxA.mId)); 1597 assertEquals(0, getUnreadCount(boxB.mId)); 1598 assertEquals(1, getUnreadCount(boxC.mId)); 1599 1600 // After deleting message 1, the count in box A should be decremented (to 2) 1601 ContentResolver cr = mMockContext.getContentResolver(); 1602 Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1.mId); 1603 cr.delete(uri, null, null); 1604 assertEquals(2, getUnreadCount(boxA.mId)); 1605 assertEquals(0, getUnreadCount(boxB.mId)); 1606 assertEquals(1, getUnreadCount(boxC.mId)); 1607 1608 // Move message 2 to box B, leaving 1 in box A and 1 in box B 1609 message2.mMailboxKey = boxB.mId; 1610 ContentValues cv = new ContentValues(); 1611 cv.put(MessageColumns.MAILBOX_KEY, boxB.mId); 1612 cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message2.mId), cv, null, null); 1613 assertEquals(1, getUnreadCount(boxA.mId)); 1614 assertEquals(1, getUnreadCount(boxB.mId)); 1615 assertEquals(1, getUnreadCount(boxC.mId)); 1616 1617 // Mark message 3 (from box A) read, leaving 0 in box A 1618 cv.clear(); 1619 cv.put(MessageColumns.FLAG_READ, 1); 1620 cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null); 1621 assertEquals(0, getUnreadCount(boxA.mId)); 1622 assertEquals(1, getUnreadCount(boxB.mId)); 1623 assertEquals(1, getUnreadCount(boxC.mId)); 1624 1625 // Move message 3 to box C; should be no change (it's read) 1626 message3.mMailboxKey = boxC.mId; 1627 cv.clear(); 1628 cv.put(MessageColumns.MAILBOX_KEY, boxC.mId); 1629 cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null); 1630 assertEquals(0, getUnreadCount(boxA.mId)); 1631 assertEquals(1, getUnreadCount(boxB.mId)); 1632 assertEquals(1, getUnreadCount(boxC.mId)); 1633 1634 // Mark message 3 unread; it's now in box C, so that box's count should go up to 3 1635 cv.clear(); 1636 cv.put(MessageColumns.FLAG_READ, 0); 1637 cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null); 1638 assertEquals(0, getUnreadCount(boxA.mId)); 1639 assertEquals(1, getUnreadCount(boxB.mId)); 1640 assertEquals(2, getUnreadCount(boxC.mId)); 1641 } 1642 1643 /** 1644 * Test for EmailProvider.createIndex(). 1645 * Check that it returns exacly the same string as the one used previously for index creation. 1646 */ 1647 public void testCreateIndex() { 1648 String oldStr = "create index message_" + MessageColumns.TIMESTAMP 1649 + " on " + Message.TABLE_NAME + " (" + MessageColumns.TIMESTAMP + ");"; 1650 String newStr = EmailProvider.createIndex(Message.TABLE_NAME, MessageColumns.TIMESTAMP); 1651 assertEquals(newStr, oldStr); 1652 } 1653 1654 public void testDatabaseCorruptionRecovery() { 1655 final ContentResolver resolver = mMockContext.getContentResolver(); 1656 final Context context = mMockContext; 1657 1658 // Create account and two mailboxes 1659 Account acct = ProviderTestUtils.setupAccount("acct1", true, context); 1660 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context); 1661 1662 // Create 4 messages in box1 with bodies 1663 ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, true, true, context); 1664 ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, true, true, context); 1665 ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, true, true, context); 1666 ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, true, true, context); 1667 1668 // Confirm there are four messages 1669 int count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1670 assertEquals(4, count); 1671 // Confirm there are four bodies 1672 count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null); 1673 assertEquals(4, count); 1674 1675 // Find the EmailProvider.db file 1676 File dbFile = mMockContext.getDatabasePath(EmailProvider.DATABASE_NAME); 1677 // The EmailProvider.db database should exist (the provider creates it automatically) 1678 assertTrue(dbFile != null); 1679 assertTrue(dbFile.exists()); 1680 // Delete it, and confirm it is gone 1681 assertTrue(dbFile.delete()); 1682 assertFalse(dbFile.exists()); 1683 1684 // Find the EmailProviderBody.db file 1685 dbFile = mMockContext.getDatabasePath(EmailProvider.BODY_DATABASE_NAME); 1686 // The EmailProviderBody.db database should still exist 1687 assertTrue(dbFile != null); 1688 assertTrue(dbFile.exists()); 1689 1690 // URI to uncache the databases 1691 // This simulates the Provider starting up again (otherwise, it will still be pointing to 1692 // the already opened files) 1693 // Note that we only have access to the EmailProvider via the ContentResolver; therefore, 1694 // we cannot directly call into the provider and use a URI for this 1695 resolver.update(EmailProvider.INTEGRITY_CHECK_URI, null, null, null); 1696 1697 // TODO We should check for the deletion of attachment files once this is implemented in 1698 // the provider 1699 1700 // Explanation for what happens below... 1701 // The next time the database is created by the provider, it will notice that there's 1702 // already a EmailProviderBody.db file. In this case, it will delete that database to 1703 // ensure that both are in sync (and empty) 1704 1705 // Confirm there are no bodies 1706 count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null); 1707 assertEquals(0, count); 1708 1709 // Confirm there are no messages 1710 count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1711 assertEquals(0, count); 1712 } 1713 1714 public void testBodyDatabaseCorruptionRecovery() { 1715 final ContentResolver resolver = mMockContext.getContentResolver(); 1716 final Context context = mMockContext; 1717 1718 // Create account and two mailboxes 1719 Account acct = ProviderTestUtils.setupAccount("acct1", true, context); 1720 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context); 1721 1722 // Create 4 messages in box1 with bodies 1723 ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, true, true, context); 1724 ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, true, true, context); 1725 ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, true, true, context); 1726 ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, true, true, context); 1727 1728 // Confirm there are four messages 1729 int count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1730 assertEquals(4, count); 1731 // Confirm there are four bodies 1732 count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null); 1733 assertEquals(4, count); 1734 1735 // Find the EmailProviderBody.db file 1736 File dbFile = mMockContext.getDatabasePath(EmailProvider.BODY_DATABASE_NAME); 1737 // The EmailProviderBody.db database should exist (the provider creates it automatically) 1738 assertTrue(dbFile != null); 1739 assertTrue(dbFile.exists()); 1740 // Delete it, and confirm it is gone 1741 assertTrue(dbFile.delete()); 1742 assertFalse(dbFile.exists()); 1743 1744 // Find the EmailProvider.db file 1745 dbFile = mMockContext.getDatabasePath(EmailProvider.DATABASE_NAME); 1746 // The EmailProviderBody.db database should still exist 1747 assertTrue(dbFile != null); 1748 assertTrue(dbFile.exists()); 1749 1750 // URI to uncache the databases 1751 // This simulates the Provider starting up again (otherwise, it will still be pointing to 1752 // the already opened files) 1753 // Note that we only have access to the EmailProvider via the ContentResolver; therefore, 1754 // we cannot directly call into the provider and use a URI for this 1755 resolver.update(EmailProvider.INTEGRITY_CHECK_URI, null, null, null); 1756 1757 // TODO We should check for the deletion of attachment files once this is implemented in 1758 // the provider 1759 1760 // Explanation for what happens below... 1761 // The next time the body database is created by the provider, it will notice that there's 1762 // already a populated EmailProvider.db file. In this case, it will delete that database to 1763 // ensure that both are in sync (and empty) 1764 1765 // Confirm there are no messages 1766 count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1767 assertEquals(0, count); 1768 1769 // Confirm there are no bodies 1770 count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null); 1771 assertEquals(0, count); 1772 } 1773 1774 public void testFindMailboxOfType() { 1775 final Context context = mMockContext; 1776 1777 // Create two accounts and a variety of mailbox types 1778 Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context); 1779 Mailbox acct1Inbox = 1780 ProviderTestUtils.setupMailbox("Inbox1", acct1.mId, true, context, Mailbox.TYPE_INBOX); 1781 Mailbox acct1Calendar 1782 = ProviderTestUtils.setupMailbox("Cal1", acct1.mId, true, context, Mailbox.TYPE_CALENDAR); 1783 Mailbox acct1Contacts = 1784 ProviderTestUtils.setupMailbox("Con1", acct1.mId, true, context, Mailbox.TYPE_CONTACTS); 1785 Account acct2 = ProviderTestUtils.setupAccount("acct1", true, context); 1786 Mailbox acct2Inbox = 1787 ProviderTestUtils.setupMailbox("Inbox2", acct2.mId, true, context, Mailbox.TYPE_INBOX); 1788 Mailbox acct2Calendar = 1789 ProviderTestUtils.setupMailbox("Cal2", acct2.mId, true, context, Mailbox.TYPE_CALENDAR); 1790 Mailbox acct2Contacts = 1791 ProviderTestUtils.setupMailbox("Con2", acct2.mId, true, context, Mailbox.TYPE_CONTACTS); 1792 1793 // Check that we can find them by type 1794 assertEquals(acct1Inbox.mId, 1795 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_INBOX)); 1796 assertEquals(acct2Inbox.mId, 1797 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_INBOX)); 1798 assertEquals(acct1Calendar.mId, 1799 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_CALENDAR)); 1800 assertEquals(acct2Calendar.mId, 1801 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_CALENDAR)); 1802 assertEquals(acct1Contacts.mId, 1803 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_CONTACTS)); 1804 assertEquals(acct2Contacts.mId, 1805 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_CONTACTS)); 1806 1807 // Check that nonexistent mailboxes are not returned 1808 assertEquals(Mailbox.NO_MAILBOX, 1809 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_DRAFTS)); 1810 assertEquals(Mailbox.NO_MAILBOX, 1811 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_OUTBOX)); 1812 1813 // delete account 1 and confirm no mailboxes are returned 1814 context.getContentResolver().delete( 1815 ContentUris.withAppendedId(Account.CONTENT_URI, acct1.mId), null, null); 1816 assertEquals(Mailbox.NO_MAILBOX, 1817 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_INBOX)); 1818 assertEquals(Mailbox.NO_MAILBOX, 1819 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_CALENDAR)); 1820 assertEquals(Mailbox.NO_MAILBOX, 1821 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_CONTACTS)); 1822 } 1823 1824 public void testRestoreMailboxOfType() { 1825 final Context context = mMockContext; 1826 1827 // Create two accounts and a variety of mailbox types 1828 Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context); 1829 Mailbox acct1Inbox = 1830 ProviderTestUtils.setupMailbox("Inbox1", acct1.mId, true, context, Mailbox.TYPE_INBOX); 1831 Mailbox acct1Calendar 1832 = ProviderTestUtils.setupMailbox("Cal1", acct1.mId, true, context, Mailbox.TYPE_CALENDAR); 1833 Mailbox acct1Contacts = 1834 ProviderTestUtils.setupMailbox("Con1", acct1.mId, true, context, Mailbox.TYPE_CONTACTS); 1835 Account acct2 = ProviderTestUtils.setupAccount("acct1", true, context); 1836 Mailbox acct2Inbox = 1837 ProviderTestUtils.setupMailbox("Inbox2", acct2.mId, true, context, Mailbox.TYPE_INBOX); 1838 Mailbox acct2Calendar = 1839 ProviderTestUtils.setupMailbox("Cal2", acct2.mId, true, context, Mailbox.TYPE_CALENDAR); 1840 Mailbox acct2Contacts = 1841 ProviderTestUtils.setupMailbox("Con2", acct2.mId, true, context, Mailbox.TYPE_CONTACTS); 1842 1843 // Check that we can find them by type 1844 ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Inbox, 1845 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_INBOX)); 1846 ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Inbox, 1847 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_INBOX)); 1848 ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Calendar, 1849 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_CALENDAR)); 1850 ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Calendar, 1851 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_CALENDAR)); 1852 ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Contacts, 1853 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_CONTACTS)); 1854 ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Contacts, 1855 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_CONTACTS)); 1856 } 1857 1858 public void testAccountIsSecurityHold() { 1859 final Context context = mMockContext; 1860 Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context); 1861 1862 Account acct2 = ProviderTestUtils.setupAccount("acct2", false, context); 1863 acct2.mFlags |= Account.FLAGS_SECURITY_HOLD; 1864 acct2.save(context); 1865 1866 assertFalse(Account.isSecurityHold(context, acct1.mId)); 1867 assertTrue(Account.isSecurityHold(context, acct2.mId)); 1868 assertFalse(Account.isSecurityHold(context, 9999999)); // No such account 1869 } 1870 1871 public void testClearAccountHoldFlags() { 1872 Account a1 = ProviderTestUtils.setupAccount("holdflag-1", false, mMockContext); 1873 a1.mFlags = Account.FLAGS_NOTIFY_NEW_MAIL; 1874 a1.save(mMockContext); 1875 Account a2 = ProviderTestUtils.setupAccount("holdflag-2", false, mMockContext); 1876 a2.mFlags = Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD; 1877 a2.save(mMockContext); 1878 1879 // bulk clear 1880 Account.clearSecurityHoldOnAllAccounts(mMockContext); 1881 1882 // confirm new values as expected - no hold flags; other flags unmolested 1883 Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId); 1884 assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL, a1a.mFlags); 1885 Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId); 1886 assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2a.mFlags); 1887 } 1888 1889 /** 1890 * @return the number of messages in a mailbox. 1891 */ 1892 private int getMessageCount(long mailboxId) { 1893 return Utility.getFirstRowInt(mMockContext, 1894 ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId), 1895 new String[] {MailboxColumns.MESSAGE_COUNT}, null, null, null, 0); 1896 } 1897 1898 /** Set -1 to the message count of all mailboxes for the recalculateMessageCount test. */ 1899 private void setMinusOneToMessageCounts() { 1900 ContentValues values = new ContentValues(); 1901 values.put(MailboxColumns.MESSAGE_COUNT, -1); 1902 1903 // EmailProvider.update() doesn't allow updating messageCount, so directly use the DB. 1904 SQLiteDatabase db = getProvider().getDatabase(mMockContext); 1905 db.update(Mailbox.TABLE_NAME, values, null, null); 1906 } 1907 1908 /** 1909 * Test for the message count triggers (insert/delete/move mailbox), and also 1910 * {@link EmailProvider#recalculateMessageCount}. 1911 * 1912 * It also covers: 1913 * - {@link Mailbox#getMessageCountByMailboxType(Context, int)} 1914 * - {@link Mailbox#getUnreadCountByAccountAndMailboxType(Context, long, int)} 1915 * - {@link Mailbox#getUnreadCountByMailboxType(Context, int)} 1916 * - {@link Message#getFavoriteMessageCount(Context)} 1917 * - {@link Message#getFavoriteMessageCount(Context, long)} 1918 */ 1919 public void testMessageCount() { 1920 final Context c = mMockContext; 1921 1922 // Create 2 accounts 1923 Account a1 = ProviderTestUtils.setupAccount("holdflag-1", true, c); 1924 Account a2 = ProviderTestUtils.setupAccount("holdflag-2", true, c); 1925 1926 // Create 2 mailboxes for each account 1927 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a1.mId, true, c, Mailbox.TYPE_INBOX); 1928 Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a1.mId, true, c, Mailbox.TYPE_OUTBOX); 1929 Mailbox b3 = ProviderTestUtils.setupMailbox("box3", a2.mId, true, c, Mailbox.TYPE_INBOX); 1930 Mailbox b4 = ProviderTestUtils.setupMailbox("box4", a2.mId, true, c, Mailbox.TYPE_OUTBOX); 1931 Mailbox bt = ProviderTestUtils.setupMailbox("boxT", a2.mId, true, c, Mailbox.TYPE_TRASH); 1932 1933 // 0. Check the initial values, just in case. 1934 1935 assertEquals(0, getMessageCount(b1.mId)); 1936 assertEquals(0, getMessageCount(b2.mId)); 1937 assertEquals(0, getMessageCount(b3.mId)); 1938 assertEquals(0, getMessageCount(b4.mId)); 1939 assertEquals(0, getMessageCount(bt.mId)); 1940 1941 assertEquals(0, Message.getFavoriteMessageCount(c)); 1942 assertEquals(0, Message.getFavoriteMessageCount(c, a1.mId)); 1943 assertEquals(0, Message.getFavoriteMessageCount(c, a2.mId)); 1944 assertEquals(0, Mailbox.getUnreadCountByMailboxType(c, Mailbox.TYPE_INBOX)); 1945 assertEquals(0, Mailbox.getUnreadCountByMailboxType(c, Mailbox.TYPE_OUTBOX)); 1946 assertEquals(0, Mailbox.getMessageCountByMailboxType(c, Mailbox.TYPE_INBOX)); 1947 assertEquals(0, Mailbox.getMessageCountByMailboxType(c, Mailbox.TYPE_OUTBOX)); 1948 assertEquals(0, Mailbox.getMessageCountByMailboxType(c, Mailbox.TYPE_TRASH)); 1949 1950 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 1951 a1.mId, Mailbox.TYPE_INBOX)); 1952 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 1953 a1.mId, Mailbox.TYPE_OUTBOX)); 1954 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 1955 a1.mId, Mailbox.TYPE_TRASH)); 1956 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 1957 a2.mId, Mailbox.TYPE_INBOX)); 1958 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 1959 a2.mId, Mailbox.TYPE_OUTBOX)); 1960 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 1961 a2.mId, Mailbox.TYPE_TRASH)); 1962 1963 // 1. Test for insert triggers. 1964 1965 // Create some messages 1966 // b1 (account 1, inbox): 1 message, including 1 starred 1967 Message m11 = createMessage(c, b1, true, false); 1968 1969 // b2 (account 1, outbox): 2 message, including 1 starred 1970 Message m21 = createMessage(c, b2, false, false); 1971 Message m22 = createMessage(c, b2, true, true); 1972 1973 // b3 (account 2, inbox): 3 message, including 1 starred 1974 Message m31 = createMessage(c, b3, false, false); 1975 Message m32 = createMessage(c, b3, false, false); 1976 Message m33 = createMessage(c, b3, true, true); 1977 1978 // b4 (account 2, outbox) has no messages. 1979 1980 // bt (account 2, trash) has 3 messages, including 2 starred 1981 Message mt1 = createMessage(c, bt, true, false); 1982 Message mt2 = createMessage(c, bt, true, false); 1983 Message mt3 = createMessage(c, bt, false, false); 1984 1985 // Check message counts 1986 assertEquals(1, getMessageCount(b1.mId)); 1987 assertEquals(2, getMessageCount(b2.mId)); 1988 assertEquals(3, getMessageCount(b3.mId)); 1989 assertEquals(0, getMessageCount(b4.mId)); 1990 assertEquals(3, getMessageCount(bt.mId)); 1991 1992 // Check the simple counting methods. 1993 assertEquals(3, Message.getFavoriteMessageCount(c)); // excludes starred in trash 1994 assertEquals(2, Message.getFavoriteMessageCount(c, a1.mId)); 1995 assertEquals(1, Message.getFavoriteMessageCount(c, a2.mId)); // excludes starred in trash 1996 assertEquals(3, Mailbox.getUnreadCountByMailboxType(c, Mailbox.TYPE_INBOX)); 1997 assertEquals(1, Mailbox.getUnreadCountByMailboxType(c, Mailbox.TYPE_OUTBOX)); 1998 assertEquals(4, Mailbox.getMessageCountByMailboxType(c, Mailbox.TYPE_INBOX)); 1999 assertEquals(2, Mailbox.getMessageCountByMailboxType(c, Mailbox.TYPE_OUTBOX)); 2000 assertEquals(3, Mailbox.getMessageCountByMailboxType(c, Mailbox.TYPE_TRASH)); 2001 2002 assertEquals(1, Mailbox.getUnreadCountByAccountAndMailboxType(c, 2003 a1.mId, Mailbox.TYPE_INBOX)); 2004 assertEquals(1, Mailbox.getUnreadCountByAccountAndMailboxType(c, 2005 a1.mId, Mailbox.TYPE_OUTBOX)); 2006 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 2007 a1.mId, Mailbox.TYPE_TRASH)); 2008 assertEquals(2, Mailbox.getUnreadCountByAccountAndMailboxType(c, 2009 a2.mId, Mailbox.TYPE_INBOX)); 2010 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 2011 a2.mId, Mailbox.TYPE_OUTBOX)); 2012 assertEquals(3, Mailbox.getUnreadCountByAccountAndMailboxType(c, 2013 a2.mId, Mailbox.TYPE_TRASH)); 2014 2015 // 2. test for recalculateMessageCount. 2016 2017 // First, invalidate the message counts. 2018 setMinusOneToMessageCounts(); 2019 assertEquals(-1, getMessageCount(b1.mId)); 2020 assertEquals(-1, getMessageCount(b2.mId)); 2021 assertEquals(-1, getMessageCount(b3.mId)); 2022 assertEquals(-1, getMessageCount(b4.mId)); 2023 2024 // Batch update. 2025 SQLiteDatabase db = getProvider().getDatabase(mMockContext); 2026 EmailProvider.recalculateMessageCount(db); 2027 2028 // Check message counts 2029 assertEquals(1, getMessageCount(b1.mId)); 2030 assertEquals(2, getMessageCount(b2.mId)); 2031 assertEquals(3, getMessageCount(b3.mId)); 2032 assertEquals(0, getMessageCount(b4.mId)); 2033 2034 // 3. Check the "move mailbox" trigger. 2035 2036 // Move m32 (in mailbox 3) to mailbox 4. 2037 ContentValues values = new ContentValues(); 2038 values.put(MessageColumns.MAILBOX_KEY, b4.mId); 2039 2040 getProvider().update(Message.CONTENT_URI, values, EmailContent.ID_SELECTION, 2041 new String[] {"" + m32.mId}); 2042 2043 // Check message counts 2044 assertEquals(1, getMessageCount(b1.mId)); 2045 assertEquals(2, getMessageCount(b2.mId)); 2046 assertEquals(2, getMessageCount(b3.mId)); 2047 assertEquals(1, getMessageCount(b4.mId)); 2048 2049 // 4. Check the delete trigger. 2050 2051 // Delete m11 (in mailbox 1) 2052 getProvider().delete(Message.CONTENT_URI, EmailContent.ID_SELECTION, 2053 new String[] {"" + m11.mId}); 2054 // Delete m21 (in mailbox 2) 2055 getProvider().delete(Message.CONTENT_URI, EmailContent.ID_SELECTION, 2056 new String[] {"" + m21.mId}); 2057 2058 // Check message counts 2059 assertEquals(0, getMessageCount(b1.mId)); 2060 assertEquals(1, getMessageCount(b2.mId)); 2061 assertEquals(2, getMessageCount(b3.mId)); 2062 assertEquals(1, getMessageCount(b4.mId)); 2063 2064 // No such mailbox type. 2065 assertEquals(0, Mailbox.getMessageCountByMailboxType(c, 99999)); 2066 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, a1.mId, 99999)); 2067 assertEquals(0, Mailbox.getUnreadCountByMailboxType(c, 99999)); 2068 2069 // No such account 2070 assertEquals(0, Mailbox.getUnreadCountByAccountAndMailboxType(c, 2071 99999, Mailbox.TYPE_INBOX)); 2072 } 2073 2074 private static Message createMessage(Context c, Mailbox b, boolean starred, boolean read) { 2075 return ProviderTestUtils.setupMessage("1", b.mAccountKey, b.mId, true, true, c, starred, 2076 read); 2077 } 2078 2079 public void testAccountIsEasAccount() { 2080 Account account = new Account(); 2081 // No hostauth 2082 assertFalse(account.isEasAccount(mMockContext)); 2083 2084 checkAccountIsEasAccount(null, false); 2085 checkAccountIsEasAccount("", false); 2086 checkAccountIsEasAccount("x", false); 2087 checkAccountIsEasAccount("eas", true); 2088 } 2089 2090 private void checkAccountIsEasAccount(String protocol, boolean expected) { 2091 Account account = ProviderTestUtils.setupAccount("account", false, mMockContext); 2092 account.mHostAuthRecv = ProviderTestUtils.setupHostAuth(protocol, "account-hostauth-recv", 2093 account.mId, false, mMockContext); 2094 account.save(mMockContext); 2095 assertEquals(expected, account.isEasAccount(mMockContext)); 2096 } 2097 2098 public void testGetKeyColumnLong() { 2099 final Context c = mMockContext; 2100 Account a = ProviderTestUtils.setupAccount("acct", true, c); 2101 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a.mId, true, c, Mailbox.TYPE_MAIL); 2102 Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a.mId, true, c, Mailbox.TYPE_MAIL); 2103 Message m1 = createMessage(c, b1, false, false); 2104 Message m2 = createMessage(c, b2, false, false); 2105 assertEquals(a.mId, Message.getKeyColumnLong(c, m1.mId, MessageColumns.ACCOUNT_KEY)); 2106 assertEquals(a.mId, Message.getKeyColumnLong(c, m2.mId, MessageColumns.ACCOUNT_KEY)); 2107 assertEquals(b1.mId, Message.getKeyColumnLong(c, m1.mId, MessageColumns.MAILBOX_KEY)); 2108 assertEquals(b2.mId, Message.getKeyColumnLong(c, m2.mId, MessageColumns.MAILBOX_KEY)); 2109 } 2110 2111 public void testGetAccountIdForMessageId() { 2112 final Context c = mMockContext; 2113 Account a1 = ProviderTestUtils.setupAccount("acct1", true, c); 2114 Account a2 = ProviderTestUtils.setupAccount("acct2", true, c); 2115 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a1.mId, true, c, Mailbox.TYPE_MAIL); 2116 Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a2.mId, true, c, Mailbox.TYPE_MAIL); 2117 Message m1 = createMessage(c, b1, false, false); 2118 Message m2 = createMessage(c, b2, false, false); 2119 2120 assertEquals(a1.mId, Account.getAccountIdForMessageId(c, m1.mId)); 2121 assertEquals(a2.mId, Account.getAccountIdForMessageId(c, m2.mId)); 2122 2123 // message desn't exist 2124 assertEquals(-1, Account.getAccountIdForMessageId(c, 12345)); 2125 } 2126 2127 public void testGetAccountMailboxFromMessageId() { 2128 final Context c = mMockContext; 2129 Account a = ProviderTestUtils.setupAccount("acct", true, c); 2130 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a.mId, true, c, Mailbox.TYPE_MAIL); 2131 Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a.mId, true, c, Mailbox.TYPE_MAIL); 2132 Message m1 = createMessage(c, b1, false, false); 2133 Message m2 = createMessage(c, b2, false, false); 2134 ProviderTestUtils.assertAccountEqual("x", a, Account.getAccountForMessageId(c, m1.mId)); 2135 ProviderTestUtils.assertAccountEqual("x", a, Account.getAccountForMessageId(c, m2.mId)); 2136 // Restore the mailboxes, since the unread & total counts will have changed 2137 b1 = Mailbox.restoreMailboxWithId(c, b1.mId); 2138 b2 = Mailbox.restoreMailboxWithId(c, b2.mId); 2139 ProviderTestUtils.assertMailboxEqual("x", b1, Mailbox.getMailboxForMessageId(c, m1.mId)); 2140 ProviderTestUtils.assertMailboxEqual("x", b2, Mailbox.getMailboxForMessageId(c, m2.mId)); 2141 } 2142 2143 public void testGetAccountGetInboxIdTest() { 2144 final Context c = mMockContext; 2145 2146 // Prepare some data with red-herrings. 2147 Account a1 = ProviderTestUtils.setupAccount("acct1", true, c); 2148 Account a2 = ProviderTestUtils.setupAccount("acct2", true, c); 2149 Mailbox b1i = ProviderTestUtils.setupMailbox("b1i", a1.mId, true, c, Mailbox.TYPE_INBOX); 2150 Mailbox b2a = ProviderTestUtils.setupMailbox("b2a", a2.mId, true, c, Mailbox.TYPE_MAIL); 2151 Mailbox b2i = ProviderTestUtils.setupMailbox("b2b", a2.mId, true, c, Mailbox.TYPE_INBOX); 2152 2153 assertEquals(b2i.mId, Account.getInboxId(c, a2.mId)); 2154 2155 // No account found. 2156 assertEquals(-1, Account.getInboxId(c, 999999)); 2157 } 2158 2159 public void testGetMailboxType() { 2160 final Context c = mMockContext; 2161 2162 Account a = ProviderTestUtils.setupAccount("acct1", true, c); 2163 Mailbox bi = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_INBOX); 2164 Mailbox bm = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_MAIL); 2165 2166 assertEquals(Mailbox.TYPE_INBOX, Mailbox.getMailboxType(c, bi.mId)); 2167 assertEquals(Mailbox.TYPE_MAIL, Mailbox.getMailboxType(c, bm.mId)); 2168 assertEquals(-1, Mailbox.getMailboxType(c, 999999)); // mailbox not found 2169 } 2170 2171 public void testGetDisplayName() { 2172 final Context c = mMockContext; 2173 2174 Account a = ProviderTestUtils.setupAccount("acct1", true, c); 2175 Mailbox bi = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_INBOX); 2176 Mailbox bm = ProviderTestUtils.setupMailbox("b2", a.mId, true, c, Mailbox.TYPE_MAIL); 2177 2178 assertEquals("b1", Mailbox.getDisplayName(c, bi.mId)); 2179 assertEquals("b2", Mailbox.getDisplayName(c, bm.mId)); 2180 assertEquals(null, Mailbox.getDisplayName(c, 999999)); // mailbox not found 2181 } 2182 2183 public void testMailboxIsRefreshable() { 2184 final Context c = mMockContext; 2185 2186 Account a = ProviderTestUtils.setupAccount("acct1", true, c); 2187 Mailbox bi = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_INBOX); 2188 Mailbox bm = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_MAIL); 2189 Mailbox bd = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_DRAFTS); 2190 Mailbox bo = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_OUTBOX); 2191 2192 assertTrue(Mailbox.isRefreshable(c, bi.mId)); 2193 assertTrue(Mailbox.isRefreshable(c, bm.mId)); 2194 assertFalse(Mailbox.isRefreshable(c, bd.mId)); 2195 assertFalse(Mailbox.isRefreshable(c, bo.mId)); 2196 2197 // No such mailbox 2198 assertFalse(Mailbox.isRefreshable(c, 9999999)); 2199 2200 // Magic mailboxes can't be refreshed. 2201 assertFalse(Mailbox.isRefreshable(c, Mailbox.QUERY_ALL_DRAFTS)); 2202 assertFalse(Mailbox.isRefreshable(c, Mailbox.QUERY_ALL_INBOXES)); 2203 } 2204 2205 public void testMailboxCanMoveFrom() { 2206 final Context c = mMockContext; 2207 2208 Account a = ProviderTestUtils.setupAccount("acct1", true, c); 2209 Mailbox bi = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_INBOX); 2210 Mailbox bm = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_MAIL); 2211 Mailbox bd = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_DRAFTS); 2212 Mailbox bo = ProviderTestUtils.setupMailbox("b1", a.mId, true, c, Mailbox.TYPE_OUTBOX); 2213 2214 assertTrue(Mailbox.canMoveFrom(c, bi.mId)); 2215 assertTrue(Mailbox.canMoveFrom(c, bm.mId)); 2216 assertFalse(Mailbox.canMoveFrom(c, bd.mId)); 2217 assertFalse(Mailbox.canMoveFrom(c, bo.mId)); 2218 } 2219 2220 /** 2221 * Check if update to {@link Account#RESET_NEW_MESSAGE_COUNT_URI} resets the new message count. 2222 */ 2223 public void testResetNewMessageCount() { 2224 final Context c = mMockContext; 2225 final ContentResolver cr = c.getContentResolver(); 2226 2227 // Prepare test data 2228 Account a1 = ProviderTestUtils.setupAccount("acct1", false, c); 2229 a1.mNewMessageCount = 1; 2230 a1.save(c); 2231 Account a2 = ProviderTestUtils.setupAccount("acct2", false, c); 2232 a2.mNewMessageCount = 2; 2233 a2.save(c); 2234 Account a3 = ProviderTestUtils.setupAccount("acct3", false, c); 2235 a3.mNewMessageCount = 3; 2236 a3.save(c); 2237 Account a4 = ProviderTestUtils.setupAccount("acct4", false, c); 2238 a4.mNewMessageCount = 4; 2239 a4.save(c); 2240 Account a5 = ProviderTestUtils.setupAccount("acct5", false, c); 2241 a5.mNewMessageCount = 5; 2242 a5.save(c); 2243 2244 // With ID in URI, no selection 2245 cr.update(ContentUris.withAppendedId(Account.RESET_NEW_MESSAGE_COUNT_URI, a1.mId), 2246 null, null, null); 2247 assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount); 2248 assertEquals(2, Account.restoreAccountWithId(c, a2.mId).mNewMessageCount); 2249 assertEquals(3, Account.restoreAccountWithId(c, a3.mId).mNewMessageCount); 2250 assertEquals(4, Account.restoreAccountWithId(c, a4.mId).mNewMessageCount); 2251 assertEquals(5, Account.restoreAccountWithId(c, a5.mId).mNewMessageCount); 2252 2253 // No ID in URI, with selection 2254 cr.update(Account.RESET_NEW_MESSAGE_COUNT_URI, null, 2255 EmailContent.ID_SELECTION, new String[] {Long.toString(a2.mId)}); 2256 assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount); 2257 assertEquals(0, Account.restoreAccountWithId(c, a2.mId).mNewMessageCount); 2258 assertEquals(3, Account.restoreAccountWithId(c, a3.mId).mNewMessageCount); 2259 assertEquals(4, Account.restoreAccountWithId(c, a4.mId).mNewMessageCount); 2260 assertEquals(5, Account.restoreAccountWithId(c, a5.mId).mNewMessageCount); 2261 2262 // With ID, with selection 2263 cr.update(ContentUris.withAppendedId(Account.RESET_NEW_MESSAGE_COUNT_URI, a3.mId), null, 2264 EmailContent.ID_SELECTION, new String[] {Long.toString(a3.mId)}); 2265 assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount); 2266 assertEquals(0, Account.restoreAccountWithId(c, a2.mId).mNewMessageCount); 2267 assertEquals(0, Account.restoreAccountWithId(c, a3.mId).mNewMessageCount); 2268 assertEquals(4, Account.restoreAccountWithId(c, a4.mId).mNewMessageCount); 2269 assertEquals(5, Account.restoreAccountWithId(c, a5.mId).mNewMessageCount); 2270 2271 // No ID in URI, no selection 2272 cr.update(Account.RESET_NEW_MESSAGE_COUNT_URI, null, null, null); 2273 assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount); 2274 assertEquals(0, Account.restoreAccountWithId(c, a2.mId).mNewMessageCount); 2275 assertEquals(0, Account.restoreAccountWithId(c, a3.mId).mNewMessageCount); 2276 assertEquals(0, Account.restoreAccountWithId(c, a4.mId).mNewMessageCount); 2277 assertEquals(0, Account.restoreAccountWithId(c, a5.mId).mNewMessageCount); 2278 } 2279 2280 private static Message createMessageWithTimestamp(Context c, Mailbox b, long timestamp) { 2281 Message m = ProviderTestUtils.setupMessage("1", b.mAccountKey, b.mId, true, false, c, false, 2282 false); 2283 m.mTimeStamp = timestamp; 2284 m.save(c); 2285 return m; 2286 } 2287 2288 public void testMessageGetLatestIncomingMessage() { 2289 final Context c = mMockContext; 2290 2291 // Create 2 accounts with a inbox. 2292 Account a1 = ProviderTestUtils.setupAccount("a1", true, c); 2293 Account a2 = ProviderTestUtils.setupAccount("a2", true, c); 2294 2295 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a1.mId, true, c, Mailbox.TYPE_INBOX); 2296 Mailbox b1d = ProviderTestUtils.setupMailbox("box1d", a1.mId, true, c, Mailbox.TYPE_DRAFTS); 2297 Mailbox b1o = ProviderTestUtils.setupMailbox("box1o", a1.mId, true, c, Mailbox.TYPE_OUTBOX); 2298 Mailbox b1s = ProviderTestUtils.setupMailbox("box1s", a1.mId, true, c, Mailbox.TYPE_SENT); 2299 Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a2.mId, true, c, Mailbox.TYPE_MAIL); 2300 2301 // Create some messages 2302 Message m11 = createMessageWithTimestamp(c, b1, 33); 2303 Message m12 = createMessageWithTimestamp(c, b1, 10); 2304 Message m13 = createMessageWithTimestamp(c, b1, 1000); // latest incoming 2305 Message m1d = createMessageWithTimestamp(c, b1d, 2000); 2306 Message m1o = createMessageWithTimestamp(c, b1o, 2000); 2307 Message m1s = createMessageWithTimestamp(c, b1s, 2000); 2308 2309 Message m21 = createMessageWithTimestamp(c, b2, 99); // latest incoming 2310 Message m22 = createMessageWithTimestamp(c, b2, 1); 2311 Message m23 = createMessageWithTimestamp(c, b2, 2); 2312 2313 // Check! 2314 assertEquals(m13.mId, Message.getLatestIncomingMessage(c, a1.mId).mId); 2315 assertEquals(m21.mId, Message.getLatestIncomingMessage(c, a2.mId).mId); 2316 2317 // No such account 2318 assertEquals(null, Message.getLatestIncomingMessage(c, 9999999L)); 2319 } 2320 2321 /** 2322 * Check if update on ACCOUNT_ID_ADD_TO_FIELD updates the cache properly. 2323 */ 2324 public void testUpdateCacheAccountIdAddToField() { 2325 final Context c = mMockContext; 2326 Account a1 = ProviderTestUtils.setupAccount("a1", true, c); 2327 2328 int start = Account.restoreAccountWithId(c, a1.mId).mNewMessageCount; 2329 2330 // +1 to NEW_MESSAGE_COUNT 2331 ContentValues cv = new ContentValues(); 2332 cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT); 2333 cv.put(EmailContent.ADD_COLUMN_NAME, 1); 2334 mProvider.update(ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, a1.mId), cv, 2335 null, null); 2336 2337 // Check 2338 assertEquals(start + 1, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount); 2339 } 2340 2341 /** 2342 * Check if update on ACCOUNT_RESET_NEW_COUNT updates the cache properly. 2343 */ 2344 public void testUpdateCacheAccountResetNewCount() { 2345 final Context c = mMockContext; 2346 Account a1 = ProviderTestUtils.setupAccount("a1", true, c); 2347 2348 // precondition 2349 assertTrue(Account.restoreAccountWithId(c, a1.mId).mNewMessageCount > 0); 2350 2351 // Reset 2352 mProvider.update(Account.RESET_NEW_MESSAGE_COUNT_URI, null, null, null); 2353 2354 // Check 2355 assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount); 2356 } 2357 2358 /** 2359 * Check if update on ACCOUNT_RESET_NEW_COUNT_ID updates the cache properly. 2360 */ 2361 public void testUpdateCacheAccountResetNewCountId() { 2362 final Context c = mMockContext; 2363 Account a1 = ProviderTestUtils.setupAccount("a1", true, c); 2364 2365 // precondition 2366 assertTrue(Account.restoreAccountWithId(c, a1.mId).mNewMessageCount > 0); 2367 2368 // Reset 2369 mProvider.update(ContentUris.withAppendedId(Account.RESET_NEW_MESSAGE_COUNT_URI, a1.mId), 2370 null, null, null); 2371 2372 // Check 2373 assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount); 2374 } 2375 2376 /** 2377 * Check if update on MAILBOX_ID_ADD_TO_FIELD updates the cache properly. 2378 */ 2379 public void testUpdateCacheMailboxIdAddToField() { 2380 final Context c = mMockContext; 2381 Account a1 = ProviderTestUtils.setupAccount("a1", true, c); 2382 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a1.mId, true, c, Mailbox.TYPE_INBOX); 2383 2384 int start = Mailbox.restoreMailboxWithId(c, b1.mId).mSyncInterval; 2385 2386 // +1 to SYNC_INTERVAL 2387 ContentValues cv = new ContentValues(); 2388 cv.put(EmailContent.FIELD_COLUMN_NAME, MailboxColumns.SYNC_INTERVAL); 2389 cv.put(EmailContent.ADD_COLUMN_NAME, 1); 2390 mProvider.update(ContentUris.withAppendedId(Mailbox.ADD_TO_FIELD_URI, a1.mId), cv, 2391 null, null); 2392 2393 // Check 2394 assertEquals(start + 1, Mailbox.restoreMailboxWithId(c, b1.mId).mSyncInterval); 2395 } 2396 2397 /** 2398 * Check that we're handling illegal uri's properly (by throwing an exception unless it's a 2399 * query for an id of -1, in which case we return a zero-length cursor) 2400 */ 2401 public void testIllegalUri() { 2402 final ContentResolver cr = mMockContext.getContentResolver(); 2403 2404 ContentValues cv = new ContentValues(); 2405 Uri uri = Uri.parse("content://" + EmailContent.AUTHORITY + "/fooble"); 2406 try { 2407 cr.insert(uri, cv); 2408 fail("Insert should have thrown exception"); 2409 } catch (IllegalArgumentException e) { 2410 } 2411 try { 2412 cr.update(uri, cv, null, null); 2413 fail("Update should have thrown exception"); 2414 } catch (IllegalArgumentException e) { 2415 } 2416 try { 2417 cr.delete(uri, null, null); 2418 fail("Delete should have thrown exception"); 2419 } catch (IllegalArgumentException e) { 2420 } 2421 try { 2422 cr.query(uri, EmailContent.ID_PROJECTION, null, null, null); 2423 fail("Query should have thrown exception"); 2424 } catch (IllegalArgumentException e) { 2425 } 2426 uri = Uri.parse("content://" + EmailContent.AUTHORITY + "/mailbox/fred"); 2427 try { 2428 cr.query(uri, EmailContent.ID_PROJECTION, null, null, null); 2429 fail("Query should have thrown exception"); 2430 } catch (IllegalArgumentException e) { 2431 } 2432 uri = Uri.parse("content://" + EmailContent.AUTHORITY + "/mailbox/-1"); 2433 Cursor c = cr.query(uri, EmailContent.ID_PROJECTION, null, null, null); 2434 assertNotNull(c); 2435 assertEquals(0, c.getCount()); 2436 c.close(); 2437 } 2438} 2439