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