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