Home | History | Annotate | Download | only in provider
      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 
     17 package com.android.email.provider;
     18 
     19 import com.android.email.provider.EmailContent.Account;
     20 import com.android.email.provider.EmailContent.AccountColumns;
     21 import com.android.email.provider.EmailContent.Attachment;
     22 import com.android.email.provider.EmailContent.AttachmentColumns;
     23 import com.android.email.provider.EmailContent.Body;
     24 import com.android.email.provider.EmailContent.BodyColumns;
     25 import com.android.email.provider.EmailContent.HostAuth;
     26 import com.android.email.provider.EmailContent.Mailbox;
     27 import com.android.email.provider.EmailContent.MailboxColumns;
     28 import com.android.email.provider.EmailContent.Message;
     29 import com.android.email.provider.EmailContent.MessageColumns;
     30 
     31 import android.content.ContentResolver;
     32 import android.content.ContentUris;
     33 import android.content.ContentValues;
     34 import android.content.Context;
     35 import android.database.Cursor;
     36 import android.net.Uri;
     37 import android.os.Bundle;
     38 import android.os.Environment;
     39 import android.os.Parcel;
     40 import android.test.MoreAsserts;
     41 import android.test.ProviderTestCase2;
     42 
     43 import java.io.File;
     44 import java.io.IOException;
     45 import java.util.ArrayList;
     46 
     47 /**
     48  * Tests of the Email provider.
     49  *
     50  * You can run this entire test case with:
     51  *   runtest -c com.android.email.provider.ProviderTests email
     52  */
     53 public class ProviderTests extends ProviderTestCase2<EmailProvider> {
     54 
     55     EmailProvider mProvider;
     56     Context mMockContext;
     57 
     58     public ProviderTests() {
     59         super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
     60     }
     61 
     62     @Override
     63     public void setUp() throws Exception {
     64         super.setUp();
     65         mMockContext = getMockContext();
     66     }
     67 
     68     @Override
     69     public void tearDown() throws Exception {
     70         super.tearDown();
     71     }
     72 
     73     /**
     74      * TODO: Database upgrade tests
     75      */
     76 
     77     /**
     78      * Test simple account save/retrieve
     79      */
     80     public void testAccountSave() {
     81         Account account1 = ProviderTestUtils.setupAccount("account-save", true, mMockContext);
     82         long account1Id = account1.mId;
     83 
     84         Account account2 = EmailContent.Account.restoreAccountWithId(mMockContext, account1Id);
     85 
     86         ProviderTestUtils.assertAccountEqual("testAccountSave", account1, account2);
     87     }
     88 
     89     /**
     90      * Test simple account save/retrieve with predefined hostauth records
     91      */
     92     public void testAccountSaveHostAuth() {
     93         Account account1 = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext);
     94         // add hostauth data, which should be saved the first time
     95         account1.mHostAuthRecv = ProviderTestUtils.setupHostAuth("account-hostauth-recv", -1, false,
     96                 mMockContext);
     97         account1.mHostAuthSend = ProviderTestUtils.setupHostAuth("account-hostauth-send", -1, false,
     98                 mMockContext);
     99         account1.save(mMockContext);
    100         long account1Id = account1.mId;
    101 
    102         // Confirm account reads back correctly
    103         Account account1get = EmailContent.Account.restoreAccountWithId(mMockContext, account1Id);
    104         ProviderTestUtils.assertAccountEqual("testAccountSave", account1, account1get);
    105 
    106         // Confirm hostauth fields can be accessed & read back correctly
    107         HostAuth hostAuth1get = EmailContent.HostAuth.restoreHostAuthWithId(mMockContext,
    108                 account1get.mHostAuthKeyRecv);
    109         ProviderTestUtils.assertHostAuthEqual("testAccountSaveHostAuth-recv",
    110                 account1.mHostAuthRecv, hostAuth1get);
    111         HostAuth hostAuth2get = EmailContent.HostAuth.restoreHostAuthWithId(mMockContext,
    112                 account1get.mHostAuthKeySend);
    113         ProviderTestUtils.assertHostAuthEqual("testAccountSaveHostAuth-send",
    114                 account1.mHostAuthSend, hostAuth2get);
    115     }
    116 
    117     /**
    118      * Simple test of account parceling.  The rather tortuous path is to ensure that the
    119      * account is really flattened all the way down to a parcel and back.
    120      */
    121     public void testAccountParcel() {
    122         Account account1 = ProviderTestUtils.setupAccount("parcel", false, mMockContext);
    123         Bundle b = new Bundle();
    124         b.putParcelable("account", account1);
    125         Parcel p = Parcel.obtain();
    126         b.writeToParcel(p, 0);
    127         p.setDataPosition(0);       // rewind it for reading
    128         Bundle b2 = new Bundle(Account.class.getClassLoader());
    129         b2.readFromParcel(p);
    130         Account account2 = (Account) b2.getParcelable("account");
    131         p.recycle();
    132 
    133         ProviderTestUtils.assertAccountEqual("testAccountParcel", account1, account2);
    134     }
    135 
    136     /**
    137      * Test for {@link Account#getShortcutSafeUri()} and
    138      * {@link Account#getAccountIdForShortcutSafeUri}.
    139      */
    140     public void testAccountShortcutSafeUri() {
    141         final Account account1 = ProviderTestUtils.setupAccount("account-1", true, mMockContext);
    142         final Account account2 = ProviderTestUtils.setupAccount("account-2", true, mMockContext);
    143         final long account1Id = account1.mId;
    144         final long account2Id = account2.mId;
    145 
    146         final Uri uri1 = account1.getShortcutSafeUri();
    147         final Uri uri2 = account2.getShortcutSafeUri();
    148 
    149         // Check the path part of the URIs.
    150         MoreAsserts.assertEquals(new String[] {"account", account1.mCompatibilityUuid},
    151                 uri1.getPathSegments().toArray());
    152         MoreAsserts.assertEquals(new String[] {"account", account2.mCompatibilityUuid},
    153                 uri2.getPathSegments().toArray());
    154 
    155         assertEquals(account1Id, Account.getAccountIdFromShortcutSafeUri(mMockContext, uri1));
    156         assertEquals(account2Id, Account.getAccountIdFromShortcutSafeUri(mMockContext, uri2));
    157 
    158         // Test for the Eclair(2.0-2.1) style URI.
    159         assertEquals(account1Id, Account.getAccountIdFromShortcutSafeUri(mMockContext,
    160                 getEclairStyleShortcutUri(account1)));
    161         assertEquals(account2Id, Account.getAccountIdFromShortcutSafeUri(mMockContext,
    162                 getEclairStyleShortcutUri(account2)));
    163     }
    164 
    165     private static Uri getEclairStyleShortcutUri(Account account) {
    166         // We used _id instead of UUID only on Eclair(2.0-2.1).
    167         return Account.CONTENT_URI.buildUpon().appendEncodedPath("" + account.mId).build();
    168     }
    169 
    170     public void testAccountIsValidId() {
    171         final Account account1 = ProviderTestUtils.setupAccount("account-1", true, mMockContext);
    172         final Account account2 = ProviderTestUtils.setupAccount("account-2", true, mMockContext);
    173 
    174         assertTrue(Account.isValidId(mMockContext, account1.mId));
    175         assertTrue(Account.isValidId(mMockContext, account2.mId));
    176 
    177         assertFalse(Account.isValidId(mMockContext, 1234567)); // Some random ID
    178         assertFalse(Account.isValidId(mMockContext, -1));
    179         assertFalse(Account.isValidId(mMockContext, -500));
    180     }
    181 
    182     private final static String[] MAILBOX_UNREAD_COUNT_PROJECTION = new String [] {
    183         MailboxColumns.UNREAD_COUNT
    184     };
    185     private final static int MAILBOX_UNREAD_COUNT_COLMUN = 0;
    186 
    187     /**
    188      * Get the value of the unread count in the mailbox of the account.
    189      * This can be different from the actual number of unread messages in that mailbox.
    190      * @param accountId
    191      * @param mailboxId
    192      * @return
    193      */
    194     private int getUnreadCount(long mailboxId) {
    195         String text = null;
    196         Cursor c = null;
    197         try {
    198             c = mMockContext.getContentResolver().query(
    199                     Mailbox.CONTENT_URI,
    200                     MAILBOX_UNREAD_COUNT_PROJECTION,
    201                     EmailContent.RECORD_ID + "=?",
    202                     new String[] { String.valueOf(mailboxId) },
    203                     null);
    204             c.moveToFirst();
    205             text = c.getString(MAILBOX_UNREAD_COUNT_COLMUN);
    206         } finally {
    207             c.close();
    208         }
    209         return Integer.valueOf(text);
    210     }
    211 
    212     /**
    213      * TODO: HostAuth tests
    214      */
    215 
    216     /**
    217      * Test the various combinations of SSL, TLS, and trust-certificates encoded as Uris
    218      */
    219     @SuppressWarnings("deprecation")
    220     public void testHostAuthSecurityUri() {
    221         HostAuth ha = ProviderTestUtils.setupHostAuth("uri-security", 1, false, mMockContext);
    222 
    223         final int MASK =
    224             HostAuth.FLAG_SSL | HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
    225 
    226         // Set various URIs and check the resulting flags
    227         ha.setStoreUri("protocol://user:password@server:123");
    228         assertEquals(0, ha.mFlags & MASK);
    229         ha.setStoreUri("protocol+ssl+://user:password@server:123");
    230         assertEquals(HostAuth.FLAG_SSL, ha.mFlags & MASK);
    231         ha.setStoreUri("protocol+ssl+trustallcerts://user:password@server:123");
    232         assertEquals(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL_CERTIFICATES, ha.mFlags & MASK);
    233         ha.setStoreUri("protocol+tls+://user:password@server:123");
    234         assertEquals(HostAuth.FLAG_TLS, ha.mFlags & MASK);
    235         ha.setStoreUri("protocol+tls+trustallcerts://user:password@server:123");
    236         assertEquals(HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL_CERTIFICATES, ha.mFlags & MASK);
    237 
    238         // Now check the retrival method (building URI from flags)
    239         ha.mFlags &= ~MASK;
    240         String uriString = ha.getStoreUri();
    241         assertTrue(uriString.startsWith("protocol://"));
    242         ha.mFlags |= HostAuth.FLAG_SSL;
    243         uriString = ha.getStoreUri();
    244         assertTrue(uriString.startsWith("protocol+ssl+://"));
    245         ha.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
    246         uriString = ha.getStoreUri();
    247         assertTrue(uriString.startsWith("protocol+ssl+trustallcerts://"));
    248         ha.mFlags &= ~MASK;
    249         ha.mFlags |= HostAuth.FLAG_TLS;
    250         uriString = ha.getStoreUri();
    251         assertTrue(uriString.startsWith("protocol+tls+://"));
    252         ha.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
    253         uriString = ha.getStoreUri();
    254         assertTrue(uriString.startsWith("protocol+tls+trustallcerts://"));
    255     }
    256 
    257     /**
    258      * Test port assignments made from Uris
    259      */
    260     @SuppressWarnings("deprecation")
    261     public void testHostAuthPortAssignments() {
    262         HostAuth ha = ProviderTestUtils.setupHostAuth("uri-port", 1, false, mMockContext);
    263 
    264         // Set various URIs and check the resulting flags
    265         // Hardwired port
    266         ha.setStoreUri("imap://user:password@server:123");
    267         assertEquals(123, ha.mPort);
    268         // Auto-assigned ports
    269         ha.setStoreUri("imap://user:password@server");
    270         assertEquals(143, ha.mPort);
    271         ha.setStoreUri("imap+ssl://user:password@server");
    272         assertEquals(993, ha.mPort);
    273         ha.setStoreUri("imap+ssl+trustallcerts://user:password@server");
    274         assertEquals(993, ha.mPort);
    275         ha.setStoreUri("imap+tls://user:password@server");
    276         assertEquals(143, ha.mPort);
    277         ha.setStoreUri("imap+tls+trustallcerts://user:password@server");
    278         assertEquals(143, ha.mPort);
    279 
    280         // Hardwired port
    281         ha.setStoreUri("pop3://user:password@server:123");
    282         assertEquals(123, ha.mPort);
    283         // Auto-assigned ports
    284         ha.setStoreUri("pop3://user:password@server");
    285         assertEquals(110, ha.mPort);
    286         ha.setStoreUri("pop3+ssl://user:password@server");
    287         assertEquals(995, ha.mPort);
    288         ha.setStoreUri("pop3+ssl+trustallcerts://user:password@server");
    289         assertEquals(995, ha.mPort);
    290         ha.setStoreUri("pop3+tls://user:password@server");
    291         assertEquals(110, ha.mPort);
    292         ha.setStoreUri("pop3+tls+trustallcerts://user:password@server");
    293         assertEquals(110, ha.mPort);
    294 
    295         // Hardwired port
    296         ha.setStoreUri("eas://user:password@server:123");
    297         assertEquals(123, ha.mPort);
    298         // Auto-assigned ports
    299         ha.setStoreUri("eas://user:password@server");
    300         assertEquals(80, ha.mPort);
    301         ha.setStoreUri("eas+ssl://user:password@server");
    302         assertEquals(443, ha.mPort);
    303         ha.setStoreUri("eas+ssl+trustallcerts://user:password@server");
    304         assertEquals(443, ha.mPort);
    305 
    306         // Hardwired port
    307         ha.setStoreUri("smtp://user:password@server:123");
    308         assertEquals(123, ha.mPort);
    309         // Auto-assigned ports
    310         ha.setStoreUri("smtp://user:password@server");
    311         assertEquals(587, ha.mPort);
    312         ha.setStoreUri("smtp+ssl://user:password@server");
    313         assertEquals(465, ha.mPort);
    314         ha.setStoreUri("smtp+ssl+trustallcerts://user:password@server");
    315         assertEquals(465, ha.mPort);
    316         ha.setStoreUri("smtp+tls://user:password@server");
    317         assertEquals(587, ha.mPort);
    318         ha.setStoreUri("smtp+tls+trustallcerts://user:password@server");
    319         assertEquals(587, ha.mPort);
    320     }
    321 
    322     /**
    323      * Test simple mailbox save/retrieve
    324      */
    325     public void testMailboxSave() {
    326         Account account1 = ProviderTestUtils.setupAccount("mailbox-save", true, mMockContext);
    327         long account1Id = account1.mId;
    328         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true,
    329                 mMockContext);
    330         long box1Id = box1.mId;
    331 
    332         Mailbox box2 = EmailContent.Mailbox.restoreMailboxWithId(mMockContext, box1Id);
    333 
    334         ProviderTestUtils.assertMailboxEqual("testMailboxSave", box1, box2);
    335     }
    336 
    337     private static String[] expectedAttachmentNames =
    338         new String[] {"attachment1.doc", "attachment2.xls", "attachment3"};
    339     // The lengths need to be kept in ascending order
    340     private static long[] expectedAttachmentSizes = new long[] {31415L, 97701L, 151213L};
    341 
    342     /*
    343      * Returns null if the message has no body.
    344      */
    345     private Body loadBodyForMessageId(long messageId) {
    346         Cursor c = null;
    347         try {
    348             c = mMockContext.getContentResolver().query(
    349                     EmailContent.Body.CONTENT_URI,
    350                     EmailContent.Body.CONTENT_PROJECTION,
    351                     EmailContent.Body.MESSAGE_KEY + "=?",
    352                     new String[] {String.valueOf(messageId)},
    353                     null);
    354             int numBodies = c.getCount();
    355             assertTrue("at most one body", numBodies < 2);
    356             return c.moveToFirst() ? EmailContent.getContent(c, Body.class) : null;
    357         } finally {
    358             c.close();
    359         }
    360     }
    361 
    362     /**
    363      * Test simple message save/retrieve
    364      *
    365      * TODO: serverId vs. serverIntId
    366      */
    367     public void testMessageSave() {
    368         Account account1 = ProviderTestUtils.setupAccount("message-save", true, mMockContext);
    369         long account1Id = account1.mId;
    370         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
    371         long box1Id = box1.mId;
    372 
    373         // Test a simple message (saved with no body)
    374         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
    375                 true, mMockContext);
    376         long message1Id = message1.mId;
    377         Message message1get = EmailContent.Message.restoreMessageWithId(mMockContext, message1Id);
    378         ProviderTestUtils.assertMessageEqual("testMessageSave", message1, message1get);
    379 
    380         // Test a message saved with a body
    381         // Note that it will read back w/o the text & html so we must extract those
    382         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
    383                 true, mMockContext);
    384         long message2Id = message2.mId;
    385         String text2 = message2.mText;
    386         String html2 = message2.mHtml;
    387         String textReply2 = message2.mTextReply;
    388         String htmlReply2 = message2.mHtmlReply;
    389         long sourceKey2 = message2.mSourceKey;
    390         String introText2 = message2.mIntroText;
    391         message2.mText = null;
    392         message2.mHtml = null;
    393         message2.mTextReply = null;
    394         message2.mHtmlReply = null;
    395         message2.mSourceKey = 0;
    396         message2.mIntroText = null;
    397         Message message2get = EmailContent.Message.restoreMessageWithId(mMockContext, message2Id);
    398         ProviderTestUtils.assertMessageEqual("testMessageSave", message2, message2get);
    399 
    400         // Now see if there's a body saved with the right stuff
    401         Body body2 = loadBodyForMessageId(message2Id);
    402         assertEquals("body text", text2, body2.mTextContent);
    403         assertEquals("body html", html2, body2.mHtmlContent);
    404         assertEquals("reply text", textReply2, body2.mTextReply);
    405         assertEquals("reply html", htmlReply2, body2.mHtmlReply);
    406         assertEquals("source key", sourceKey2, body2.mSourceKey);
    407         assertEquals("intro text", introText2, body2.mIntroText);
    408 
    409         // Message with attachments and body
    410         Message message3 = ProviderTestUtils.setupMessage("message3", account1Id, box1Id, true,
    411                 false, mMockContext);
    412         ArrayList<Attachment> atts = new ArrayList<Attachment>();
    413         for (int i = 0; i < 3; i++) {
    414             atts.add(ProviderTestUtils.setupAttachment(
    415                     -1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
    416                     false, mMockContext));
    417         }
    418         message3.mAttachments = atts;
    419         message3.save(mMockContext);
    420         long message3Id = message3.mId;
    421 
    422         // Now check the attachments; there should be three and they should match name and size
    423         Cursor c = null;
    424         try {
    425             // Note that there is NO guarantee of the order of returned records in the general case,
    426             // so we specifically ask for ordering by size.  The expectedAttachmentSizes array must
    427             // be kept sorted by size (ascending) for this test to work properly
    428             c = mMockContext.getContentResolver().query(
    429                     Attachment.CONTENT_URI,
    430                     Attachment.CONTENT_PROJECTION,
    431                     Attachment.MESSAGE_KEY + "=?",
    432                     new String[] {
    433                             String.valueOf(message3Id)
    434                     },
    435                     Attachment.SIZE);
    436             int numAtts = c.getCount();
    437             assertEquals(3, numAtts);
    438             int i = 0;
    439             while (c.moveToNext()) {
    440                 Attachment actual = EmailContent.getContent(c, Attachment.class);
    441                 ProviderTestUtils.assertAttachmentEqual("save-message3", atts.get(i), actual);
    442                 i++;
    443             }
    444         } finally {
    445             c.close();
    446         }
    447 
    448         // Message with attachments but no body
    449         Message message4 = ProviderTestUtils.setupMessage("message4", account1Id, box1Id, false,
    450                 false, mMockContext);
    451         atts = new ArrayList<Attachment>();
    452         for (int i = 0; i < 3; i++) {
    453             atts.add(ProviderTestUtils.setupAttachment(
    454                     -1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
    455                     false, mMockContext));
    456         }
    457         message4.mAttachments = atts;
    458         message4.save(mMockContext);
    459         long message4Id = message4.mId;
    460 
    461         // Now check the attachments; there should be three and they should match name and size
    462         c = null;
    463 
    464         try {
    465             // Note that there is NO guarantee of the order of returned records in the general case,
    466             // so we specifically ask for ordering by size.  The expectedAttachmentSizes array must
    467             // be kept sorted by size (ascending) for this test to work properly
    468             c = mMockContext.getContentResolver().query(
    469                     Attachment.CONTENT_URI,
    470                     Attachment.CONTENT_PROJECTION,
    471                     Attachment.MESSAGE_KEY + "=?",
    472                     new String[] {
    473                             String.valueOf(message4Id)
    474                     },
    475                     Attachment.SIZE);
    476             int numAtts = c.getCount();
    477             assertEquals(3, numAtts);
    478             int i = 0;
    479             while (c.moveToNext()) {
    480                 Attachment actual = EmailContent.getContent(c, Attachment.class);
    481                 ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), actual);
    482                 i++;
    483             }
    484         } finally {
    485             c.close();
    486         }
    487 
    488         // test EmailContent.restoreAttachmentsWitdMessageId()
    489         Attachment[] attachments =
    490             Attachment.restoreAttachmentsWithMessageId(mMockContext, message4Id);
    491         int size = attachments.length;
    492         assertEquals(3, size);
    493         for (int i = 0; i < size; ++i) {
    494             ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), attachments[i]);
    495         }
    496     }
    497 
    498     /**
    499      * TODO: update account
    500      */
    501 
    502     /**
    503      * TODO: update mailbox
    504      */
    505 
    506     /**
    507      * TODO: update message
    508      */
    509 
    510     /**
    511      * Test delete account
    512      * TODO: hostauth
    513      */
    514     public void testAccountDelete() {
    515         Account account1 = ProviderTestUtils.setupAccount("account-delete-1", true, mMockContext);
    516         long account1Id = account1.mId;
    517         Account account2 = ProviderTestUtils.setupAccount("account-delete-2", true, mMockContext);
    518         long account2Id = account2.mId;
    519 
    520         // make sure there are two accounts
    521         int numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
    522         assertEquals(2, numBoxes);
    523 
    524         // now delete one of them
    525         Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id);
    526         mMockContext.getContentResolver().delete(uri, null, null);
    527 
    528         // make sure there's only one account now
    529         numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
    530         assertEquals(1, numBoxes);
    531 
    532         // now delete the other one
    533         uri = ContentUris.withAppendedId(Account.CONTENT_URI, account2Id);
    534         mMockContext.getContentResolver().delete(uri, null, null);
    535 
    536         // make sure there are no accounts now
    537         numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
    538         assertEquals(0, numBoxes);
    539     }
    540 
    541     /**
    542      * Test for Body.lookupBodyIdWithMessageId()
    543      * Verifies that:
    544      * - for a message without body, -1 is returned.
    545      * - for a mesage with body, the id matches the one from loadBodyForMessageId.
    546      */
    547     public void testLookupBodyIdWithMessageId() {
    548         final ContentResolver resolver = mMockContext.getContentResolver();
    549         Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext);
    550         long account1Id = account1.mId;
    551         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
    552         long box1Id = box1.mId;
    553 
    554         // 1. create message with no body, check that returned bodyId is -1
    555         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
    556                 true, mMockContext);
    557         long message1Id = message1.mId;
    558         long bodyId1 = Body.lookupBodyIdWithMessageId(resolver, message1Id);
    559         assertEquals(bodyId1, -1);
    560 
    561         // 2. create message with body, check that returned bodyId is correct
    562         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
    563                 true, mMockContext);
    564         long message2Id = message2.mId;
    565         long bodyId2 = Body.lookupBodyIdWithMessageId(resolver, message2Id);
    566         Body body = loadBodyForMessageId(message2Id);
    567         assertNotNull(body);
    568         assertEquals(body.mId, bodyId2);
    569     }
    570 
    571     /**
    572      * Test for Body.updateBodyWithMessageId().
    573      * 1. - create message without body,
    574      *    - update its body (set TEXT_CONTENT)
    575      *    - check correct updated body is read back
    576      *
    577      * 2. - create message with body,
    578      *    - update body (set TEXT_CONTENT)
    579      *    - check correct updated body is read back
    580      */
    581     public void testUpdateBodyWithMessageId() {
    582         Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext);
    583         long account1Id = account1.mId;
    584         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
    585         long box1Id = box1.mId;
    586 
    587         final String textContent = "foobar some odd text";
    588         final String htmlContent = "and some html";
    589         final String textReply = "plain text reply";
    590         final String htmlReply = "or the html reply";
    591         final String introText = "fred wrote:";
    592 
    593         ContentValues values = new ContentValues();
    594         values.put(BodyColumns.TEXT_CONTENT, textContent);
    595         values.put(BodyColumns.HTML_CONTENT, htmlContent);
    596         values.put(BodyColumns.TEXT_REPLY, textReply);
    597         values.put(BodyColumns.HTML_REPLY, htmlReply);
    598         values.put(BodyColumns.SOURCE_MESSAGE_KEY, 17);
    599         values.put(BodyColumns.INTRO_TEXT, introText);
    600 
    601         // 1
    602         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
    603                 true, mMockContext);
    604         long message1Id = message1.mId;
    605         Body body1 = loadBodyForMessageId(message1Id);
    606         assertNull(body1);
    607         Body.updateBodyWithMessageId(mMockContext, message1Id, values);
    608         body1 = loadBodyForMessageId(message1Id);
    609         assertNotNull(body1);
    610         assertEquals(body1.mTextContent, textContent);
    611         assertEquals(body1.mHtmlContent, htmlContent);
    612         assertEquals(body1.mTextReply, textReply);
    613         assertEquals(body1.mHtmlReply, htmlReply);
    614         assertEquals(body1.mSourceKey, 17);
    615         assertEquals(body1.mIntroText, introText);
    616 
    617         // 2
    618         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
    619                 true, mMockContext);
    620         long message2Id = message2.mId;
    621         Body body2 = loadBodyForMessageId(message2Id);
    622         assertNotNull(body2);
    623         assertTrue(!body2.mTextContent.equals(textContent));
    624         Body.updateBodyWithMessageId(mMockContext, message2Id, values);
    625         body2 = loadBodyForMessageId(message1Id);
    626         assertNotNull(body2);
    627         assertEquals(body2.mTextContent, textContent);
    628         assertEquals(body2.mHtmlContent, htmlContent);
    629         assertEquals(body2.mTextReply, textReply);
    630         assertEquals(body2.mHtmlReply, htmlReply);
    631         assertEquals(body2.mSourceKey, 17);
    632         assertEquals(body2.mIntroText, introText);
    633     }
    634 
    635     /**
    636      * Test body retrieve methods
    637      */
    638     public void testBodyRetrieve() {
    639         // No account needed
    640         // No mailbox needed
    641         Message message1 = ProviderTestUtils.setupMessage("bodyretrieve", 1, 1, true,
    642                 true, mMockContext);
    643         long messageId = message1.mId;
    644 
    645         assertEquals(message1.mText,
    646                 Body.restoreBodyTextWithMessageId(mMockContext, messageId));
    647         assertEquals(message1.mHtml,
    648                 Body.restoreBodyHtmlWithMessageId(mMockContext, messageId));
    649         assertEquals(message1.mTextReply,
    650                 Body.restoreReplyTextWithMessageId(mMockContext, messageId));
    651         assertEquals(message1.mHtmlReply,
    652                 Body.restoreReplyHtmlWithMessageId(mMockContext, messageId));
    653         assertEquals(message1.mIntroText,
    654                 Body.restoreIntroTextWithMessageId(mMockContext, messageId));
    655         assertEquals(message1.mSourceKey,
    656                 Body.restoreBodySourceKey(mMockContext, messageId));
    657     }
    658 
    659     /**
    660      * Test delete body.
    661      * 1. create message without body (message id 1)
    662      * 2. create message with body (message id 2. The body has _id 1 and messageKey 2).
    663      * 3. delete first message.
    664      * 4. verify that body for message 2 has not been deleted.
    665      * 5. delete message 2, verify body is deleted.
    666      */
    667     public void testDeleteBody() {
    668         final ContentResolver resolver = mMockContext.getContentResolver();
    669 
    670         // Create account and mailboxes
    671         Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext);
    672         long account1Id = account1.mId;
    673         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
    674         long box1Id = box1.mId;
    675 
    676         // 1. create message without body
    677         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
    678                 true, mMockContext);
    679         long message1Id = message1.mId;
    680 
    681         // 2. create message with body
    682         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
    683                 true, mMockContext);
    684         long message2Id = message2.mId;
    685         // verify body is there
    686         assertNotNull(loadBodyForMessageId(message2Id));
    687 
    688         // 3. delete first message
    689         resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null);
    690 
    691         // 4. verify body for second message wasn't deleted
    692         assertNotNull(loadBodyForMessageId(message2Id));
    693 
    694         // 5. delete second message, check its body is deleted
    695         resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message2Id), null, null);
    696         assertNull(loadBodyForMessageId(message2Id));
    697     }
    698 
    699     /**
    700      * Test delete orphan bodies.
    701      * 1. create message without body (message id 1)
    702      * 2. create message with body (message id 2. Body has _id 1 and messageKey 2).
    703      * 3. delete first message.
    704      * 4. delete some other mailbox -- this triggers delete orphan bodies.
    705      * 5. verify that body for message 2 has not been deleted.
    706      */
    707     public void testDeleteOrphanBodies() {
    708         final ContentResolver resolver = mMockContext.getContentResolver();
    709 
    710         // Create account and two mailboxes
    711         Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext);
    712         long account1Id = account1.mId;
    713         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
    714         long box1Id = box1.mId;
    715         Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mMockContext);
    716         long box2Id = box2.mId;
    717 
    718         // 1. create message without body
    719         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
    720                 true, mMockContext);
    721         long message1Id = message1.mId;
    722 
    723         // 2. create message with body
    724         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
    725                 true, mMockContext);
    726         long message2Id = message2.mId;
    727         //verify body is there
    728         assertNotNull(loadBodyForMessageId(message2Id));
    729 
    730         // 3. delete first message
    731         resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null);
    732 
    733         // 4. delete some mailbox (because it triggers "delete orphan bodies")
    734         resolver.delete(ContentUris.withAppendedId(Mailbox.CONTENT_URI, box2Id), null, null);
    735 
    736         // 5. verify body for second message wasn't deleted during "delete orphan bodies"
    737         assertNotNull(loadBodyForMessageId(message2Id));
    738     }
    739 
    740     /**
    741      * Test delete orphan messages
    742      * 1. create message without body (message id 1)
    743      * 2. create message with body (message id 2. Body has _id 1 and messageKey 2).
    744      * 3. delete first message.
    745      * 4. delete some other mailbox -- this triggers delete orphan bodies.
    746      * 5. verify that body for message 2 has not been deleted.
    747      */
    748      public void testDeleteOrphanMessages() {
    749         final ContentResolver resolver = mMockContext.getContentResolver();
    750         final Context context = mMockContext;
    751 
    752         // Create account and two mailboxes
    753         Account acct = ProviderTestUtils.setupAccount("orphaned body", true, context);
    754         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
    755         Mailbox box2 = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context);
    756 
    757         // Create 4 messages in box1
    758         Message msg1_1 =
    759             ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, false, true, context);
    760         Message msg1_2 =
    761             ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, false, true, context);
    762         Message msg1_3 =
    763             ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, false, true, context);
    764         Message msg1_4 =
    765             ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, false, true, context);
    766 
    767         // Create 4 messages in box2
    768         Message msg2_1 =
    769             ProviderTestUtils.setupMessage("message1", acct.mId, box2.mId, false, true, context);
    770         Message msg2_2 =
    771             ProviderTestUtils.setupMessage("message2", acct.mId, box2.mId, false, true, context);
    772         Message msg2_3 =
    773             ProviderTestUtils.setupMessage("message3", acct.mId, box2.mId, false, true, context);
    774         Message msg2_4 =
    775             ProviderTestUtils.setupMessage("message4", acct.mId, box2.mId, false, true, context);
    776 
    777         // Delete 2 from each mailbox
    778         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_1.mId),
    779                 null, null);
    780         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_2.mId),
    781                 null, null);
    782         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_1.mId),
    783                 null, null);
    784         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_2.mId),
    785                 null, null);
    786 
    787         // There should be 4 items in the deleted item table
    788         assertEquals(4, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null));
    789 
    790         // Update 2 from each mailbox
    791         ContentValues v = new ContentValues();
    792         v.put(MessageColumns.DISPLAY_NAME, "--updated--");
    793         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_3.mId),
    794                 v, null, null);
    795         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_4.mId),
    796                 v, null, null);
    797         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_3.mId),
    798                 v, null, null);
    799         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_4.mId),
    800                 v, null, null);
    801 
    802          // There should be 4 items in the updated item table
    803         assertEquals(4, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null));
    804 
    805         // Manually add 2 messages from a "deleted" mailbox to deleted and updated tables
    806         // Use a value > 2 for the deleted box id
    807         long delBoxId = 10;
    808         // Create 4 messages in the "deleted" mailbox
    809         Message msgX_A =
    810             ProviderTestUtils.setupMessage("messageA", acct.mId, delBoxId, false, false, context);
    811         Message msgX_B =
    812             ProviderTestUtils.setupMessage("messageB", acct.mId, delBoxId, false, false, context);
    813         Message msgX_C =
    814             ProviderTestUtils.setupMessage("messageC", acct.mId, delBoxId, false, false, context);
    815         Message msgX_D =
    816             ProviderTestUtils.setupMessage("messageD", acct.mId, delBoxId, false, false, context);
    817 
    818         ContentValues cv;
    819         // We have to assign id's manually because there are no autoincrement id's for these tables
    820         // Start with an id that won't exist, since id's in these tables must be unique
    821         long msgId = 10;
    822         // It's illegal to manually insert these, so we need to catch the exception
    823         // NOTE: The insert succeeds, and then throws the exception
    824         try {
    825             cv = msgX_A.toContentValues();
    826             cv.put(EmailContent.RECORD_ID, msgId++);
    827             resolver.insert(Message.DELETED_CONTENT_URI, cv);
    828         } catch (IllegalArgumentException e) {
    829         }
    830         try {
    831             cv = msgX_B.toContentValues();
    832             cv.put(EmailContent.RECORD_ID, msgId++);
    833             resolver.insert(Message.DELETED_CONTENT_URI, cv);
    834         } catch (IllegalArgumentException e) {
    835         }
    836         try {
    837             cv = msgX_C.toContentValues();
    838             cv.put(EmailContent.RECORD_ID, msgId++);
    839             resolver.insert(Message.UPDATED_CONTENT_URI, cv);
    840         } catch (IllegalArgumentException e) {
    841         }
    842         try {
    843             cv = msgX_D.toContentValues();
    844             cv.put(EmailContent.RECORD_ID, msgId++);
    845             resolver.insert(Message.UPDATED_CONTENT_URI, cv);
    846         } catch (IllegalArgumentException e) {
    847         }
    848 
    849         // There should be 6 items in the deleted and updated tables
    850         assertEquals(6, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null));
    851         assertEquals(6, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null));
    852 
    853         // Delete the orphans
    854         EmailProvider.deleteOrphans(EmailProvider.getReadableDatabase(context),
    855                 Message.DELETED_TABLE_NAME);
    856         EmailProvider.deleteOrphans(EmailProvider.getReadableDatabase(context),
    857                 Message.UPDATED_TABLE_NAME);
    858 
    859         // There should now be 4 messages in each of the deleted and updated tables again
    860         assertEquals(4, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null));
    861         assertEquals(4, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null));
    862     }
    863 
    864     /**
    865      * Test delete mailbox
    866      */
    867     public void testMailboxDelete() {
    868         Account account1 = ProviderTestUtils.setupAccount("mailbox-delete", true, mMockContext);
    869         long account1Id = account1.mId;
    870         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
    871         long box1Id = box1.mId;
    872         Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mMockContext);
    873         long box2Id = box2.mId;
    874 
    875         String selection = EmailContent.MailboxColumns.ACCOUNT_KEY + "=?";
    876         String[] selArgs = new String[] { String.valueOf(account1Id) };
    877 
    878         // make sure there are two mailboxes
    879         int numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs);
    880         assertEquals(2, numBoxes);
    881 
    882         // now delete one of them
    883         Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box1Id);
    884         mMockContext.getContentResolver().delete(uri, null, null);
    885 
    886         // make sure there's only one mailbox now
    887         numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs);
    888         assertEquals(1, numBoxes);
    889 
    890         // now delete the other one
    891         uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box2Id);
    892         mMockContext.getContentResolver().delete(uri, null, null);
    893 
    894         // make sure there are no mailboxes now
    895         numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs);
    896         assertEquals(0, numBoxes);
    897     }
    898 
    899     /**
    900      * Test delete message
    901      * TODO: body
    902      * TODO: attachments
    903      */
    904     public void testMessageDelete() {
    905         Account account1 = ProviderTestUtils.setupAccount("message-delete", true, mMockContext);
    906         long account1Id = account1.mId;
    907         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
    908         long box1Id = box1.mId;
    909         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
    910                 true, mMockContext);
    911         long message1Id = message1.mId;
    912         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false,
    913                 true, mMockContext);
    914         long message2Id = message2.mId;
    915 
    916         String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " +
    917                 EmailContent.MessageColumns.MAILBOX_KEY + "=?";
    918         String[] selArgs = new String[] { String.valueOf(account1Id), String.valueOf(box1Id) };
    919 
    920         // make sure there are two messages
    921         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
    922         assertEquals(2, numMessages);
    923 
    924         // now delete one of them
    925         Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id);
    926         mMockContext.getContentResolver().delete(uri, null, null);
    927 
    928         // make sure there's only one message now
    929         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
    930         assertEquals(1, numMessages);
    931 
    932         // now delete the other one
    933         uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id);
    934         mMockContext.getContentResolver().delete(uri, null, null);
    935 
    936         // make sure there are no messages now
    937         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
    938         assertEquals(0, numMessages);
    939     }
    940 
    941     /**
    942      * Test delete synced message
    943      * TODO: body
    944      * TODO: attachments
    945      */
    946     public void testSyncedMessageDelete() {
    947         Account account1 = ProviderTestUtils.setupAccount("synced-message-delete", true,
    948                 mMockContext);
    949         long account1Id = account1.mId;
    950         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
    951         long box1Id = box1.mId;
    952         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
    953                 true, mMockContext);
    954         long message1Id = message1.mId;
    955         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false,
    956                 true, mMockContext);
    957         long message2Id = message2.mId;
    958 
    959         String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND "
    960                 + EmailContent.MessageColumns.MAILBOX_KEY + "=?";
    961         String[] selArgs = new String[] {
    962             String.valueOf(account1Id), String.valueOf(box1Id)
    963         };
    964 
    965         // make sure there are two messages
    966         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
    967         assertEquals(2, numMessages);
    968 
    969         // make sure we start with no synced deletions
    970         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
    971                 selArgs);
    972         assertEquals(0, numMessages);
    973 
    974         // now delete one of them SYNCED
    975         Uri uri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message1Id);
    976         mMockContext.getContentResolver().delete(uri, null, null);
    977 
    978         // make sure there's only one message now
    979         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
    980         assertEquals(1, numMessages);
    981 
    982         // make sure there's one synced deletion now
    983         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
    984                 selArgs);
    985         assertEquals(1, numMessages);
    986 
    987         // now delete the other one NOT SYNCED
    988         uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id);
    989         mMockContext.getContentResolver().delete(uri, null, null);
    990 
    991         // make sure there are no messages now
    992         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
    993         assertEquals(0, numMessages);
    994 
    995         // make sure there's still one deletion now
    996         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
    997                 selArgs);
    998         assertEquals(1, numMessages);
    999     }
   1000 
   1001     /**
   1002      * Test message update
   1003      * TODO: body
   1004      * TODO: attachments
   1005      */
   1006     public void testMessageUpdate() {
   1007         Account account1 = ProviderTestUtils.setupAccount("message-update", true, mMockContext);
   1008         long account1Id = account1.mId;
   1009         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
   1010         long box1Id = box1.mId;
   1011         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
   1012                 true, mMockContext);
   1013         long message1Id = message1.mId;
   1014         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false,
   1015                 true, mMockContext);
   1016         long message2Id = message2.mId;
   1017         ContentResolver cr = mMockContext.getContentResolver();
   1018 
   1019         String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND "
   1020                 + EmailContent.MessageColumns.MAILBOX_KEY + "=?";
   1021         String[] selArgs = new String[] {
   1022             String.valueOf(account1Id), String.valueOf(box1Id)
   1023         };
   1024 
   1025         // make sure there are two messages
   1026         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
   1027         assertEquals(2, numMessages);
   1028 
   1029         // change the first one
   1030         Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id);
   1031         ContentValues cv = new ContentValues();
   1032         cv.put(MessageColumns.FROM_LIST, "from-list");
   1033         cr.update(uri, cv, null, null);
   1034 
   1035         // make sure there's no updated message
   1036         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
   1037                 selArgs);
   1038         assertEquals(0, numMessages);
   1039 
   1040         // get the message back from the provider, make sure the change "stuck"
   1041         Message restoredMessage = Message.restoreMessageWithId(mMockContext, message1Id);
   1042         assertEquals("from-list", restoredMessage.mFrom);
   1043 
   1044         // change the second one
   1045         uri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2Id);
   1046         cv = new ContentValues();
   1047         cv.put(MessageColumns.FROM_LIST, "from-list");
   1048         cr.update(uri, cv, null, null);
   1049 
   1050         // make sure there's one updated message
   1051         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
   1052                 selArgs);
   1053         assertEquals(1, numMessages);
   1054 
   1055         // get the message back from the provider, make sure the change "stuck",
   1056         // as before
   1057         restoredMessage = Message.restoreMessageWithId(mMockContext, message2Id);
   1058         assertEquals("from-list", restoredMessage.mFrom);
   1059 
   1060         // get the original message back from the provider
   1061         Cursor c = cr.query(Message.UPDATED_CONTENT_URI, Message.CONTENT_PROJECTION, null, null,
   1062                 null);
   1063         try {
   1064             assertTrue(c.moveToFirst());
   1065             Message originalMessage = EmailContent.getContent(c, Message.class);
   1066             // make sure this has the original value
   1067             assertEquals("from message2", originalMessage.mFrom);
   1068             // Should only be one
   1069             assertFalse(c.moveToNext());
   1070         } finally {
   1071             c.close();
   1072         }
   1073 
   1074         // delete the second message
   1075         cr.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2Id), null, null);
   1076 
   1077         // hey, presto! the change should be gone
   1078         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
   1079                 selArgs);
   1080         assertEquals(0, numMessages);
   1081 
   1082         // and there should now be a deleted record
   1083         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
   1084                 selArgs);
   1085         assertEquals(1, numMessages);
   1086     }
   1087 
   1088     /**
   1089      * TODO: cascaded delete account
   1090      * TODO: hostauth
   1091      * TODO: body
   1092      * TODO: attachments
   1093      * TODO: create other account, mailbox & messages and confirm the right objects were deleted
   1094      */
   1095     public void testCascadeDeleteAccount() {
   1096         Account account1 = ProviderTestUtils.setupAccount("account-delete-cascade", true,
   1097                 mMockContext);
   1098         long account1Id = account1.mId;
   1099         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
   1100         long box1Id = box1.mId;
   1101         /* Message message1 = */ ProviderTestUtils.setupMessage("message1", account1Id, box1Id,
   1102                 false, true, mMockContext);
   1103         /* Message message2 = */ ProviderTestUtils.setupMessage("message2", account1Id, box1Id,
   1104                 false, true, mMockContext);
   1105 
   1106         // make sure there is one account, one mailbox, and two messages
   1107         int numAccounts = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
   1108         assertEquals(1, numAccounts);
   1109         int numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, null, null);
   1110         assertEquals(1, numBoxes);
   1111         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
   1112         assertEquals(2, numMessages);
   1113 
   1114         // delete the account
   1115         Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id);
   1116         mMockContext.getContentResolver().delete(uri, null, null);
   1117 
   1118         // make sure there are no accounts, mailboxes, or messages
   1119         numAccounts = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
   1120         assertEquals(0, numAccounts);
   1121         numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, null, null);
   1122         assertEquals(0, numBoxes);
   1123         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
   1124         assertEquals(0, numMessages);
   1125     }
   1126 
   1127     /**
   1128      * Test cascaded delete mailbox
   1129      * TODO: body
   1130      * TODO: attachments
   1131      * TODO: create other mailbox & messages and confirm the right objects were deleted
   1132      */
   1133     public void testCascadeDeleteMailbox() {
   1134         Account account1 = ProviderTestUtils.setupAccount("mailbox-delete-cascade", true,
   1135                 mMockContext);
   1136         long account1Id = account1.mId;
   1137         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
   1138         long box1Id = box1.mId;
   1139         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id,
   1140                 false, true, mMockContext);
   1141         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id,
   1142                 false, true, mMockContext);
   1143         Message message3 = ProviderTestUtils.setupMessage("message3", account1Id, box1Id,
   1144                 false, true, mMockContext);
   1145         Message message4 = ProviderTestUtils.setupMessage("message4", account1Id, box1Id,
   1146                 false, true, mMockContext);
   1147         ProviderTestUtils.setupMessage("message5", account1Id, box1Id, false, true, mMockContext);
   1148         ProviderTestUtils.setupMessage("message6", account1Id, box1Id, false, true, mMockContext);
   1149 
   1150         String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " +
   1151                 EmailContent.MessageColumns.MAILBOX_KEY + "=?";
   1152         String[] selArgs = new String[] { String.valueOf(account1Id), String.valueOf(box1Id) };
   1153 
   1154         // make sure there are six messages
   1155         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
   1156         assertEquals(6, numMessages);
   1157 
   1158         ContentValues cv = new ContentValues();
   1159         cv.put(Message.SERVER_ID, "SERVER_ID");
   1160         ContentResolver resolver = mMockContext.getContentResolver();
   1161 
   1162         // Update two messages
   1163         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message1.mId),
   1164                 cv, null, null);
   1165         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2.mId),
   1166                 cv, null, null);
   1167         // Delete two messages
   1168         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message3.mId),
   1169                 null, null);
   1170         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message4.mId),
   1171                 null, null);
   1172 
   1173         // There should now be two messages in updated/deleted, and 4 in messages
   1174         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
   1175         assertEquals(4, numMessages);
   1176         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
   1177                 selArgs);
   1178         assertEquals(2, numMessages);
   1179         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
   1180                 selArgs);
   1181         assertEquals(2, numMessages);
   1182 
   1183         // now delete the mailbox
   1184         Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box1Id);
   1185         resolver.delete(uri, null, null);
   1186 
   1187         // there should now be zero messages in all three tables
   1188         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
   1189         assertEquals(0, numMessages);
   1190         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
   1191                 selArgs);
   1192         assertEquals(0, numMessages);
   1193         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
   1194                 selArgs);
   1195         assertEquals(0, numMessages);
   1196     }
   1197 
   1198     /**
   1199      * Test cascaded delete message
   1200      * Confirms that deleting a message will also delete its body & attachments
   1201      */
   1202     public void testCascadeMessageDelete() {
   1203         Account account1 = ProviderTestUtils.setupAccount("message-cascade", true, mMockContext);
   1204         long account1Id = account1.mId;
   1205         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
   1206         long box1Id = box1.mId;
   1207 
   1208         // Each message has a body, and also give each 2 attachments
   1209         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
   1210                 false, mMockContext);
   1211         ArrayList<Attachment> atts = new ArrayList<Attachment>();
   1212         for (int i = 0; i < 2; i++) {
   1213             atts.add(ProviderTestUtils.setupAttachment(
   1214                     -1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
   1215                     false, mMockContext));
   1216         }
   1217         message1.mAttachments = atts;
   1218         message1.save(mMockContext);
   1219         long message1Id = message1.mId;
   1220 
   1221         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, true,
   1222                 false, mMockContext);
   1223         atts = new ArrayList<Attachment>();
   1224         for (int i = 0; i < 2; i++) {
   1225             atts.add(ProviderTestUtils.setupAttachment(
   1226                     -1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
   1227                     false, mMockContext));
   1228         }
   1229         message2.mAttachments = atts;
   1230         message2.save(mMockContext);
   1231         long message2Id = message2.mId;
   1232 
   1233         // Set up to test total counts of bodies & attachments for our test messages
   1234         String bodySelection = BodyColumns.MESSAGE_KEY + " IN (?,?)";
   1235         String attachmentSelection = AttachmentColumns.MESSAGE_KEY + " IN (?,?)";
   1236         String[] selArgs = new String[] { String.valueOf(message1Id), String.valueOf(message2Id) };
   1237 
   1238         // make sure there are two bodies
   1239         int numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs);
   1240         assertEquals(2, numBodies);
   1241 
   1242         // make sure there are four attachments
   1243         int numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI,
   1244                 attachmentSelection, selArgs);
   1245         assertEquals(4, numAttachments);
   1246 
   1247         // now delete one of the messages
   1248         Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id);
   1249         mMockContext.getContentResolver().delete(uri, null, null);
   1250 
   1251         // there should be one body and two attachments
   1252         numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs);
   1253         assertEquals(1, numBodies);
   1254 
   1255         numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI,
   1256                 attachmentSelection, selArgs);
   1257         assertEquals(2, numAttachments);
   1258 
   1259         // now delete the other message
   1260         uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id);
   1261         mMockContext.getContentResolver().delete(uri, null, null);
   1262 
   1263         // make sure there are no bodies or attachments
   1264         numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs);
   1265         assertEquals(0, numBodies);
   1266 
   1267         numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI,
   1268                 attachmentSelection, selArgs);
   1269         assertEquals(0, numAttachments);
   1270     }
   1271 
   1272     /**
   1273      * Test that our unique file name algorithm works as expected.  Since this test requires an
   1274      * SD card, we check the environment first, and return immediately if none is mounted.
   1275      * @throws IOException
   1276      */
   1277     public void testCreateUniqueFile() throws IOException {
   1278         // Delete existing files, if they exist
   1279         if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
   1280             return;
   1281         }
   1282         try {
   1283             String fileName = "A11achm3n1.doc";
   1284             File uniqueFile = Attachment.createUniqueFile(fileName);
   1285             assertEquals(fileName, uniqueFile.getName());
   1286             if (uniqueFile.createNewFile()) {
   1287                 uniqueFile = Attachment.createUniqueFile(fileName);
   1288                 assertEquals("A11achm3n1-2.doc", uniqueFile.getName());
   1289                 if (uniqueFile.createNewFile()) {
   1290                     uniqueFile = Attachment.createUniqueFile(fileName);
   1291                     assertEquals("A11achm3n1-3.doc", uniqueFile.getName());
   1292                 }
   1293            }
   1294             fileName = "A11achm3n1";
   1295             uniqueFile = Attachment.createUniqueFile(fileName);
   1296             assertEquals(fileName, uniqueFile.getName());
   1297             if (uniqueFile.createNewFile()) {
   1298                 uniqueFile = Attachment.createUniqueFile(fileName);
   1299                 assertEquals("A11achm3n1-2", uniqueFile.getName());
   1300             }
   1301         } finally {
   1302             File directory = Environment.getExternalStorageDirectory();
   1303             // These are the files that should be created earlier in the test.  Make sure
   1304             // they are deleted for the next go-around
   1305             String[] fileNames = new String[] {"A11achm3n1.doc", "A11achm3n1-2.doc", "A11achm3n1"};
   1306             int length = fileNames.length;
   1307             for (int i = 0; i < length; i++) {
   1308                 File file = new File(directory, fileNames[i]);
   1309                 if (file.exists()) {
   1310                     file.delete();
   1311                 }
   1312             }
   1313         }
   1314     }
   1315 
   1316     /**
   1317      * Test retrieving attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI)
   1318      */
   1319     public void testGetAttachmentByMessageIdUri() {
   1320 
   1321         // Note, we don't strictly need accounts, mailboxes or messages to run this test.
   1322         Attachment a1 = ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext);
   1323         Attachment a2 = ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext);
   1324         ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext);
   1325         ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext);
   1326 
   1327         // Now ask for the attachments of message id=1
   1328         // Note: Using the "sort by size" trick to bring them back in expected order
   1329         Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1);
   1330         Cursor c = mMockContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
   1331                 null, null, Attachment.SIZE);
   1332         assertEquals(2, c.getCount());
   1333 
   1334         try {
   1335             c.moveToFirst();
   1336             Attachment a1Get = EmailContent.getContent(c, Attachment.class);
   1337             ProviderTestUtils.assertAttachmentEqual("getAttachByUri-1", a1, a1Get);
   1338             c.moveToNext();
   1339             Attachment a2Get = EmailContent.getContent(c, Attachment.class);
   1340             ProviderTestUtils.assertAttachmentEqual("getAttachByUri-2", a2, a2Get);
   1341         } finally {
   1342             c.close();
   1343         }
   1344     }
   1345 
   1346     /**
   1347      * Test deleting attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI)
   1348      */
   1349     public void testDeleteAttachmentByMessageIdUri() {
   1350         ContentResolver mockResolver = mMockContext.getContentResolver();
   1351 
   1352         // Note, we don't strictly need accounts, mailboxes or messages to run this test.
   1353         ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext);
   1354         ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext);
   1355         Attachment a3 = ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext);
   1356         Attachment a4 = ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext);
   1357 
   1358         // Delete all attachments for message id=1
   1359         Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1);
   1360         mockResolver.delete(uri, null, null);
   1361 
   1362         // Read back all attachments and confirm that we have the expected remaining attachments
   1363         // (the attachments that are set for message id=2).  Note order-by size to simplify test.
   1364         Cursor c = mockResolver.query(Attachment.CONTENT_URI, Attachment.CONTENT_PROJECTION,
   1365                 null, null, Attachment.SIZE);
   1366         assertEquals(2, c.getCount());
   1367 
   1368         try {
   1369             c.moveToFirst();
   1370             Attachment a3Get = EmailContent.getContent(c, Attachment.class);
   1371             ProviderTestUtils.assertAttachmentEqual("getAttachByUri-3", a3, a3Get);
   1372             c.moveToNext();
   1373             Attachment a4Get = EmailContent.getContent(c, Attachment.class);
   1374             ProviderTestUtils.assertAttachmentEqual("getAttachByUri-4", a4, a4Get);
   1375         } finally {
   1376             c.close();
   1377         }
   1378     }
   1379 
   1380     /**
   1381      * Tests of default account behavior
   1382      *
   1383      * 1.  Simple set/get
   1384      * 2.  Moving default between 3 accounts
   1385      * 3.  Delete default, make sure another becomes default
   1386      */
   1387     public void testSetGetDefaultAccount() {
   1388         // There should be no default account if there are no accounts
   1389         long defaultAccountId = Account.getDefaultAccountId(mMockContext);
   1390         assertEquals(-1, defaultAccountId);
   1391 
   1392         Account account1 = ProviderTestUtils.setupAccount("account-default-1", true, mMockContext);
   1393         long account1Id = account1.mId;
   1394         Account account2 = ProviderTestUtils.setupAccount("account-default-2", true, mMockContext);
   1395         long account2Id = account2.mId;
   1396         Account account3 = ProviderTestUtils.setupAccount("account-default-3", true, mMockContext);
   1397         long account3Id = account3.mId;
   1398 
   1399         // With three accounts, but none marked default, confirm that some default account
   1400         // is returned.  Which one is undefined here.
   1401         defaultAccountId = Account.getDefaultAccountId(mMockContext);
   1402         assertTrue(defaultAccountId == account1Id
   1403                     || defaultAccountId == account2Id
   1404                     || defaultAccountId == account3Id);
   1405 
   1406         updateIsDefault(account1, true);
   1407         defaultAccountId = Account.getDefaultAccountId(mMockContext);
   1408         assertEquals(account1Id, defaultAccountId);
   1409 
   1410         updateIsDefault(account2, true);
   1411         defaultAccountId = Account.getDefaultAccountId(mMockContext);
   1412         assertEquals(account2Id, defaultAccountId);
   1413 
   1414         updateIsDefault(account3, true);
   1415         defaultAccountId = Account.getDefaultAccountId(mMockContext);
   1416         assertEquals(account3Id, defaultAccountId);
   1417 
   1418         // Now delete a non-default account and confirm no change
   1419         Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id);
   1420         mMockContext.getContentResolver().delete(uri, null, null);
   1421 
   1422         defaultAccountId = Account.getDefaultAccountId(mMockContext);
   1423         assertEquals(account3Id, defaultAccountId);
   1424 
   1425         // Now confirm deleting the default account and it switches to another one
   1426         uri = ContentUris.withAppendedId(Account.CONTENT_URI, account3Id);
   1427         mMockContext.getContentResolver().delete(uri, null, null);
   1428 
   1429         defaultAccountId = Account.getDefaultAccountId(mMockContext);
   1430         assertEquals(account2Id, defaultAccountId);
   1431 
   1432         // Now delete the final account and confirm there are no default accounts again
   1433         uri = ContentUris.withAppendedId(Account.CONTENT_URI, account2Id);
   1434         mMockContext.getContentResolver().delete(uri, null, null);
   1435 
   1436         defaultAccountId = Account.getDefaultAccountId(mMockContext);
   1437         assertEquals(-1, defaultAccountId);
   1438     }
   1439 
   1440     private void updateIsDefault(Account account, boolean newState) {
   1441         account.setDefaultAccount(newState);
   1442         ContentValues cv = new ContentValues();
   1443         cv.put(AccountColumns.IS_DEFAULT, account.mIsDefault);
   1444         account.update(mMockContext, cv);
   1445     }
   1446 
   1447     public static Message setupUnreadMessage(String name, long accountId, long mailboxId,
   1448             boolean addBody, boolean saveIt, Context context) {
   1449         Message msg =
   1450             ProviderTestUtils.setupMessage(name, accountId, mailboxId, addBody, false, context);
   1451         msg.mFlagRead = false;
   1452         if (saveIt) {
   1453             msg.save(context);
   1454         }
   1455         return msg;
   1456     }
   1457 
   1458     public void testUnreadCountTriggers() {
   1459         // Start with one account and three mailboxes
   1460         Account account = ProviderTestUtils.setupAccount("triggers", true, mMockContext);
   1461         Mailbox boxA = ProviderTestUtils.setupMailbox("boxA", account.mId, true, mMockContext);
   1462         Mailbox boxB = ProviderTestUtils.setupMailbox("boxB", account.mId, true, mMockContext);
   1463         Mailbox boxC = ProviderTestUtils.setupMailbox("boxC", account.mId, true, mMockContext);
   1464 
   1465         // Make sure there are no unreads
   1466         assertEquals(0, getUnreadCount(boxA.mId));
   1467         assertEquals(0, getUnreadCount(boxB.mId));
   1468         assertEquals(0, getUnreadCount(boxC.mId));
   1469 
   1470         // Create 4 unread messages (only 3 named) in boxA
   1471         Message message1 = setupUnreadMessage("message1", account.mId, boxA.mId,
   1472                 false, true, mMockContext);
   1473         Message message2= setupUnreadMessage("message2", account.mId, boxA.mId,
   1474                 false, true, mMockContext);
   1475         Message message3 =  setupUnreadMessage("message3", account.mId, boxA.mId,
   1476                 false, true, mMockContext);
   1477         setupUnreadMessage("message4", account.mId, boxC.mId, false, true, mMockContext);
   1478 
   1479         // Make sure the unreads are where we expect them
   1480         assertEquals(3, getUnreadCount(boxA.mId));
   1481         assertEquals(0, getUnreadCount(boxB.mId));
   1482         assertEquals(1, getUnreadCount(boxC.mId));
   1483 
   1484         // After deleting message 1, the count in box A should be decremented (to 2)
   1485         ContentResolver cr = mMockContext.getContentResolver();
   1486         Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1.mId);
   1487         cr.delete(uri, null, null);
   1488         assertEquals(2, getUnreadCount(boxA.mId));
   1489         assertEquals(0, getUnreadCount(boxB.mId));
   1490         assertEquals(1, getUnreadCount(boxC.mId));
   1491 
   1492         // Move message 2 to box B, leaving 1 in box A and 1 in box B
   1493         message2.mMailboxKey = boxB.mId;
   1494         ContentValues cv = new ContentValues();
   1495         cv.put(MessageColumns.MAILBOX_KEY, boxB.mId);
   1496         cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message2.mId), cv, null, null);
   1497         assertEquals(1, getUnreadCount(boxA.mId));
   1498         assertEquals(1, getUnreadCount(boxB.mId));
   1499         assertEquals(1, getUnreadCount(boxC.mId));
   1500 
   1501         // Mark message 3 (from box A) read, leaving 0 in box A
   1502         cv.clear();
   1503         cv.put(MessageColumns.FLAG_READ, 1);
   1504         cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null);
   1505         assertEquals(0, getUnreadCount(boxA.mId));
   1506         assertEquals(1, getUnreadCount(boxB.mId));
   1507         assertEquals(1, getUnreadCount(boxC.mId));
   1508 
   1509         // Move message 3 to box C; should be no change (it's read)
   1510         message3.mMailboxKey = boxC.mId;
   1511         cv.clear();
   1512         cv.put(MessageColumns.MAILBOX_KEY, boxC.mId);
   1513         cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null);
   1514         assertEquals(0, getUnreadCount(boxA.mId));
   1515         assertEquals(1, getUnreadCount(boxB.mId));
   1516         assertEquals(1, getUnreadCount(boxC.mId));
   1517 
   1518         // Mark message 3 unread; it's now in box C, so that box's count should go up to 3
   1519         cv.clear();
   1520         cv.put(MessageColumns.FLAG_READ, 0);
   1521         cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null);
   1522         assertEquals(0, getUnreadCount(boxA.mId));
   1523         assertEquals(1, getUnreadCount(boxB.mId));
   1524         assertEquals(2, getUnreadCount(boxC.mId));
   1525     }
   1526 
   1527     /**
   1528      * Test for EmailProvider.createIndex().
   1529      * Check that it returns exacly the same string as the one used previously for index creation.
   1530      */
   1531     public void testCreateIndex() {
   1532         String oldStr = "create index message_" + MessageColumns.TIMESTAMP
   1533             + " on " + Message.TABLE_NAME + " (" + MessageColumns.TIMESTAMP + ");";
   1534         String newStr = EmailProvider.createIndex(Message.TABLE_NAME, MessageColumns.TIMESTAMP);
   1535         assertEquals(newStr, oldStr);
   1536     }
   1537 
   1538     public void testIdAddToField() {
   1539         ContentResolver cr = mMockContext.getContentResolver();
   1540         ContentValues cv = new ContentValues();
   1541 
   1542         // Try changing the newMessageCount of an account
   1543         Account account = ProviderTestUtils.setupAccount("field-add", true, mMockContext);
   1544         int startCount = account.mNewMessageCount;
   1545         // "field" and "add" are the two required elements
   1546         cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT);
   1547         cv.put(EmailContent.ADD_COLUMN_NAME, 17);
   1548         cr.update(ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, account.mId),
   1549                 cv, null, null);
   1550         Account restoredAccount = Account.restoreAccountWithId(mMockContext, account.mId);
   1551         assertEquals(17 + startCount, restoredAccount.mNewMessageCount);
   1552         cv.put(EmailContent.ADD_COLUMN_NAME, -11);
   1553         cr.update(ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, account.mId),
   1554                 cv, null, null);
   1555         restoredAccount = Account.restoreAccountWithId(mMockContext, account.mId);
   1556         assertEquals(17 - 11 + startCount, restoredAccount.mNewMessageCount);
   1557 
   1558         // Now try with a mailbox
   1559         Mailbox boxA = ProviderTestUtils.setupMailbox("boxA", account.mId, true, mMockContext);
   1560         assertEquals(0, boxA.mUnreadCount);
   1561         cv.put(EmailContent.FIELD_COLUMN_NAME, MailboxColumns.UNREAD_COUNT);
   1562         cv.put(EmailContent.ADD_COLUMN_NAME, 11);
   1563         cr.update(ContentUris.withAppendedId(Mailbox.ADD_TO_FIELD_URI, boxA.mId), cv, null, null);
   1564         Mailbox restoredBoxA = Mailbox.restoreMailboxWithId(mMockContext, boxA.mId);
   1565         assertEquals(11, restoredBoxA.mUnreadCount);
   1566     }
   1567 
   1568     public void testDatabaseCorruptionRecovery() {
   1569         final ContentResolver resolver = mMockContext.getContentResolver();
   1570         final Context context = mMockContext;
   1571 
   1572         // Create account and two mailboxes
   1573         Account acct = ProviderTestUtils.setupAccount("acct1", true, context);
   1574         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
   1575 
   1576         // Create 4 messages in box1 with bodies
   1577         ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, true, true, context);
   1578         ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, true, true, context);
   1579         ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, true, true, context);
   1580         ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, true, true, context);
   1581 
   1582         // Confirm there are four messages
   1583         int count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
   1584         assertEquals(4, count);
   1585         // Confirm there are four bodies
   1586         count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null);
   1587         assertEquals(4, count);
   1588 
   1589         // Find the EmailProvider.db file
   1590         File dbFile = mMockContext.getDatabasePath(EmailProvider.DATABASE_NAME);
   1591         // The EmailProvider.db database should exist (the provider creates it automatically)
   1592         assertTrue(dbFile != null);
   1593         assertTrue(dbFile.exists());
   1594         // Delete it, and confirm it is gone
   1595         assertTrue(dbFile.delete());
   1596         assertFalse(dbFile.exists());
   1597 
   1598         // Find the EmailProviderBody.db file
   1599         dbFile = mMockContext.getDatabasePath(EmailProvider.BODY_DATABASE_NAME);
   1600         // The EmailProviderBody.db database should still exist
   1601         assertTrue(dbFile != null);
   1602         assertTrue(dbFile.exists());
   1603 
   1604         // URI to uncache the databases
   1605         // This simulates the Provider starting up again (otherwise, it will still be pointing to
   1606         // the already opened files)
   1607         // Note that we only have access to the EmailProvider via the ContentResolver; therefore,
   1608         // we cannot directly call into the provider and use a URI for this
   1609         resolver.update(EmailProvider.INTEGRITY_CHECK_URI, null, null, null);
   1610 
   1611         // TODO We should check for the deletion of attachment files once this is implemented in
   1612         // the provider
   1613 
   1614         // Explanation for what happens below...
   1615         // The next time the database is created by the provider, it will notice that there's
   1616         // already a EmailProviderBody.db file.  In this case, it will delete that database to
   1617         // ensure that both are in sync (and empty)
   1618 
   1619         // Confirm there are no bodies
   1620         count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null);
   1621         assertEquals(0, count);
   1622 
   1623         // Confirm there are no messages
   1624         count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
   1625         assertEquals(0, count);
   1626     }
   1627 
   1628     public void testBodyDatabaseCorruptionRecovery() {
   1629         final ContentResolver resolver = mMockContext.getContentResolver();
   1630         final Context context = mMockContext;
   1631 
   1632         // Create account and two mailboxes
   1633         Account acct = ProviderTestUtils.setupAccount("acct1", true, context);
   1634         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
   1635 
   1636         // Create 4 messages in box1 with bodies
   1637         ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, true, true, context);
   1638         ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, true, true, context);
   1639         ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, true, true, context);
   1640         ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, true, true, context);
   1641 
   1642         // Confirm there are four messages
   1643         int count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
   1644         assertEquals(4, count);
   1645         // Confirm there are four bodies
   1646         count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null);
   1647         assertEquals(4, count);
   1648 
   1649         // Find the EmailProviderBody.db file
   1650         File dbFile = mMockContext.getDatabasePath(EmailProvider.BODY_DATABASE_NAME);
   1651         // The EmailProviderBody.db database should exist (the provider creates it automatically)
   1652         assertTrue(dbFile != null);
   1653         assertTrue(dbFile.exists());
   1654         // Delete it, and confirm it is gone
   1655         assertTrue(dbFile.delete());
   1656         assertFalse(dbFile.exists());
   1657 
   1658         // Find the EmailProvider.db file
   1659         dbFile = mMockContext.getDatabasePath(EmailProvider.DATABASE_NAME);
   1660         // The EmailProviderBody.db database should still exist
   1661         assertTrue(dbFile != null);
   1662         assertTrue(dbFile.exists());
   1663 
   1664         // URI to uncache the databases
   1665         // This simulates the Provider starting up again (otherwise, it will still be pointing to
   1666         // the already opened files)
   1667         // Note that we only have access to the EmailProvider via the ContentResolver; therefore,
   1668         // we cannot directly call into the provider and use a URI for this
   1669         resolver.update(EmailProvider.INTEGRITY_CHECK_URI, null, null, null);
   1670 
   1671         // TODO We should check for the deletion of attachment files once this is implemented in
   1672         // the provider
   1673 
   1674         // Explanation for what happens below...
   1675         // The next time the body database is created by the provider, it will notice that there's
   1676         // already a populated EmailProvider.db file.  In this case, it will delete that database to
   1677         // ensure that both are in sync (and empty)
   1678 
   1679         // Confirm there are no messages
   1680         count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
   1681         assertEquals(0, count);
   1682 
   1683         // Confirm there are no bodies
   1684         count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null);
   1685         assertEquals(0, count);
   1686     }
   1687 
   1688     public void testFindMailboxOfType() {
   1689         final Context context = mMockContext;
   1690 
   1691         // Create two accounts and a variety of mailbox types
   1692         Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context);
   1693         Mailbox acct1Inbox =
   1694             ProviderTestUtils.setupMailbox("Inbox1", acct1.mId, true, context, Mailbox.TYPE_INBOX);
   1695         Mailbox acct1Calendar
   1696         = ProviderTestUtils.setupMailbox("Cal1", acct1.mId, true, context, Mailbox.TYPE_CALENDAR);
   1697         Mailbox acct1Contacts =
   1698             ProviderTestUtils.setupMailbox("Con1", acct1.mId, true, context, Mailbox.TYPE_CONTACTS);
   1699         Account acct2 = ProviderTestUtils.setupAccount("acct1", true, context);
   1700         Mailbox acct2Inbox =
   1701             ProviderTestUtils.setupMailbox("Inbox2", acct2.mId, true, context, Mailbox.TYPE_INBOX);
   1702         Mailbox acct2Calendar =
   1703             ProviderTestUtils.setupMailbox("Cal2", acct2.mId, true, context, Mailbox.TYPE_CALENDAR);
   1704         Mailbox acct2Contacts =
   1705             ProviderTestUtils.setupMailbox("Con2", acct2.mId, true, context, Mailbox.TYPE_CONTACTS);
   1706 
   1707         // Check that we can find them by type
   1708         assertEquals(acct1Inbox.mId,
   1709                 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_INBOX));
   1710         assertEquals(acct2Inbox.mId,
   1711                 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_INBOX));
   1712         assertEquals(acct1Calendar.mId,
   1713                 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_CALENDAR));
   1714         assertEquals(acct2Calendar.mId,
   1715                 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_CALENDAR));
   1716         assertEquals(acct1Contacts.mId,
   1717                 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_CONTACTS));
   1718         assertEquals(acct2Contacts.mId,
   1719                 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_CONTACTS));
   1720     }
   1721 
   1722     public void testRestoreMailboxOfType() {
   1723         final Context context = mMockContext;
   1724 
   1725         // Create two accounts and a variety of mailbox types
   1726         Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context);
   1727         Mailbox acct1Inbox =
   1728             ProviderTestUtils.setupMailbox("Inbox1", acct1.mId, true, context, Mailbox.TYPE_INBOX);
   1729         Mailbox acct1Calendar
   1730         = ProviderTestUtils.setupMailbox("Cal1", acct1.mId, true, context, Mailbox.TYPE_CALENDAR);
   1731         Mailbox acct1Contacts =
   1732             ProviderTestUtils.setupMailbox("Con1", acct1.mId, true, context, Mailbox.TYPE_CONTACTS);
   1733         Account acct2 = ProviderTestUtils.setupAccount("acct1", true, context);
   1734         Mailbox acct2Inbox =
   1735             ProviderTestUtils.setupMailbox("Inbox2", acct2.mId, true, context, Mailbox.TYPE_INBOX);
   1736         Mailbox acct2Calendar =
   1737             ProviderTestUtils.setupMailbox("Cal2", acct2.mId, true, context, Mailbox.TYPE_CALENDAR);
   1738         Mailbox acct2Contacts =
   1739             ProviderTestUtils.setupMailbox("Con2", acct2.mId, true, context, Mailbox.TYPE_CONTACTS);
   1740 
   1741         // Check that we can find them by type
   1742         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Inbox,
   1743                 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_INBOX));
   1744         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Inbox,
   1745                 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_INBOX));
   1746         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Calendar,
   1747                 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_CALENDAR));
   1748         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Calendar,
   1749                 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_CALENDAR));
   1750         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Contacts,
   1751                 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_CONTACTS));
   1752         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Contacts,
   1753                 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_CONTACTS));
   1754     }
   1755 }
   1756