1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.email; 18 19 import android.content.ContentUris; 20 import android.content.Context; 21 import android.database.Cursor; 22 import android.net.Uri; 23 import android.test.ProviderTestCase2; 24 import android.test.suitebuilder.annotation.Suppress; 25 26 import com.android.email.provider.EmailProvider; 27 import com.android.email.provider.ProviderTestUtils; 28 import com.android.emailcommon.internet.MimeBodyPart; 29 import com.android.emailcommon.internet.MimeHeader; 30 import com.android.emailcommon.internet.MimeMessage; 31 import com.android.emailcommon.internet.MimeUtility; 32 import com.android.emailcommon.internet.TextBody; 33 import com.android.emailcommon.mail.Address; 34 import com.android.emailcommon.mail.BodyPart; 35 import com.android.emailcommon.mail.Flag; 36 import com.android.emailcommon.mail.Message; 37 import com.android.emailcommon.mail.Message.RecipientType; 38 import com.android.emailcommon.mail.MessageTestUtils; 39 import com.android.emailcommon.mail.MessageTestUtils.MessageBuilder; 40 import com.android.emailcommon.mail.MessageTestUtils.MultipartBuilder; 41 import com.android.emailcommon.mail.MessagingException; 42 import com.android.emailcommon.mail.Part; 43 import com.android.emailcommon.provider.EmailContent; 44 import com.android.emailcommon.provider.EmailContent.Attachment; 45 import com.android.emailcommon.utility.ConversionUtilities; 46 import com.android.emailcommon.utility.ConversionUtilities.BodyFieldData; 47 48 import java.io.IOException; 49 import java.util.ArrayList; 50 import java.util.Date; 51 52 /** 53 * Tests of the Legacy Conversions code (used by MessagingController). 54 * 55 * NOTE: It would probably make sense to rewrite this using a MockProvider, instead of the 56 * ProviderTestCase (which is a real provider running on a temp database). This would be more of 57 * a true "unit test". 58 * 59 * You can run this entire test case with: 60 * runtest -c com.android.email.LegacyConversionsTests email 61 */ 62 @Suppress 63 public class LegacyConversionsTests extends ProviderTestCase2<EmailProvider> { 64 65 private static final String UID = "UID.12345678"; 66 private static final String SENDER = "sender (at) android.com"; 67 private static final String RECIPIENT_TO = "recipient-to (at) android.com"; 68 private static final String RECIPIENT_CC = "recipient-cc (at) android.com"; 69 private static final String RECIPIENT_BCC = "recipient-bcc (at) android.com"; 70 private static final String REPLY_TO = "reply-to (at) android.com"; 71 private static final String SUBJECT = "This is the subject"; 72 private static final String MESSAGE_ID = "Test-Message-ID"; 73 private static final String MESSAGE_ID_2 = "Test-Message-ID-Second"; 74 75 EmailProvider mProvider; 76 Context mProviderContext; 77 Context mContext; 78 Preferences mPreferences = null; 79 80 public LegacyConversionsTests() { 81 super(EmailProvider.class, EmailContent.AUTHORITY); 82 } 83 84 @Override 85 public void setUp() throws Exception { 86 super.setUp(); 87 mProviderContext = getMockContext(); 88 mContext = getContext(); 89 } 90 91 /** 92 * TODO: basic Legacy -> Provider Message conversions 93 * TODO: basic Legacy -> Provider Body conversions 94 * TODO: rainy day tests of all kinds 95 */ 96 97 /** 98 * Test basic conversion from Store message to Provider message 99 * 100 * TODO: Not a complete test of all fields, and some fields need special tests (e.g. flags) 101 * TODO: There are many special cases in the tested function, that need to be 102 * tested here as well. 103 */ 104 public void testUpdateMessageFields() throws MessagingException { 105 MimeMessage message = buildTestMessage(RECIPIENT_TO, RECIPIENT_CC, RECIPIENT_BCC, 106 REPLY_TO, SENDER, SUBJECT, null); 107 EmailContent.Message localMessage = new EmailContent.Message(); 108 109 boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1); 110 assertTrue(result); 111 checkProviderMessage("testUpdateMessageFields", message, localMessage); 112 } 113 114 /** 115 * Test basic conversion from Store message to Provider message, when the provider message 116 * does not have a proper message-id. 117 */ 118 public void testUpdateMessageFieldsNoMessageId() throws MessagingException { 119 MimeMessage message = buildTestMessage(RECIPIENT_TO, RECIPIENT_CC, RECIPIENT_BCC, 120 REPLY_TO, SENDER, SUBJECT, null); 121 EmailContent.Message localMessage = new EmailContent.Message(); 122 123 // If the source message-id is null, the target should be left as-is 124 localMessage.mMessageId = MESSAGE_ID_2; 125 message.removeHeader("Message-ID"); 126 127 boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1); 128 assertTrue(result); 129 assertEquals(MESSAGE_ID_2, localMessage.mMessageId); 130 } 131 132 /** 133 * Build a lightweight Store message with simple field population 134 */ 135 private MimeMessage buildTestMessage(String to, String cc, String bcc, String replyTo, 136 String sender, String subject, String content) throws MessagingException { 137 MimeMessage message = new MimeMessage(); 138 139 if (to != null) { 140 Address[] addresses = Address.parse(to); 141 message.setRecipients(RecipientType.TO, addresses); 142 } 143 if (cc != null) { 144 Address[] addresses = Address.parse(cc); 145 message.setRecipients(RecipientType.CC, addresses); 146 } 147 if (bcc != null) { 148 Address[] addresses = Address.parse(bcc); 149 message.setRecipients(RecipientType.BCC, addresses); 150 } 151 if (replyTo != null) { 152 Address[] addresses = Address.parse(replyTo); 153 message.setReplyTo(addresses); 154 } 155 if (sender != null) { 156 Address[] addresses = Address.parse(sender); 157 message.setFrom(addresses[0]); 158 } 159 if (subject != null) { 160 message.setSubject(subject); 161 } 162 if (content != null) { 163 TextBody body = new TextBody(content); 164 message.setBody(body); 165 } 166 167 message.setUid(UID); 168 message.setSentDate(new Date()); 169 message.setInternalDate(new Date()); 170 message.setMessageId(MESSAGE_ID); 171 return message; 172 } 173 174 /** 175 * Basic test of body parts conversion from Store message to Provider message. 176 * This tests that a null body part simply results in null text, and does not crash 177 * or return "null". 178 * 179 * TODO very incomplete, there are many permutations to be explored 180 */ 181 public void testUpdateBodyFieldsNullText() throws MessagingException { 182 EmailContent.Body localBody = new EmailContent.Body(); 183 EmailContent.Message localMessage = new EmailContent.Message(); 184 ArrayList<Part> viewables = new ArrayList<Part>(); 185 Part emptyTextPart = new MimeBodyPart(null, "text/plain"); 186 viewables.add(emptyTextPart); 187 188 // a "null" body part of type text/plain should result in a null mTextContent 189 final BodyFieldData data = 190 ConversionUtilities.parseBodyFields(viewables); 191 assertNull(data.textContent); 192 } 193 194 /** 195 * Sunny day test of adding attachments from an IMAP/POP message. 196 */ 197 public void testAddAttachments() throws MessagingException, IOException { 198 // Prepare a local message to add the attachments to 199 final long accountId = 1; 200 final long mailboxId = 1; 201 202 // test 1: legacy message using content-type:name style for name 203 final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 204 "local-message", accountId, mailboxId, false, true, mProviderContext); 205 final Message legacyMessage = prepareLegacyMessageWithAttachments(2, false); 206 convertAndCheckcheckAddedAttachments(localMessage, legacyMessage); 207 208 // test 2: legacy message using content-disposition:filename style for name 209 final EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage( 210 "local-message", accountId, mailboxId, false, true, mProviderContext); 211 final Message legacyMessage2 = prepareLegacyMessageWithAttachments(2, true); 212 convertAndCheckcheckAddedAttachments(localMessage2, legacyMessage2); 213 } 214 215 /** 216 * Helper for testAddAttachments 217 */ 218 private void convertAndCheckcheckAddedAttachments(final EmailContent.Message localMessage, 219 final Message legacyMessage) throws MessagingException, IOException { 220 // Now, convert from legacy to provider and see what happens 221 ArrayList<Part> viewables = new ArrayList<Part>(); 222 ArrayList<Part> attachments = new ArrayList<Part>(); 223 MimeUtility.collectParts(legacyMessage, viewables, attachments); 224 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments); 225 226 // Read back all attachments for message and check field values 227 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 228 Cursor c = mProviderContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION, 229 null, null, null); 230 try { 231 assertEquals(2, c.getCount()); 232 while (c.moveToNext()) { 233 Attachment attachment = Attachment.getContent(c, Attachment.class); 234 if ("100".equals(attachment.mLocation)) { 235 checkAttachment("attachment1Part", attachments.get(0), attachment, 236 localMessage.mAccountKey); 237 } else if ("101".equals(attachment.mLocation)) { 238 checkAttachment("attachment2Part", attachments.get(1), attachment, 239 localMessage.mAccountKey); 240 } else { 241 fail("Unexpected attachment with location " + attachment.mLocation); 242 } 243 } 244 } finally { 245 c.close(); 246 } 247 } 248 249 /** 250 * Test that only "attachment" or "inline" attachments are captured and added. 251 * @throws MessagingException 252 * @throws IOException 253 */ 254 public void testAttachmentDispositions() throws MessagingException, IOException { 255 // Prepare a local message to add the attachments to 256 final long accountId = 1; 257 final long mailboxId = 1; 258 259 // Prepare the three attachments we want to test 260 BodyPart[] sourceAttachments = new BodyPart[3]; 261 BodyPart attachmentPart; 262 263 // 1. Standard attachment 264 attachmentPart = MessageTestUtils.bodyPart("image/jpg", null); 265 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg"); 266 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 267 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, 268 "attachment;\n filename=\"file-1\";\n size=100"); 269 attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "100"); 270 sourceAttachments[0] = attachmentPart; 271 272 // 2. Inline attachment 273 attachmentPart = MessageTestUtils.bodyPart("image/gif", null); 274 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/gif"); 275 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 276 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, 277 "inline;\n filename=\"file-2\";\n size=200"); 278 attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "101"); 279 sourceAttachments[1] = attachmentPart; 280 281 // 3. Neither (use VCALENDAR) 282 attachmentPart = MessageTestUtils.bodyPart("text/calendar", null); 283 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, 284 "text/calendar; charset=UTF-8; method=REQUEST"); 285 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "7bit"); 286 attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "102"); 287 sourceAttachments[2] = attachmentPart; 288 289 // Prepare local message (destination) and legacy message w/attachments (source) 290 final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 291 "local-message", accountId, mailboxId, false, true, mProviderContext); 292 final Message legacyMessage = prepareLegacyMessageWithAttachments(sourceAttachments); 293 convertAndCheckcheckAddedAttachments(localMessage, legacyMessage); 294 295 // Run the conversion and check for the converted attachments - this test asserts 296 // that there are two attachments numbered 100 & 101 (so will fail if it finds 102) 297 convertAndCheckcheckAddedAttachments(localMessage, legacyMessage); 298 } 299 300 /** 301 * Test that attachments aren't re-added in the DB. This supports the "partial download" 302 * nature of POP messages. 303 */ 304 public void testAddDuplicateAttachments() throws MessagingException, IOException { 305 // Prepare a local message to add the attachments to 306 final long accountId = 1; 307 final long mailboxId = 1; 308 final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 309 "local-message", accountId, mailboxId, false, true, mProviderContext); 310 311 // Prepare a legacy message with attachments 312 Message legacyMessage = prepareLegacyMessageWithAttachments(2, false); 313 314 // Now, convert from legacy to provider and see what happens 315 ArrayList<Part> viewables = new ArrayList<Part>(); 316 ArrayList<Part> attachments = new ArrayList<Part>(); 317 MimeUtility.collectParts(legacyMessage, viewables, attachments); 318 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments); 319 320 // Confirm two attachment objects created 321 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 322 assertEquals(2, EmailContent.count(mProviderContext, uri, null, null)); 323 324 // Now add the attachments again and confirm there are still only two 325 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments); 326 assertEquals(2, EmailContent.count(mProviderContext, uri, null, null)); 327 328 // Now add a 3rd & 4th attachment and make sure the total is 4, not 2 or 6 329 legacyMessage = prepareLegacyMessageWithAttachments(4, false); 330 viewables = new ArrayList<Part>(); 331 attachments = new ArrayList<Part>(); 332 MimeUtility.collectParts(legacyMessage, viewables, attachments); 333 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments); 334 assertEquals(4, EmailContent.count(mProviderContext, uri, null, null)); 335 } 336 337 /** 338 * Prepare a legacy message with 1+ attachments 339 * @param numAttachments how many attachments to add 340 * @param filenameInDisposition False: attachment names are sent as content-type:name. True: 341 * attachment names are sent as content-disposition:filename. 342 */ 343 private Message prepareLegacyMessageWithAttachments(int numAttachments, 344 boolean filenameInDisposition) throws MessagingException { 345 BodyPart[] attachmentParts = new BodyPart[numAttachments]; 346 for (int i = 0; i < numAttachments; ++i) { 347 // construct parameter parts for content-type:name or content-disposition:filename. 348 String name = ""; 349 String filename = ""; 350 String quotedName = "\"test-attachment-" + i + "\""; 351 if (filenameInDisposition) { 352 filename = ";\n filename=" + quotedName; 353 } else { 354 name = ";\n name=" + quotedName; 355 } 356 357 // generate an attachment that came from a server 358 BodyPart attachmentPart = MessageTestUtils.bodyPart("image/jpg", null); 359 360 // name=attachmentN size=N00 location=10N 361 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg" + name); 362 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 363 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, 364 "attachment" + filename + ";\n size=" + (i+1) + "00"); 365 attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "10" + i); 366 367 attachmentParts[i] = attachmentPart; 368 } 369 370 return prepareLegacyMessageWithAttachments(attachmentParts); 371 } 372 373 /** 374 * Prepare a legacy message with 1+ attachments 375 * @param attachments array containing one or more attachments 376 */ 377 private Message prepareLegacyMessageWithAttachments(BodyPart[] attachments) 378 throws MessagingException { 379 // Build the multipart that holds the attachments 380 MultipartBuilder mpBuilder = new MultipartBuilder("multipart/mixed"); 381 for (int i = 0; i < attachments.length; ++i) { 382 mpBuilder.addBodyPart(attachments[i]); 383 } 384 385 // Now build a message with them 386 final Message legacyMessage = new MessageBuilder() 387 .setBody(new MultipartBuilder("multipart/mixed") 388 .addBodyPart(MessageTestUtils.bodyPart("text/html", null)) 389 .addBodyPart(mpBuilder.buildBodyPart()) 390 .build()) 391 .build(); 392 393 return legacyMessage; 394 } 395 396 /** 397 * Test the stringInequal helper 398 */ 399 public void testStringInequal() { 400 // Pairs that are "equal" 401 assertFalse(LegacyConversions.stringNotEqual(null, null)); 402 assertFalse(LegacyConversions.stringNotEqual(null, "")); 403 assertFalse(LegacyConversions.stringNotEqual("", null)); 404 assertFalse(LegacyConversions.stringNotEqual("", "")); 405 assertFalse(LegacyConversions.stringNotEqual("string-equal", "string-equal")); 406 // Pairs that are "inequal" 407 assertTrue(LegacyConversions.stringNotEqual(null, "string-inequal")); 408 assertTrue(LegacyConversions.stringNotEqual("", "string-inequal")); 409 assertTrue(LegacyConversions.stringNotEqual("string-inequal", null)); 410 assertTrue(LegacyConversions.stringNotEqual("string-inequal", "")); 411 assertTrue(LegacyConversions.stringNotEqual("string-inequal-a", "string-inequal-b")); 412 } 413 414 /** 415 * Compare attachment that was converted from Part (expected) to Provider Attachment (actual) 416 * 417 * TODO content URI should only be set if we also saved a file 418 * TODO other data encodings 419 */ 420 private void checkAttachment(String tag, Part expected, EmailContent.Attachment actual, 421 long accountKey) throws MessagingException { 422 String contentType = MimeUtility.unfoldAndDecode(expected.getContentType()); 423 String contentTypeName = MimeUtility.getHeaderParameter(contentType, "name"); 424 assertEquals(tag, expected.getMimeType(), actual.mMimeType); 425 String disposition = expected.getDisposition(); 426 String sizeString = MimeUtility.getHeaderParameter(disposition, "size"); 427 String dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename"); 428 long expectedSize = (sizeString != null) ? Long.parseLong(sizeString) : 0; 429 assertEquals(tag, expectedSize, actual.mSize); 430 assertEquals(tag, expected.getContentId(), actual.mContentId); 431 432 // filename is either content-type:name or content-disposition:filename 433 String expectedName = (contentTypeName != null) ? contentTypeName : dispositionFilename; 434 assertEquals(tag, expectedName, actual.mFileName); 435 436 // content URI should be null 437 assertNull(tag, actual.getContentUri()); 438 439 assertTrue(tag, 0 != actual.mMessageKey); 440 441 // location is either both null or both matching 442 String expectedPartId = null; 443 String[] storeData = expected.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); 444 if (storeData != null && storeData.length > 0) { 445 expectedPartId = storeData[0]; 446 } 447 assertEquals(tag, expectedPartId, actual.mLocation); 448 assertEquals(tag, "B", actual.mEncoding); 449 assertEquals(tag, accountKey, actual.mAccountKey); 450 } 451 452 /** 453 * TODO: Sunny day test of adding attachments from a POP message. 454 */ 455 456 /** 457 * Sunny day tests of converting an original message to a legacy message 458 */ 459 public void testMakeLegacyMessage() throws MessagingException { 460 // Set up and store a message in the provider 461 long account1Id = 1; 462 long mailbox1Id = 1; 463 464 // Test message 1: No body 465 EmailContent.Message localMessage1 = ProviderTestUtils.setupMessage("make-legacy", 466 account1Id, mailbox1Id, false, true, mProviderContext); 467 Message getMessage1 = LegacyConversions.makeMessage(mProviderContext, localMessage1); 468 checkLegacyMessage("no body", localMessage1, getMessage1); 469 470 // Test message 2: Simple body 471 EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage("make-legacy", 472 account1Id, mailbox1Id, true, false, mProviderContext); 473 localMessage2.mTextReply = null; 474 localMessage2.mHtmlReply = null; 475 localMessage2.mIntroText = null; 476 localMessage2.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 477 localMessage2.save(mProviderContext); 478 Message getMessage2 = LegacyConversions.makeMessage(mProviderContext, localMessage2); 479 checkLegacyMessage("simple body", localMessage2, getMessage2); 480 481 // Test message 3: Body + replied-to text 482 EmailContent.Message localMessage3 = ProviderTestUtils.setupMessage("make-legacy", 483 account1Id, mailbox1Id, true, false, mProviderContext); 484 localMessage3.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 485 localMessage3.mFlags |= EmailContent.Message.FLAG_TYPE_REPLY; 486 localMessage3.save(mProviderContext); 487 Message getMessage3 = LegacyConversions.makeMessage(mProviderContext, localMessage3); 488 checkLegacyMessage("reply-to", localMessage3, getMessage3); 489 490 // Test message 4: Body + forwarded text 491 EmailContent.Message localMessage4 = ProviderTestUtils.setupMessage("make-legacy", 492 account1Id, mailbox1Id, true, false, mProviderContext); 493 localMessage4.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 494 localMessage4.mFlags |= EmailContent.Message.FLAG_TYPE_FORWARD; 495 localMessage4.save(mProviderContext); 496 Message getMessage4 = LegacyConversions.makeMessage(mProviderContext, localMessage4); 497 checkLegacyMessage("forwarding", localMessage4, getMessage4); 498 } 499 500 /** 501 * Check equality of a pair of converted messages 502 */ 503 private void checkProviderMessage(String tag, Message expect, EmailContent.Message actual) 504 throws MessagingException { 505 assertEquals(tag, expect.getUid(), actual.mServerId); 506 assertEquals(tag, expect.getSubject(), actual.mSubject); 507 assertEquals(tag, Address.pack(expect.getFrom()), actual.mFrom); 508 assertEquals(tag, expect.getSentDate().getTime(), actual.mTimeStamp); 509 assertEquals(tag, Address.pack(expect.getRecipients(RecipientType.TO)), actual.mTo); 510 assertEquals(tag, Address.pack(expect.getRecipients(RecipientType.CC)), actual.mCc); 511 assertEquals(tag, ((MimeMessage)expect).getMessageId(), actual.mMessageId); 512 assertEquals(tag, expect.isSet(Flag.SEEN), actual.mFlagRead); 513 assertEquals(tag, expect.isSet(Flag.FLAGGED), actual.mFlagFavorite); 514 } 515 516 /** 517 * Check equality of a pair of converted messages 518 */ 519 private void checkLegacyMessage(String tag, EmailContent.Message expect, Message actual) 520 throws MessagingException { 521 assertEquals(tag, expect.mServerId, actual.getUid()); 522 assertEquals(tag, expect.mServerTimeStamp, actual.getInternalDate().getTime()); 523 assertEquals(tag, expect.mSubject, actual.getSubject()); 524 assertEquals(tag, expect.mFrom, Address.pack(actual.getFrom())); 525 assertEquals(tag, expect.mTimeStamp, actual.getSentDate().getTime()); 526 assertEquals(tag, expect.mTo, Address.pack(actual.getRecipients(RecipientType.TO))); 527 assertEquals(tag, expect.mCc, Address.pack(actual.getRecipients(RecipientType.CC))); 528 assertEquals(tag, expect.mBcc, Address.pack(actual.getRecipients(RecipientType.BCC))); 529 assertEquals(tag, expect.mReplyTo, Address.pack(actual.getReplyTo())); 530 assertEquals(tag, expect.mMessageId, ((MimeMessage)actual).getMessageId()); 531 // check flags 532 assertEquals(tag, expect.mFlagRead, actual.isSet(Flag.SEEN)); 533 assertEquals(tag, expect.mFlagFavorite, actual.isSet(Flag.FLAGGED)); 534 535 // Check the body of the message 536 ArrayList<Part> viewables = new ArrayList<Part>(); 537 ArrayList<Part> attachments = new ArrayList<Part>(); 538 MimeUtility.collectParts(actual, viewables, attachments); 539 String get1Text = null; 540 String get1Html = null; 541 String get1TextReply = null; 542 String get1HtmlReply = null; 543 String get1TextIntro = null; 544 for (Part viewable : viewables) { 545 String text = MimeUtility.getTextFromPart(viewable); 546 boolean isHtml = viewable.getMimeType().equalsIgnoreCase("text/html"); 547 String[] headers = viewable.getHeader(MimeHeader.HEADER_ANDROID_BODY_QUOTED_PART); 548 if (headers != null) { 549 String header = headers[0]; 550 boolean isReply = LegacyConversions.BODY_QUOTED_PART_REPLY.equalsIgnoreCase(header); 551 boolean isFwd = LegacyConversions.BODY_QUOTED_PART_FORWARD.equalsIgnoreCase(header); 552 boolean isIntro = LegacyConversions.BODY_QUOTED_PART_INTRO.equalsIgnoreCase(header); 553 if (isReply || isFwd) { 554 if (isHtml) { 555 get1HtmlReply = text; 556 } else { 557 get1TextReply = text; 558 } 559 } else if (isIntro) { 560 get1TextIntro = text; 561 } 562 // Check flags 563 int replyTypeFlags = expect.mFlags & EmailContent.Message.FLAG_TYPE_MASK; 564 if (isReply) { 565 assertEquals(tag, EmailContent.Message.FLAG_TYPE_REPLY, replyTypeFlags); 566 } 567 if (isFwd) { 568 assertEquals(tag, EmailContent.Message.FLAG_TYPE_FORWARD, replyTypeFlags); 569 } 570 } else { 571 if (isHtml) { 572 get1Html = text; 573 } else { 574 get1Text = text; 575 } 576 } 577 } 578 assertEquals(tag, expect.mText, get1Text); 579 assertEquals(tag, expect.mHtml, get1Html); 580 assertEquals(tag, expect.mTextReply, get1TextReply); 581 assertEquals(tag, expect.mHtmlReply, get1HtmlReply); 582 assertEquals(tag, expect.mIntroText, get1TextIntro); 583 584 // TODO Check the attachments 585 586 // cv.put("attachment_count", attachments.size()); 587 } 588 } 589