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