replicant-packages_apps_Email/tests/src/com/android/email/LegacyConversionsTests.java

406 lines
19 KiB
Java

/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.test.ProviderTestCase2;
import android.test.suitebuilder.annotation.Suppress;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.ProviderTestUtils;
import com.android.emailcommon.internet.MimeHeader;
import com.android.emailcommon.internet.MimeUtility;
import com.android.emailcommon.mail.Address;
import com.android.emailcommon.mail.BodyPart;
import com.android.emailcommon.mail.Flag;
import com.android.emailcommon.mail.Message;
import com.android.emailcommon.mail.Message.RecipientType;
import com.android.emailcommon.mail.MessageTestUtils;
import com.android.emailcommon.mail.MessageTestUtils.MessageBuilder;
import com.android.emailcommon.mail.MessageTestUtils.MultipartBuilder;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.mail.Part;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Attachment;
import java.io.IOException;
import java.util.ArrayList;
/**
* Tests of the Legacy Conversions code (used by MessagingController).
*
* NOTE: It would probably make sense to rewrite this using a MockProvider, instead of the
* ProviderTestCase (which is a real provider running on a temp database). This would be more of
* a true "unit test".
*
* You can run this entire test case with:
* runtest -c com.android.email.LegacyConversionsTests email
*/
@Suppress
public class LegacyConversionsTests extends ProviderTestCase2<EmailProvider> {
Context mProviderContext;
Context mContext;
public LegacyConversionsTests() {
super(EmailProvider.class, EmailContent.AUTHORITY);
}
@Override
public void setUp() throws Exception {
super.setUp();
mProviderContext = getMockContext();
mContext = getContext();
}
/**
* TODO: basic Legacy -> Provider Message conversions
* TODO: basic Legacy -> Provider Body conversions
* TODO: rainy day tests of all kinds
*/
/**
* Sunny day test of adding attachments from an IMAP/POP message.
*/
public void brokentestAddAttachments() throws MessagingException, IOException {
// Prepare a local message to add the attachments to
final long accountId = 1;
final long mailboxId = 1;
// test 1: legacy message using content-type:name style for name
final EmailContent.Message localMessage = ProviderTestUtils.setupMessage(
"local-message", accountId, mailboxId, false, true, mProviderContext);
final Message legacyMessage = prepareLegacyMessageWithAttachments(2, false);
convertAndCheckcheckAddedAttachments(localMessage, legacyMessage);
// test 2: legacy message using content-disposition:filename style for name
final EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage(
"local-message", accountId, mailboxId, false, true, mProviderContext);
final Message legacyMessage2 = prepareLegacyMessageWithAttachments(2, true);
convertAndCheckcheckAddedAttachments(localMessage2, legacyMessage2);
}
/**
* Helper for testAddAttachments
*/
private void convertAndCheckcheckAddedAttachments(final EmailContent.Message localMessage,
final Message legacyMessage) throws MessagingException, IOException {
// Now, convert from legacy to provider and see what happens
ArrayList<Part> viewables = new ArrayList<Part>();
ArrayList<Part> attachments = new ArrayList<Part>();
MimeUtility.collectParts(legacyMessage, viewables, attachments);
LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
// Read back all attachments for message and check field values
Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
Cursor c = mProviderContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
null, null, null);
try {
assertEquals(2, c.getCount());
while (c.moveToNext()) {
Attachment attachment =
Attachment.getContent(mProviderContext, c, Attachment.class);
if ("100".equals(attachment.mLocation)) {
checkAttachment("attachment1Part", attachments.get(0), attachment,
localMessage.mAccountKey);
} else if ("101".equals(attachment.mLocation)) {
checkAttachment("attachment2Part", attachments.get(1), attachment,
localMessage.mAccountKey);
} else {
fail("Unexpected attachment with location " + attachment.mLocation);
}
}
} finally {
c.close();
}
}
/**
* Test that only "attachment" or "inline" attachments are captured and added.
* @throws MessagingException
* @throws IOException
*/
public void brokentestAttachmentDispositions() throws MessagingException, IOException {
// Prepare a local message to add the attachments to
final long accountId = 1;
final long mailboxId = 1;
// Prepare the three attachments we want to test
BodyPart[] sourceAttachments = new BodyPart[3];
BodyPart attachmentPart;
// 1. Standard attachment
attachmentPart = MessageTestUtils.bodyPart("image/jpg", null);
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg");
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
"attachment;\n filename=\"file-1\";\n size=100");
attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "100");
sourceAttachments[0] = attachmentPart;
// 2. Inline attachment
attachmentPart = MessageTestUtils.bodyPart("image/gif", null);
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/gif");
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
"inline;\n filename=\"file-2\";\n size=200");
attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "101");
sourceAttachments[1] = attachmentPart;
// 3. Neither (use VCALENDAR)
attachmentPart = MessageTestUtils.bodyPart("text/calendar", null);
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
"text/calendar; charset=UTF-8; method=REQUEST");
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "7bit");
attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "102");
sourceAttachments[2] = attachmentPart;
// Prepare local message (destination) and legacy message w/attachments (source)
final EmailContent.Message localMessage = ProviderTestUtils.setupMessage(
"local-message", accountId, mailboxId, false, true, mProviderContext);
final Message legacyMessage = prepareLegacyMessageWithAttachments(sourceAttachments);
convertAndCheckcheckAddedAttachments(localMessage, legacyMessage);
// Run the conversion and check for the converted attachments - this test asserts
// that there are two attachments numbered 100 & 101 (so will fail if it finds 102)
convertAndCheckcheckAddedAttachments(localMessage, legacyMessage);
}
/**
* Test that attachments aren't re-added in the DB. This supports the "partial download"
* nature of POP messages.
*/
public void brokentestAddDuplicateAttachments() throws MessagingException, IOException {
// Prepare a local message to add the attachments to
final long accountId = 1;
final long mailboxId = 1;
final EmailContent.Message localMessage = ProviderTestUtils.setupMessage(
"local-message", accountId, mailboxId, false, true, mProviderContext);
// Prepare a legacy message with attachments
Message legacyMessage = prepareLegacyMessageWithAttachments(2, false);
// Now, convert from legacy to provider and see what happens
ArrayList<Part> viewables = new ArrayList<Part>();
ArrayList<Part> attachments = new ArrayList<Part>();
MimeUtility.collectParts(legacyMessage, viewables, attachments);
LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
// Confirm two attachment objects created
Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
assertEquals(2, EmailContent.count(mProviderContext, uri, null, null));
// Now add the attachments again and confirm there are still only two
LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
assertEquals(2, EmailContent.count(mProviderContext, uri, null, null));
// Now add a 3rd & 4th attachment and make sure the total is 4, not 2 or 6
legacyMessage = prepareLegacyMessageWithAttachments(4, false);
viewables = new ArrayList<Part>();
attachments = new ArrayList<Part>();
MimeUtility.collectParts(legacyMessage, viewables, attachments);
LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments);
assertEquals(4, EmailContent.count(mProviderContext, uri, null, null));
}
/**
* Prepare a legacy message with 1+ attachments
* @param numAttachments how many attachments to add
* @param filenameInDisposition False: attachment names are sent as content-type:name. True:
* attachment names are sent as content-disposition:filename.
*/
private Message prepareLegacyMessageWithAttachments(int numAttachments,
boolean filenameInDisposition) throws MessagingException {
BodyPart[] attachmentParts = new BodyPart[numAttachments];
for (int i = 0; i < numAttachments; ++i) {
// construct parameter parts for content-type:name or content-disposition:filename.
String name = "";
String filename = "";
String quotedName = "\"test-attachment-" + i + "\"";
if (filenameInDisposition) {
filename = ";\n filename=" + quotedName;
} else {
name = ";\n name=" + quotedName;
}
// generate an attachment that came from a server
BodyPart attachmentPart = MessageTestUtils.bodyPart("image/jpg", null);
// name=attachmentN size=N00 location=10N
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg" + name);
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
"attachment" + filename + ";\n size=" + (i+1) + "00");
attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "10" + i);
attachmentParts[i] = attachmentPart;
}
return prepareLegacyMessageWithAttachments(attachmentParts);
}
/**
* Prepare a legacy message with 1+ attachments
* @param attachments array containing one or more attachments
*/
private Message prepareLegacyMessageWithAttachments(BodyPart[] attachments)
throws MessagingException {
// Build the multipart that holds the attachments
MultipartBuilder mpBuilder = new MultipartBuilder("multipart/mixed");
for (int i = 0; i < attachments.length; ++i) {
mpBuilder.addBodyPart(attachments[i]);
}
// Now build a message with them
final Message legacyMessage = new MessageBuilder()
.setBody(new MultipartBuilder("multipart/mixed")
.addBodyPart(MessageTestUtils.bodyPart("text/html", null))
.addBodyPart(mpBuilder.buildBodyPart())
.build())
.build();
return legacyMessage;
}
/**
* Compare attachment that was converted from Part (expected) to Provider Attachment (actual)
*
* TODO content URI should only be set if we also saved a file
* TODO other data encodings
*/
private void checkAttachment(String tag, Part expected, EmailContent.Attachment actual,
long accountKey) throws MessagingException {
String contentType = MimeUtility.unfoldAndDecode(expected.getContentType());
String contentTypeName = MimeUtility.getHeaderParameter(contentType, "name");
assertEquals(tag, expected.getMimeType(), actual.mMimeType);
String disposition = expected.getDisposition();
String sizeString = MimeUtility.getHeaderParameter(disposition, "size");
String dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename");
long expectedSize = (sizeString != null) ? Long.parseLong(sizeString) : 0;
assertEquals(tag, expectedSize, actual.mSize);
assertEquals(tag, expected.getContentId(), actual.mContentId);
// filename is either content-type:name or content-disposition:filename
String expectedName = (contentTypeName != null) ? contentTypeName : dispositionFilename;
assertEquals(tag, expectedName, actual.mFileName);
// content URI should be null
assertNull(tag, actual.getContentUri());
assertTrue(tag, 0 != actual.mMessageKey);
// location is either both null or both matching
String expectedPartId = null;
String[] storeData = expected.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA);
if (storeData != null && storeData.length > 0) {
expectedPartId = storeData[0];
}
assertEquals(tag, expectedPartId, actual.mLocation);
assertEquals(tag, "B", actual.mEncoding);
assertEquals(tag, accountKey, actual.mAccountKey);
}
/**
* TODO: Sunny day test of adding attachments from a POP message.
*/
/**
* Sunny day tests of converting an original message to a legacy message
*/
public void brokentestMakeLegacyMessage() throws MessagingException {
// Set up and store a message in the provider
long account1Id = 1;
long mailbox1Id = 1;
// Test message 1: No body
EmailContent.Message localMessage1 = ProviderTestUtils.setupMessage("make-legacy",
account1Id, mailbox1Id, false, true, mProviderContext);
Message getMessage1 = LegacyConversions.makeMessage(mProviderContext, localMessage1);
checkLegacyMessage("no body", localMessage1, getMessage1);
// Test message 2: Simple body
EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage("make-legacy",
account1Id, mailbox1Id, true, false, mProviderContext);
localMessage2.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK;
localMessage2.save(mProviderContext);
Message getMessage2 = LegacyConversions.makeMessage(mProviderContext, localMessage2);
checkLegacyMessage("simple body", localMessage2, getMessage2);
// Test message 3: Body + replied-to text
EmailContent.Message localMessage3 = ProviderTestUtils.setupMessage("make-legacy",
account1Id, mailbox1Id, true, false, mProviderContext);
localMessage3.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK;
localMessage3.mFlags |= EmailContent.Message.FLAG_TYPE_REPLY;
localMessage3.save(mProviderContext);
Message getMessage3 = LegacyConversions.makeMessage(mProviderContext, localMessage3);
checkLegacyMessage("reply-to", localMessage3, getMessage3);
// Test message 4: Body + forwarded text
EmailContent.Message localMessage4 = ProviderTestUtils.setupMessage("make-legacy",
account1Id, mailbox1Id, true, false, mProviderContext);
localMessage4.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK;
localMessage4.mFlags |= EmailContent.Message.FLAG_TYPE_FORWARD;
localMessage4.save(mProviderContext);
Message getMessage4 = LegacyConversions.makeMessage(mProviderContext, localMessage4);
checkLegacyMessage("forwarding", localMessage4, getMessage4);
}
/**
* Check equality of a pair of converted messages
*/
private void checkLegacyMessage(String tag, EmailContent.Message expect, Message actual)
throws MessagingException {
assertEquals(tag, expect.mServerId, actual.getUid());
assertEquals(tag, expect.mServerTimeStamp, actual.getInternalDate().getTime());
assertEquals(tag, expect.mSubject, actual.getSubject());
assertEquals(tag, expect.mFrom, Address.toHeader(actual.getFrom()));
assertEquals(tag, expect.mTimeStamp, actual.getSentDate().getTime());
assertEquals(tag, expect.mTo, Address.toHeader(actual.getRecipients(RecipientType.TO)));
assertEquals(tag, expect.mCc, Address.toHeader(actual.getRecipients(RecipientType.CC)));
assertEquals(tag, expect.mBcc, Address.toHeader(actual.getRecipients(RecipientType.BCC)));
assertEquals(tag, expect.mReplyTo, Address.toHeader(actual.getReplyTo()));
assertEquals(tag, expect.mMessageId, actual.getMessageId());
// check flags
assertEquals(tag, expect.mFlagRead, actual.isSet(Flag.SEEN));
assertEquals(tag, expect.mFlagFavorite, actual.isSet(Flag.FLAGGED));
// Check the body of the message
ArrayList<Part> viewables = new ArrayList<Part>();
ArrayList<Part> attachments = new ArrayList<Part>();
MimeUtility.collectParts(actual, viewables, attachments);
String get1Text = null;
String get1Html = null;
for (Part viewable : viewables) {
String text = MimeUtility.getTextFromPart(viewable, true);
if (viewable.getMimeType().equalsIgnoreCase("text/html")) {
get1Html = text;
} else {
get1Text = text;
}
}
assertEquals(tag, expect.mText, get1Text);
assertEquals(tag, expect.mHtml, get1Html);
// TODO Check the attachments
// cv.put("attachment_count", attachments.size());
}
}