LegacyConversionsTests.java revision c41c47fa07a22f8a7612fb0191f152a36d95b7a5
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;
18
19import com.android.email.mail.Address;
20import com.android.email.mail.BodyPart;
21import com.android.email.mail.Flag;
22import com.android.email.mail.Message;
23import com.android.email.mail.MessageTestUtils;
24import com.android.email.mail.MessagingException;
25import com.android.email.mail.Part;
26import com.android.email.mail.Message.RecipientType;
27import com.android.email.mail.MessageTestUtils.MessageBuilder;
28import com.android.email.mail.MessageTestUtils.MultipartBuilder;
29import com.android.email.mail.internet.MimeHeader;
30import com.android.email.mail.internet.MimeMessage;
31import com.android.email.mail.internet.MimeUtility;
32import com.android.email.provider.EmailContent;
33import com.android.email.provider.EmailProvider;
34import com.android.email.provider.ProviderTestUtils;
35import com.android.email.provider.EmailContent.Attachment;
36
37import android.content.ContentUris;
38import android.content.Context;
39import android.database.Cursor;
40import android.net.Uri;
41import android.test.ProviderTestCase2;
42
43import java.io.IOException;
44import java.util.ArrayList;
45
46/**
47 * Tests of the Legacy Conversions code (used by MessagingController).
48 *
49 * NOTE:  It would probably make sense to rewrite this using a MockProvider, instead of the
50 * ProviderTestCase (which is a real provider running on a temp database).  This would be more of
51 * a true "unit test".
52 *
53 * You can run this entire test case with:
54 *   runtest -c com.android.email.LegacyConversionsTests email
55 */
56public class LegacyConversionsTests extends ProviderTestCase2<EmailProvider> {
57
58    EmailProvider mProvider;
59    Context mProviderContext;
60    Context mContext;
61
62    public LegacyConversionsTests() {
63        super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
64    }
65
66    @Override
67    public void setUp() throws Exception {
68        super.setUp();
69        mProviderContext = getMockContext();
70        mContext = getContext();
71    }
72
73    @Override
74    public void tearDown() throws Exception {
75        super.tearDown();
76    }
77
78    /**
79     * TODO: basic Legacy -> Provider Message conversions
80     * TODO: basic Legacy -> Provider Body conversions
81     * TODO: rainy day tests of all kinds
82     */
83
84    /**
85     * Sunny day test of adding attachments from an IMAP message.
86     */
87    public void testAddAttachments() throws MessagingException, IOException {
88        // Prepare a local message to add the attachments to
89        final long accountId = 1;
90        final long mailboxId = 1;
91        final EmailContent.Message localMessage = ProviderTestUtils.setupMessage(
92                "local-message", accountId, mailboxId, false, true, mProviderContext);
93
94        // Prepare a legacy message with attachments
95        Part attachment1Part = MessageTestUtils.bodyPart("image/gif", null);
96        attachment1Part.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
97                "image/gif;\n name=\"attachment1\"");
98        attachment1Part.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
99        attachment1Part.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
100                "attachment;\n filename=\"attachment1\";\n size=100");
101        attachment1Part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "101");
102
103        Part attachment2Part = MessageTestUtils.bodyPart("image/jpg", null);
104        attachment2Part.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
105                "image/jpg;\n name=\"attachment2\"");
106        attachment2Part.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
107        attachment2Part.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
108                "attachment;\n filename=\"attachment2\";\n size=200");
109        attachment2Part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "102");
110
111        final Message legacyMessage = new MessageBuilder()
112            .setBody(new MultipartBuilder("multipart/mixed")
113                     .addBodyPart(MessageTestUtils.bodyPart("text/html", null))
114                     .addBodyPart(new MultipartBuilder("multipart/mixed")
115                             .addBodyPart((BodyPart)attachment1Part)
116                             .addBodyPart((BodyPart)attachment2Part)
117                             .buildBodyPart())
118                     .build())
119                .build();
120
121        // Now, convert from legacy to provider and see what happens
122        ArrayList<Part> viewables = new ArrayList<Part>();
123        ArrayList<Part> attachments = new ArrayList<Part>();
124        MimeUtility.collectParts(legacyMessage, viewables, attachments);
125        LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
126
127        // Read back all attachments for message and check field values
128        Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
129        Cursor c = mProviderContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
130                null, null, null);
131        try {
132            assertEquals(2, c.getCount());
133            while (c.moveToNext()) {
134                Attachment attachment = Attachment.getContent(c, Attachment.class);
135                if ("101".equals(attachment.mLocation)) {
136                    checkAttachment("attachment1Part", attachment1Part, attachment);
137                } else if ("102".equals(attachment.mLocation)) {
138                    checkAttachment("attachment2Part", attachment2Part, attachment);
139                } else {
140                    fail("Unexpected attachment with location " + attachment.mLocation);
141                }
142            }
143        } finally {
144            c.close();
145        }
146    }
147
148    /**
149     * Compare attachment that was converted from Part (expected) to Provider Attachment (actual)
150     *
151     * TODO content URI should only be set if we also saved a file
152     * TODO other data encodings
153     */
154    private void checkAttachment(String tag, Part expected, EmailContent.Attachment actual)
155            throws MessagingException {
156        String contentType = MimeUtility.unfoldAndDecode(expected.getContentType());
157        String expectedName = MimeUtility.getHeaderParameter(contentType, "name");
158        assertEquals(tag, expectedName, actual.mFileName);
159        assertEquals(tag, expected.getMimeType(), actual.mMimeType);
160        String disposition = expected.getDisposition();
161        String sizeString = MimeUtility.getHeaderParameter(disposition, "size");
162        long expectedSize = Long.parseLong(sizeString);
163        assertEquals(tag, expectedSize, actual.mSize);
164        assertEquals(tag, expected.getContentId(), actual.mContentId);
165        assertNull(tag, actual.mContentUri);
166        assertTrue(tag, 0 != actual.mMessageKey);
167        String expectedPartId =
168            expected.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA)[0];
169        assertEquals(tag, expectedPartId, actual.mLocation);
170        assertEquals(tag, "B", actual.mEncoding);
171    }
172
173    /**
174     * TODO: Sunny day test of adding attachments from a POP message.
175     */
176
177    /**
178     * Sunny day tests of converting an original message to a legacy message
179     */
180    public void testMakeLegacyMessage() throws MessagingException {
181        // Set up and store a message in the provider
182        long account1Id = 1;
183        long mailbox1Id = 1;
184
185        // Test message 1: No body
186        EmailContent.Message localMessage1 = ProviderTestUtils.setupMessage("make-legacy",
187                account1Id, mailbox1Id, false, true, mProviderContext);
188        Message getMessage1 = LegacyConversions.makeMessage(mProviderContext, localMessage1);
189        checkLegacyMessage("no body", localMessage1, getMessage1);
190
191        // Test message 2: Simple body
192        EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage("make-legacy",
193                account1Id, mailbox1Id, true, false, mProviderContext);
194        localMessage2.mTextReply = null;
195        localMessage2.mHtmlReply = null;
196        localMessage2.mIntroText = null;
197        localMessage2.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK;
198        localMessage2.save(mProviderContext);
199        Message getMessage2 = LegacyConversions.makeMessage(mProviderContext, localMessage2);
200        checkLegacyMessage("simple body", localMessage2, getMessage2);
201
202        // Test message 3: Body + replied-to text
203        EmailContent.Message localMessage3 = ProviderTestUtils.setupMessage("make-legacy",
204                account1Id, mailbox1Id, true, false, mProviderContext);
205        localMessage3.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK;
206        localMessage3.mFlags |= EmailContent.Message.FLAG_TYPE_REPLY;
207        localMessage3.save(mProviderContext);
208        Message getMessage3 = LegacyConversions.makeMessage(mProviderContext, localMessage3);
209        checkLegacyMessage("reply-to", localMessage3, getMessage3);
210
211        // Test message 4: Body + forwarded text
212        EmailContent.Message localMessage4 = ProviderTestUtils.setupMessage("make-legacy",
213                account1Id, mailbox1Id, true, false, mProviderContext);
214        localMessage4.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK;
215        localMessage4.mFlags |= EmailContent.Message.FLAG_TYPE_FORWARD;
216        localMessage4.save(mProviderContext);
217        Message getMessage4 = LegacyConversions.makeMessage(mProviderContext, localMessage4);
218        checkLegacyMessage("forwarding", localMessage4, getMessage4);
219    }
220
221    /**
222     * Check equality of a pair of converted message
223     */
224    private void checkLegacyMessage(String tag, EmailContent.Message expect, Message actual)
225            throws MessagingException {
226        assertEquals(tag, expect.mServerId, actual.getUid());
227        assertEquals(tag, expect.mSubject, actual.getSubject());
228        assertEquals(tag, expect.mFrom, Address.pack(actual.getFrom()));
229        assertEquals(tag, expect.mTimeStamp, actual.getSentDate().getTime());
230        assertEquals(tag, expect.mTo, Address.pack(actual.getRecipients(RecipientType.TO)));
231        assertEquals(tag, expect.mCc, Address.pack(actual.getRecipients(RecipientType.CC)));
232        assertEquals(tag, expect.mMessageId, ((MimeMessage)actual).getMessageId());
233        // check flags
234        assertEquals(tag, expect.mFlagRead, actual.isSet(Flag.SEEN));
235        assertEquals(tag, expect.mFlagFavorite, actual.isSet(Flag.FLAGGED));
236
237        // Check the body of the message
238        ArrayList<Part> viewables = new ArrayList<Part>();
239        ArrayList<Part> attachments = new ArrayList<Part>();
240        MimeUtility.collectParts(actual, viewables, attachments);
241        String get1Text = null;
242        String get1Html = null;
243        String get1TextReply = null;
244        String get1HtmlReply = null;
245        String get1TextIntro = null;
246        for (Part viewable : viewables) {
247            String text = MimeUtility.getTextFromPart(viewable);
248            boolean isHtml = viewable.getMimeType().equalsIgnoreCase("text/html");
249            String[] headers = viewable.getHeader(MimeHeader.HEADER_ANDROID_BODY_QUOTED_PART);
250            if (headers != null) {
251                String header = headers[0];
252                boolean isReply = LegacyConversions.BODY_QUOTED_PART_REPLY.equalsIgnoreCase(header);
253                boolean isFwd = LegacyConversions.BODY_QUOTED_PART_FORWARD.equalsIgnoreCase(header);
254                boolean isIntro = LegacyConversions.BODY_QUOTED_PART_INTRO.equalsIgnoreCase(header);
255                if (isReply || isFwd) {
256                    if (isHtml) {
257                        get1HtmlReply = text;
258                    } else {
259                        get1TextReply = text;
260                    }
261                } else if (isIntro) {
262                    get1TextIntro = text;
263                }
264                // Check flags
265                int replyTypeFlags = expect.mFlags & EmailContent.Message.FLAG_TYPE_MASK;
266                if (isReply) {
267                    assertEquals(tag, EmailContent.Message.FLAG_TYPE_REPLY, replyTypeFlags);
268                }
269                if (isFwd) {
270                    assertEquals(tag, EmailContent.Message.FLAG_TYPE_FORWARD, replyTypeFlags);
271                }
272            } else {
273                if (isHtml) {
274                    get1Html = text;
275                } else {
276                    get1Text = text;
277                }
278            }
279        }
280        assertEquals(tag, expect.mText, get1Text);
281        assertEquals(tag, expect.mHtml, get1Html);
282        assertEquals(tag, expect.mTextReply, get1TextReply);
283        assertEquals(tag, expect.mHtmlReply, get1HtmlReply);
284        assertEquals(tag, expect.mIntroText, get1TextIntro);
285
286        // TODO Check the attachments
287
288//      cv.put("attachment_count", attachments.size());
289    }
290}
291