LegacyConversionsTests.java revision 75a873be8420e50f0aeb5a77716358ee0ca66b01
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.Body; 21import com.android.email.mail.BodyPart; 22import com.android.email.mail.Flag; 23import com.android.email.mail.Folder; 24import com.android.email.mail.Folder.OpenMode; 25import com.android.email.mail.Message; 26import com.android.email.mail.Message.RecipientType; 27import com.android.email.mail.MessageTestUtils; 28import com.android.email.mail.MessageTestUtils.MessageBuilder; 29import com.android.email.mail.MessageTestUtils.MultipartBuilder; 30import com.android.email.mail.MessagingException; 31import com.android.email.mail.Part; 32import com.android.email.mail.internet.MimeBodyPart; 33import com.android.email.mail.internet.MimeHeader; 34import com.android.email.mail.internet.MimeMessage; 35import com.android.email.mail.internet.MimeUtility; 36import com.android.email.mail.internet.TextBody; 37import com.android.email.mail.store.LocalStore; 38import com.android.email.mail.store.LocalStoreUnitTests; 39import com.android.email.provider.EmailContent; 40import com.android.email.provider.EmailContent.Attachment; 41import com.android.email.provider.EmailContent.Mailbox; 42import com.android.email.provider.EmailProvider; 43import com.android.email.provider.ProviderTestUtils; 44 45import android.content.ContentUris; 46import android.content.Context; 47import android.database.Cursor; 48import android.net.Uri; 49import android.test.ProviderTestCase2; 50 51import java.io.IOException; 52import java.util.ArrayList; 53import java.util.Date; 54 55/** 56 * Tests of the Legacy Conversions code (used by MessagingController). 57 * 58 * NOTE: It would probably make sense to rewrite this using a MockProvider, instead of the 59 * ProviderTestCase (which is a real provider running on a temp database). This would be more of 60 * a true "unit test". 61 * 62 * You can run this entire test case with: 63 * runtest -c com.android.email.LegacyConversionsTests email 64 */ 65public class LegacyConversionsTests extends ProviderTestCase2<EmailProvider> { 66 67 private static final String UID = "UID.12345678"; 68 private static final String SENDER = "sender@android.com"; 69 private static final String RECIPIENT_TO = "recipient-to@android.com"; 70 private static final String RECIPIENT_CC = "recipient-cc@android.com"; 71 private static final String RECIPIENT_BCC = "recipient-bcc@android.com"; 72 private static final String REPLY_TO = "reply-to@android.com"; 73 private static final String SUBJECT = "This is the subject"; 74 private static final String MESSAGE_ID = "Test-Message-ID"; 75 private static final String MESSAGE_ID_2 = "Test-Message-ID-Second"; 76 77 EmailProvider mProvider; 78 Context mProviderContext; 79 Context mContext; 80 Account mLegacyAccount = null; 81 Preferences mPreferences = null; 82 83 public LegacyConversionsTests() { 84 super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY); 85 } 86 87 @Override 88 public void setUp() throws Exception { 89 super.setUp(); 90 mProviderContext = getMockContext(); 91 mContext = getContext(); 92 } 93 94 @Override 95 public void tearDown() throws Exception { 96 super.tearDown(); 97 if (mLegacyAccount != null) { 98 mLegacyAccount.delete(mPreferences); 99 } 100 } 101 102 /** 103 * TODO: basic Legacy -> Provider Message conversions 104 * TODO: basic Legacy -> Provider Body conversions 105 * TODO: rainy day tests of all kinds 106 */ 107 108 /** 109 * Test basic conversion from Store message to Provider message 110 * 111 * TODO: Not a complete test of all fields, and some fields need special tests (e.g. flags) 112 * TODO: There are many special cases in the tested function, that need to be 113 * tested here as well. 114 */ 115 public void testUpdateMessageFields() 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 boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1); 121 assertTrue(result); 122 checkProviderMessage("testUpdateMessageFields", message, localMessage); 123 } 124 125 /** 126 * Test basic conversion from Store message to Provider message, when the provider message 127 * does not have a proper message-id. 128 */ 129 public void testUpdateMessageFieldsNoMessageId() throws MessagingException { 130 MimeMessage message = buildTestMessage(RECIPIENT_TO, RECIPIENT_CC, RECIPIENT_BCC, 131 REPLY_TO, SENDER, SUBJECT, null); 132 EmailContent.Message localMessage = new EmailContent.Message(); 133 134 // If the source message-id is null, the target should be left as-is 135 localMessage.mMessageId = MESSAGE_ID_2; 136 message.removeHeader("Message-ID"); 137 138 boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1); 139 assertTrue(result); 140 assertEquals(MESSAGE_ID_2, localMessage.mMessageId); 141 } 142 143 /** 144 * Build a lightweight Store message with simple field population 145 */ 146 private MimeMessage buildTestMessage(String to, String cc, String bcc, String replyTo, 147 String sender, String subject, String content) throws MessagingException { 148 MimeMessage message = new MimeMessage(); 149 150 if (to != null) { 151 Address[] addresses = Address.parse(to); 152 message.setRecipients(RecipientType.TO, addresses); 153 } 154 if (cc != null) { 155 Address[] addresses = Address.parse(cc); 156 message.setRecipients(RecipientType.CC, addresses); 157 } 158 if (bcc != null) { 159 Address[] addresses = Address.parse(bcc); 160 message.setRecipients(RecipientType.BCC, addresses); 161 } 162 if (replyTo != null) { 163 Address[] addresses = Address.parse(replyTo); 164 message.setReplyTo(addresses); 165 } 166 if (sender != null) { 167 Address[] addresses = Address.parse(sender); 168 message.setFrom(addresses[0]); 169 } 170 if (subject != null) { 171 message.setSubject(subject); 172 } 173 if (content != null) { 174 TextBody body = new TextBody(content); 175 message.setBody(body); 176 } 177 178 message.setUid(UID); 179 message.setSentDate(new Date()); 180 message.setInternalDate(new Date()); 181 message.setMessageId(MESSAGE_ID); 182 return message; 183 } 184 185 /** 186 * Basic test of body parts conversion from Store message to Provider message. 187 * This tests that a null body part simply results in null text, and does not crash 188 * or return "null". 189 * 190 * TODO very incomplete, there are many permutations to be explored 191 */ 192 public void testUpdateBodyFieldsNullText() throws MessagingException { 193 EmailContent.Body localBody = new EmailContent.Body(); 194 EmailContent.Message localMessage = new EmailContent.Message(); 195 ArrayList<Part> viewables = new ArrayList<Part>(); 196 Part emptyTextPart = new MimeBodyPart(null, "text/plain"); 197 viewables.add(emptyTextPart); 198 199 // a "null" body part of type text/plain should result in a null mTextContent 200 boolean result = LegacyConversions.updateBodyFields(localBody, localMessage, viewables); 201 assertTrue(result); 202 assertNull(localBody.mTextContent); 203 } 204 205 /** 206 * Sunny day test of adding attachments from an IMAP/POP message. 207 */ 208 public void testAddAttachments() throws MessagingException, IOException { 209 // Prepare a local message to add the attachments to 210 final long accountId = 1; 211 final long mailboxId = 1; 212 213 // test 1: legacy message using content-type:name style for name 214 final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 215 "local-message", accountId, mailboxId, false, true, mProviderContext); 216 final Message legacyMessage = prepareLegacyMessageWithAttachments(2, false, false); 217 convertAndCheckcheckAddedAttachments(localMessage, legacyMessage); 218 219 // test 2: legacy message using content-disposition:filename style for name 220 final EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage( 221 "local-message", accountId, mailboxId, false, true, mProviderContext); 222 final Message legacyMessage2 = prepareLegacyMessageWithAttachments(2, false, true); 223 convertAndCheckcheckAddedAttachments(localMessage2, legacyMessage2); 224 } 225 226 /** 227 * Helper for testAddAttachments 228 */ 229 private void convertAndCheckcheckAddedAttachments(final EmailContent.Message localMessage, 230 final Message legacyMessage) throws MessagingException, IOException { 231 // Now, convert from legacy to provider and see what happens 232 ArrayList<Part> viewables = new ArrayList<Part>(); 233 ArrayList<Part> attachments = new ArrayList<Part>(); 234 MimeUtility.collectParts(legacyMessage, viewables, attachments); 235 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, false); 236 237 // Read back all attachments for message and check field values 238 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 239 Cursor c = mProviderContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION, 240 null, null, null); 241 try { 242 assertEquals(2, c.getCount()); 243 while (c.moveToNext()) { 244 Attachment attachment = Attachment.getContent(c, Attachment.class); 245 if ("101".equals(attachment.mLocation)) { 246 checkAttachment("attachment1Part", attachments.get(0), attachment, 247 localMessage.mAccountKey); 248 } else if ("102".equals(attachment.mLocation)) { 249 checkAttachment("attachment2Part", attachments.get(1), attachment, 250 localMessage.mAccountKey); 251 } else { 252 fail("Unexpected attachment with location " + attachment.mLocation); 253 } 254 } 255 } finally { 256 c.close(); 257 } 258 } 259 260 /** 261 * Test that attachments aren't re-added in the DB. This supports the "partial download" 262 * nature of POP messages. 263 */ 264 public void testAddDuplicateAttachments() throws MessagingException, IOException { 265 // Prepare a local message to add the attachments to 266 final long accountId = 1; 267 final long mailboxId = 1; 268 final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 269 "local-message", accountId, mailboxId, false, true, mProviderContext); 270 271 // Prepare a legacy message with attachments 272 Message legacyMessage = prepareLegacyMessageWithAttachments(2, false, false); 273 274 // Now, convert from legacy to provider and see what happens 275 ArrayList<Part> viewables = new ArrayList<Part>(); 276 ArrayList<Part> attachments = new ArrayList<Part>(); 277 MimeUtility.collectParts(legacyMessage, viewables, attachments); 278 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, false); 279 280 // Confirm two attachment objects created 281 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 282 assertEquals(2, EmailContent.count(mProviderContext, uri, null, null)); 283 284 // Now add the attachments again and confirm there are still only two 285 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, false); 286 assertEquals(2, EmailContent.count(mProviderContext, uri, null, null)); 287 288 // Now add a 3rd & 4th attachment and make sure the total is 4, not 2 or 6 289 legacyMessage = prepareLegacyMessageWithAttachments(4, false, false); 290 viewables = new ArrayList<Part>(); 291 attachments = new ArrayList<Part>(); 292 MimeUtility.collectParts(legacyMessage, viewables, attachments); 293 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, false); 294 assertEquals(4, EmailContent.count(mProviderContext, uri, null, null)); 295 } 296 297 /** 298 * Sunny day test of adding attachments in "local account upgrade" mode 299 */ 300 public void testLocalUpgradeAttachments() throws MessagingException, IOException { 301 // Prepare a local message to add the attachments to 302 final long accountId = 1; 303 final long mailboxId = 1; 304 final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 305 "local-upgrade", accountId, mailboxId, false, true, mProviderContext); 306 307 // Prepare a legacy message with attachments 308 final Message legacyMessage = prepareLegacyMessageWithAttachments(2, true, false); 309 310 // Now, convert from legacy to provider and see what happens 311 ArrayList<Part> viewables = new ArrayList<Part>(); 312 ArrayList<Part> attachments = new ArrayList<Part>(); 313 MimeUtility.collectParts(legacyMessage, viewables, attachments); 314 LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments, true); 315 316 // Read back all attachments for message and check field values 317 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 318 Cursor c = mProviderContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION, 319 null, null, null); 320 try { 321 assertEquals(2, c.getCount()); 322 while (c.moveToNext()) { 323 Attachment attachment = Attachment.getContent(c, Attachment.class); 324 // This attachment should look as if created by modern (provider) MessageCompose. 325 // 1. find the original that it was created from 326 Part fromPart = null; 327 for (Part from : attachments) { 328 String contentType = MimeUtility.unfoldAndDecode(from.getContentType()); 329 String name = MimeUtility.getHeaderParameter(contentType, "name"); 330 if (name.equals(attachment.mFileName)) { 331 fromPart = from; 332 break; 333 } 334 } 335 assertTrue(fromPart != null); 336 // 2. Check values 337 checkAttachment(attachment.mFileName, fromPart, attachment, accountId); 338 } 339 } finally { 340 c.close(); 341 } 342 } 343 344 /** 345 * Prepare a legacy message with 1+ attachments 346 * @param numAttachments how many attachments to add 347 * @param localData if true, attachments are "local" data. false = "remote" (from server) 348 * @param filenameInDisposition False: attachment names are sent as content-type:name. True: 349 * attachment names are sent as content-disposition:filename. 350 */ 351 private Message prepareLegacyMessageWithAttachments(int numAttachments, boolean localData, 352 boolean filenameInDisposition) throws MessagingException { 353 // First, build one or more attachment parts 354 MultipartBuilder mpBuilder = new MultipartBuilder("multipart/mixed"); 355 for (int i = 1; i <= numAttachments; ++i) { 356 // construct parameter parts for content-type:name or content-disposition:filename. 357 String name = ""; 358 String filename = ""; 359 String quotedName = "\"test-attachment-" + i + "\""; 360 if (filenameInDisposition) { 361 filename = ";\n filename=" + quotedName; 362 } else { 363 name = ";\n name=" + quotedName; 364 } 365 if (localData) { 366 // generate an attachment that was generated by legacy code (e.g. donut) 367 // for test of upgrading accounts in place 368 // This creator models the code in legacy MessageCompose 369 Uri uri = Uri.parse("content://test/attachment/" + i); 370 MimeBodyPart bp = new MimeBodyPart( 371 new LocalStore.LocalAttachmentBody(uri, mProviderContext)); 372 bp.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg" + name); 373 bp.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 374 bp.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "attachment" + filename); 375 mpBuilder.addBodyPart(bp); 376 } else { 377 // generate an attachment that came from a server 378 BodyPart attachmentPart = MessageTestUtils.bodyPart("image/jpg", null); 379 380 // name=attachmentN size=N00 location=10N 381 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg" + name); 382 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 383 attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, 384 "attachment" + filename + ";\n size=" + i + "00"); 385 attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "10" + i); 386 387 mpBuilder.addBodyPart(attachmentPart); 388 } 389 } 390 391 // Now build a message with them 392 final Message legacyMessage = new MessageBuilder() 393 .setBody(new MultipartBuilder("multipart/mixed") 394 .addBodyPart(MessageTestUtils.bodyPart("text/html", null)) 395 .addBodyPart(mpBuilder.buildBodyPart()) 396 .build()) 397 .build(); 398 399 return legacyMessage; 400 } 401 402 /** 403 * Test the stringInequal helper 404 */ 405 public void testStringInequal() { 406 // Pairs that are "equal" 407 assertFalse(LegacyConversions.stringNotEqual(null, null)); 408 assertFalse(LegacyConversions.stringNotEqual(null, "")); 409 assertFalse(LegacyConversions.stringNotEqual("", null)); 410 assertFalse(LegacyConversions.stringNotEqual("", "")); 411 assertFalse(LegacyConversions.stringNotEqual("string-equal", "string-equal")); 412 // Pairs that are "inequal" 413 assertTrue(LegacyConversions.stringNotEqual(null, "string-inequal")); 414 assertTrue(LegacyConversions.stringNotEqual("", "string-inequal")); 415 assertTrue(LegacyConversions.stringNotEqual("string-inequal", null)); 416 assertTrue(LegacyConversions.stringNotEqual("string-inequal", "")); 417 assertTrue(LegacyConversions.stringNotEqual("string-inequal-a", "string-inequal-b")); 418 } 419 420 /** 421 * Compare attachment that was converted from Part (expected) to Provider Attachment (actual) 422 * 423 * TODO content URI should only be set if we also saved a file 424 * TODO other data encodings 425 */ 426 private void checkAttachment(String tag, Part expected, EmailContent.Attachment actual, 427 long accountKey) throws MessagingException { 428 String contentType = MimeUtility.unfoldAndDecode(expected.getContentType()); 429 String contentTypeName = MimeUtility.getHeaderParameter(contentType, "name"); 430 assertEquals(tag, expected.getMimeType(), actual.mMimeType); 431 String disposition = expected.getDisposition(); 432 String sizeString = MimeUtility.getHeaderParameter(disposition, "size"); 433 String dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename"); 434 long expectedSize = (sizeString != null) ? Long.parseLong(sizeString) : 0; 435 assertEquals(tag, expectedSize, actual.mSize); 436 assertEquals(tag, expected.getContentId(), actual.mContentId); 437 438 // filename is either content-type:name or content-disposition:filename 439 String expectedName = (contentTypeName != null) ? contentTypeName : dispositionFilename; 440 assertEquals(tag, expectedName, actual.mFileName); 441 442 // content URI either both null or both matching 443 String expectedUriString = null; 444 Body body = expected.getBody(); 445 if (body instanceof LocalStore.LocalAttachmentBody) { 446 LocalStore.LocalAttachmentBody localBody = (LocalStore.LocalAttachmentBody) body; 447 Uri contentUri = localBody.getContentUri(); 448 if (contentUri != null) { 449 expectedUriString = contentUri.toString(); 450 } 451 } 452 assertEquals(tag, expectedUriString, actual.mContentUri); 453 454 assertTrue(tag, 0 != actual.mMessageKey); 455 456 // location is either both null or both matching 457 String expectedPartId = null; 458 String[] storeData = expected.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); 459 if (storeData != null && storeData.length > 0) { 460 expectedPartId = storeData[0]; 461 } 462 assertEquals(tag, expectedPartId, actual.mLocation); 463 assertEquals(tag, "B", actual.mEncoding); 464 assertEquals(tag, accountKey, actual.mAccountKey); 465 } 466 467 /** 468 * TODO: Sunny day test of adding attachments from a POP message. 469 */ 470 471 /** 472 * Sunny day tests of converting an original message to a legacy message 473 */ 474 public void testMakeLegacyMessage() throws MessagingException { 475 // Set up and store a message in the provider 476 long account1Id = 1; 477 long mailbox1Id = 1; 478 479 // Test message 1: No body 480 EmailContent.Message localMessage1 = ProviderTestUtils.setupMessage("make-legacy", 481 account1Id, mailbox1Id, false, true, mProviderContext); 482 Message getMessage1 = LegacyConversions.makeMessage(mProviderContext, localMessage1); 483 checkLegacyMessage("no body", localMessage1, getMessage1); 484 485 // Test message 2: Simple body 486 EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage("make-legacy", 487 account1Id, mailbox1Id, true, false, mProviderContext); 488 localMessage2.mTextReply = null; 489 localMessage2.mHtmlReply = null; 490 localMessage2.mIntroText = null; 491 localMessage2.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 492 localMessage2.save(mProviderContext); 493 Message getMessage2 = LegacyConversions.makeMessage(mProviderContext, localMessage2); 494 checkLegacyMessage("simple body", localMessage2, getMessage2); 495 496 // Test message 3: Body + replied-to text 497 EmailContent.Message localMessage3 = ProviderTestUtils.setupMessage("make-legacy", 498 account1Id, mailbox1Id, true, false, mProviderContext); 499 localMessage3.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 500 localMessage3.mFlags |= EmailContent.Message.FLAG_TYPE_REPLY; 501 localMessage3.save(mProviderContext); 502 Message getMessage3 = LegacyConversions.makeMessage(mProviderContext, localMessage3); 503 checkLegacyMessage("reply-to", localMessage3, getMessage3); 504 505 // Test message 4: Body + forwarded text 506 EmailContent.Message localMessage4 = ProviderTestUtils.setupMessage("make-legacy", 507 account1Id, mailbox1Id, true, false, mProviderContext); 508 localMessage4.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 509 localMessage4.mFlags |= EmailContent.Message.FLAG_TYPE_FORWARD; 510 localMessage4.save(mProviderContext); 511 Message getMessage4 = LegacyConversions.makeMessage(mProviderContext, localMessage4); 512 checkLegacyMessage("forwarding", localMessage4, getMessage4); 513 } 514 515 /** 516 * Check equality of a pair of converted messages 517 */ 518 private void checkProviderMessage(String tag, Message expect, EmailContent.Message actual) 519 throws MessagingException { 520 assertEquals(tag, expect.getUid(), actual.mServerId); 521 assertEquals(tag, expect.getSubject(), actual.mSubject); 522 assertEquals(tag, Address.pack(expect.getFrom()), actual.mFrom); 523 assertEquals(tag, expect.getSentDate().getTime(), actual.mTimeStamp); 524 assertEquals(tag, Address.pack(expect.getRecipients(RecipientType.TO)), actual.mTo); 525 assertEquals(tag, Address.pack(expect.getRecipients(RecipientType.CC)), actual.mCc); 526 assertEquals(tag, ((MimeMessage)expect).getMessageId(), actual.mMessageId); 527 assertEquals(tag, expect.isSet(Flag.SEEN), actual.mFlagRead); 528 assertEquals(tag, expect.isSet(Flag.FLAGGED), actual.mFlagFavorite); 529 } 530 531 /** 532 * Check equality of a pair of converted messages 533 */ 534 private void checkLegacyMessage(String tag, EmailContent.Message expect, Message actual) 535 throws MessagingException { 536 assertEquals(tag, expect.mServerId, actual.getUid()); 537 assertEquals(tag, expect.mServerTimeStamp, actual.getInternalDate().getTime()); 538 assertEquals(tag, expect.mSubject, actual.getSubject()); 539 assertEquals(tag, expect.mFrom, Address.pack(actual.getFrom())); 540 assertEquals(tag, expect.mTimeStamp, actual.getSentDate().getTime()); 541 assertEquals(tag, expect.mTo, Address.pack(actual.getRecipients(RecipientType.TO))); 542 assertEquals(tag, expect.mCc, Address.pack(actual.getRecipients(RecipientType.CC))); 543 assertEquals(tag, expect.mBcc, Address.pack(actual.getRecipients(RecipientType.BCC))); 544 assertEquals(tag, expect.mReplyTo, Address.pack(actual.getReplyTo())); 545 assertEquals(tag, expect.mMessageId, ((MimeMessage)actual).getMessageId()); 546 // check flags 547 assertEquals(tag, expect.mFlagRead, actual.isSet(Flag.SEEN)); 548 assertEquals(tag, expect.mFlagFavorite, actual.isSet(Flag.FLAGGED)); 549 550 // Check the body of the message 551 ArrayList<Part> viewables = new ArrayList<Part>(); 552 ArrayList<Part> attachments = new ArrayList<Part>(); 553 MimeUtility.collectParts(actual, viewables, attachments); 554 String get1Text = null; 555 String get1Html = null; 556 String get1TextReply = null; 557 String get1HtmlReply = null; 558 String get1TextIntro = null; 559 for (Part viewable : viewables) { 560 String text = MimeUtility.getTextFromPart(viewable); 561 boolean isHtml = viewable.getMimeType().equalsIgnoreCase("text/html"); 562 String[] headers = viewable.getHeader(MimeHeader.HEADER_ANDROID_BODY_QUOTED_PART); 563 if (headers != null) { 564 String header = headers[0]; 565 boolean isReply = LegacyConversions.BODY_QUOTED_PART_REPLY.equalsIgnoreCase(header); 566 boolean isFwd = LegacyConversions.BODY_QUOTED_PART_FORWARD.equalsIgnoreCase(header); 567 boolean isIntro = LegacyConversions.BODY_QUOTED_PART_INTRO.equalsIgnoreCase(header); 568 if (isReply || isFwd) { 569 if (isHtml) { 570 get1HtmlReply = text; 571 } else { 572 get1TextReply = text; 573 } 574 } else if (isIntro) { 575 get1TextIntro = text; 576 } 577 // Check flags 578 int replyTypeFlags = expect.mFlags & EmailContent.Message.FLAG_TYPE_MASK; 579 if (isReply) { 580 assertEquals(tag, EmailContent.Message.FLAG_TYPE_REPLY, replyTypeFlags); 581 } 582 if (isFwd) { 583 assertEquals(tag, EmailContent.Message.FLAG_TYPE_FORWARD, replyTypeFlags); 584 } 585 } else { 586 if (isHtml) { 587 get1Html = text; 588 } else { 589 get1Text = text; 590 } 591 } 592 } 593 assertEquals(tag, expect.mText, get1Text); 594 assertEquals(tag, expect.mHtml, get1Html); 595 assertEquals(tag, expect.mTextReply, get1TextReply); 596 assertEquals(tag, expect.mHtmlReply, get1HtmlReply); 597 assertEquals(tag, expect.mIntroText, get1TextIntro); 598 599 // TODO Check the attachments 600 601// cv.put("attachment_count", attachments.size()); 602 } 603 604 /** 605 * Test conversion of a legacy account to a provider account 606 */ 607 public void testMakeProviderAccount() throws MessagingException { 608 609 setupLegacyAccount("testMakeProviderAccount", true); 610 EmailContent.Account toAccount = 611 LegacyConversions.makeAccount(mProviderContext, mLegacyAccount); 612 checkProviderAccount("testMakeProviderAccount", mLegacyAccount, toAccount); 613 } 614 615 /** 616 * Test conversion of a provider account to a legacy account 617 */ 618 public void testMakeLegacyAccount() throws MessagingException { 619 EmailContent.Account fromAccount = ProviderTestUtils.setupAccount("convert-to-legacy", 620 false, mProviderContext); 621 fromAccount.mHostAuthRecv = 622 ProviderTestUtils.setupHostAuth("legacy-recv", 0, false, mProviderContext); 623 fromAccount.mHostAuthSend = 624 ProviderTestUtils.setupHostAuth("legacy-send", 0, false, mProviderContext); 625 fromAccount.save(mProviderContext); 626 627 Account toAccount = LegacyConversions.makeLegacyAccount(mProviderContext, fromAccount); 628 checkLegacyAccount("testMakeLegacyAccount", fromAccount, toAccount); 629 } 630 631 /** 632 * Setup a legacy account in mLegacyAccount with many fields prefilled. 633 */ 634 private void setupLegacyAccount(String name, boolean saveIt) { 635 // prefs & legacy account are saved for cleanup (it's stored in the real prefs file) 636 mPreferences = Preferences.getPreferences(mProviderContext); 637 mLegacyAccount = new Account(mProviderContext); 638 639 // fill in useful fields 640 mLegacyAccount.mUuid = "test-uid-" + name; 641 mLegacyAccount.mStoreUri = "store://test/" + name; 642 mLegacyAccount.mLocalStoreUri = "local://localhost/" + name; 643 mLegacyAccount.mSenderUri = "sender://test/" + name; 644 mLegacyAccount.mDescription = "description " + name; 645 mLegacyAccount.mName = "name " + name; 646 mLegacyAccount.mEmail = "email " + name; 647 mLegacyAccount.mAutomaticCheckIntervalMinutes = 100; 648 mLegacyAccount.mLastAutomaticCheckTime = 200; 649 mLegacyAccount.mNotifyNewMail = true; 650 mLegacyAccount.mDraftsFolderName = "drafts " + name; 651 mLegacyAccount.mSentFolderName = "sent " + name; 652 mLegacyAccount.mTrashFolderName = "trash " + name; 653 mLegacyAccount.mOutboxFolderName = "outbox " + name; 654 mLegacyAccount.mAccountNumber = 300; 655 mLegacyAccount.mVibrate = true; 656 mLegacyAccount.mVibrateWhenSilent = false; 657 mLegacyAccount.mRingtoneUri = "ringtone://test/" + name; 658 mLegacyAccount.mSyncWindow = 400; 659 mLegacyAccount.mBackupFlags = 0; 660 mLegacyAccount.mDeletePolicy = Account.DELETE_POLICY_NEVER; 661 mLegacyAccount.mSecurityFlags = 500; 662 mLegacyAccount.mSignature = "signature " + name; 663 664 if (saveIt) { 665 mLegacyAccount.save(mPreferences); 666 } 667 } 668 669 /** 670 * Compare a provider account to the legacy account it was created from 671 */ 672 private void checkProviderAccount(String tag, Account expect, EmailContent.Account actual) 673 throws MessagingException { 674 assertEquals(tag + " description", expect.getDescription(), actual.mDisplayName); 675 assertEquals(tag + " email", expect.getEmail(), actual.mEmailAddress); 676 assertEquals(tag + " sync key", null, actual.mSyncKey); 677 assertEquals(tag + " lookback", expect.getSyncWindow(), actual.mSyncLookback); 678 assertEquals(tag + " sync intvl", expect.getAutomaticCheckIntervalMinutes(), 679 actual.mSyncInterval); 680 // These asserts are checking mHostAuthKeyRecv & mHostAuthKeySend 681 assertEquals(tag + " store", expect.getStoreUri(), actual.getStoreUri(mProviderContext)); 682 assertEquals(tag + " sender", expect.getSenderUri(), actual.getSenderUri(mProviderContext)); 683 // Synthesize & check flags 684 int expectFlags = 0; 685 if (expect.mNotifyNewMail) expectFlags |= EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL; 686 if (expect.mVibrate) expectFlags |= EmailContent.Account.FLAGS_VIBRATE_ALWAYS; 687 if (expect.mVibrateWhenSilent) 688 expectFlags |= EmailContent.Account.FLAGS_VIBRATE_WHEN_SILENT; 689 expectFlags |= 690 (expect.mDeletePolicy << EmailContent.Account.FLAGS_DELETE_POLICY_SHIFT) 691 & EmailContent.Account.FLAGS_DELETE_POLICY_MASK; 692 assertEquals(tag + " flags", expectFlags, actual.mFlags); 693 assertEquals(tag + " default", false, actual.mIsDefault); 694 assertEquals(tag + " uuid", expect.getUuid(), actual.mCompatibilityUuid); 695 assertEquals(tag + " name", expect.getName(), actual.mSenderName); 696 assertEquals(tag + " ringtone", expect.getRingtone(), actual.mRingtoneUri); 697 assertEquals(tag + " proto vers", expect.mProtocolVersion, actual.mProtocolVersion); 698 assertEquals(tag + " new count", 0, actual.mNewMessageCount); 699 assertEquals(tag + " security", expect.mSecurityFlags, actual.mSecurityFlags); 700 assertEquals(tag + " sec sync key", null, actual.mSecuritySyncKey); 701 assertEquals(tag + " signature", expect.mSignature, actual.mSignature); 702 } 703 704 /** 705 * Compare a legacy account to the provider account it was created from 706 */ 707 private void checkLegacyAccount(String tag, EmailContent.Account expect, Account actual) 708 throws MessagingException { 709 int expectFlags = expect.getFlags(); 710 711 assertEquals(tag + " uuid", expect.mCompatibilityUuid, actual.mUuid); 712 assertEquals(tag + " store", expect.getStoreUri(mProviderContext), actual.mStoreUri); 713 assertTrue(actual.mLocalStoreUri.startsWith("local://localhost")); 714 assertEquals(tag + " sender", expect.getSenderUri(mProviderContext), actual.mSenderUri); 715 assertEquals(tag + " description", expect.getDisplayName(), actual.mDescription); 716 assertEquals(tag + " name", expect.getSenderName(), actual.mName); 717 assertEquals(tag + " email", expect.getEmailAddress(), actual.mEmail); 718 assertEquals(tag + " checkintvl", expect.getSyncInterval(), 719 actual.mAutomaticCheckIntervalMinutes); 720 assertEquals(tag + " checktime", 0, actual.mLastAutomaticCheckTime); 721 assertEquals(tag + " notify", 722 (expectFlags & EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL) != 0, 723 actual.mNotifyNewMail); 724 assertEquals(tag + " drafts", null, actual.mDraftsFolderName); 725 assertEquals(tag + " sent", null, actual.mSentFolderName); 726 assertEquals(tag + " trash", null, actual.mTrashFolderName); 727 assertEquals(tag + " outbox", null, actual.mOutboxFolderName); 728 assertEquals(tag + " acct #", -1, actual.mAccountNumber); 729 assertEquals(tag + " vibrate", 730 (expectFlags & EmailContent.Account.FLAGS_VIBRATE_ALWAYS) != 0, 731 actual.mVibrate); 732 assertEquals(tag + " vibrateSilent", 733 (expectFlags & EmailContent.Account.FLAGS_VIBRATE_WHEN_SILENT) != 0, 734 actual.mVibrateWhenSilent); 735 assertEquals(tag + " ", expect.getRingtone(), actual.mRingtoneUri); 736 assertEquals(tag + " sync window", expect.getSyncLookback(), actual.mSyncWindow); 737 assertEquals(tag + " backup flags", 0, actual.mBackupFlags); 738 assertEquals(tag + " proto vers", expect.mProtocolVersion, actual.mProtocolVersion); 739 assertEquals(tag + " delete policy", expect.getDeletePolicy(), actual.getDeletePolicy()); 740 assertEquals(tag + " security", expect.mSecurityFlags, actual.mSecurityFlags); 741 assertEquals(tag + " signature", expect.mSignature, actual.mSignature); 742 } 743 744 /** 745 * Test conversion of a legacy mailbox to a provider mailbox 746 */ 747 public void testMakeProviderMailbox() throws MessagingException { 748 EmailContent.Account toAccount = ProviderTestUtils.setupAccount("convert-mailbox", 749 true, mProviderContext); 750 Folder fromFolder = buildTestFolder("INBOX"); 751 Mailbox toMailbox = LegacyConversions.makeMailbox(mProviderContext, toAccount, fromFolder); 752 753 // Now test fields in created mailbox 754 assertEquals("INBOX", toMailbox.mDisplayName); 755 assertNull(toMailbox.mServerId); 756 assertNull(toMailbox.mParentServerId); 757 assertEquals(toAccount.mId, toMailbox.mAccountKey); 758 assertEquals(Mailbox.TYPE_INBOX, toMailbox.mType); 759 assertEquals(0, toMailbox.mDelimiter); 760 assertNull(toMailbox.mSyncKey); 761 assertEquals(0, toMailbox.mSyncLookback); 762 assertEquals(0, toMailbox.mSyncInterval); 763 assertEquals(0, toMailbox.mSyncTime); 764 assertTrue(toMailbox.mFlagVisible); 765 assertEquals(0, toMailbox.mFlags); 766 assertEquals(Email.VISIBLE_LIMIT_DEFAULT, toMailbox.mVisibleLimit); 767 assertNull(toMailbox.mSyncStatus); 768 } 769 770 /** 771 * Build a lightweight Store Folder with simple field population. The folder is "open" 772 * and should be closed by the caller. 773 */ 774 private Folder buildTestFolder(String folderName) throws MessagingException { 775 String localStoreUri = 776 "local://localhost/" + mProviderContext.getDatabasePath(LocalStoreUnitTests.DB_NAME); 777 LocalStore store = (LocalStore) LocalStore.newInstance(localStoreUri, getContext(), null); 778 LocalStore.LocalFolder folder = (LocalStore.LocalFolder) store.getFolder(folderName); 779 folder.open(OpenMode.READ_WRITE, null); // this will create it 780 781 // set a few fields to test values 782 // folder.getName - set by getFolder() 783 folder.setUnreadMessageCount(100); 784 785 return folder; 786 } 787} 788