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.mail.transport; 18 19import com.android.email.R; 20import com.android.email.mail.MessagingException; 21import com.android.email.provider.EmailProvider; 22import com.android.email.provider.EmailContent.Attachment; 23import com.android.email.provider.EmailContent.Message; 24 25import org.apache.james.mime4j.field.Field; 26import org.apache.james.mime4j.message.Body; 27import org.apache.james.mime4j.message.Entity; 28import org.apache.james.mime4j.message.Header; 29import org.apache.james.mime4j.message.Multipart; 30 31import android.content.Context; 32import android.test.ProviderTestCase2; 33 34import java.io.ByteArrayInputStream; 35import java.io.ByteArrayOutputStream; 36import java.io.IOException; 37import java.util.ArrayList; 38import java.util.List; 39 40 41/** 42 * Tests of the Rfc822Output (used for sending mail) 43 * 44 * You can run this entire test case with: 45 * runtest -c com.android.email.mail.transport.Rfc822OutputTests email 46 */ 47public class Rfc822OutputTests extends ProviderTestCase2<EmailProvider> { 48 private static final String SENDER = "sender@android.com"; 49 private static final String REPLYTO = "replyto@android.com"; 50 private static final String RECIPIENT_TO = "recipient-to@android.com"; 51 private static final String RECIPIENT_CC = "recipient-cc@android.com"; 52 private static final String RECIPIENT_BCC = "recipient-bcc@android.com"; 53 private static final String SUBJECT = "This is the subject"; 54 private static final String BODY = "This is the body. This is also the body."; 55 private static final String TEXT = "Here is some new text."; 56 57 private Context mMockContext; 58 private String mForwardIntro; 59 private String mReplyIntro; 60 private String mReplyBody; 61 62 public Rfc822OutputTests () { 63 super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY); 64 } 65 66 @Override 67 public void setUp() throws Exception { 68 super.setUp(); 69 mMockContext = getMockContext(); 70 mForwardIntro = mMockContext.getString(R.string.message_compose_fwd_header_fmt, SUBJECT, 71 SENDER, RECIPIENT_TO, RECIPIENT_CC); 72 mReplyIntro = mMockContext.getString(R.string.message_compose_reply_header_fmt, SENDER); 73 mReplyBody = mReplyIntro + ">" + BODY; 74 } 75 76 // TODO Create more tests here. Specifically, we should test to make sure that forward works 77 // properly instead of just reply 78 79 // TODO Write test that ensures that bcc is handled properly (i.e. sent/not send depending 80 // on the flag passed to writeTo 81 82 /** 83 * Test for buildBodyText(). 84 * Compare with expected values. 85 * Also test the situation where the message has no body. 86 */ 87 public void testBuildBodyTextWithReply() { 88 // Create the least necessary; sender, flags, and the body of the reply 89 Message msg = new Message(); 90 msg.mText = ""; 91 msg.mFrom = SENDER; 92 msg.mFlags = Message.FLAG_TYPE_REPLY; 93 msg.mTextReply = BODY; 94 msg.mIntroText = mReplyIntro; 95 msg.save(mMockContext); 96 97 String body = Rfc822Output.buildBodyText(mMockContext, msg, true); 98 assertEquals(mReplyBody, body); 99 100 // Save a different message with no reply body (so we reset the id) 101 msg.mId = -1; 102 msg.mTextReply = null; 103 msg.save(mMockContext); 104 body = Rfc822Output.buildBodyText(mMockContext, msg, true); 105 assertEquals(mReplyIntro, body); 106 } 107 108 /** 109 * Test for buildBodyText(). 110 * Compare with expected values. 111 * Also test the situation where the message has no body. 112 */ 113 public void testBuildBodyTextWithoutReply() { 114 // Create the least necessary; sender, flags, and the body of the reply 115 Message msg = new Message(); 116 msg.mText = TEXT; 117 msg.mFrom = SENDER; 118 msg.mFlags = Message.FLAG_TYPE_REPLY; 119 msg.mTextReply = BODY; 120 msg.mIntroText = mReplyIntro; 121 msg.save(mMockContext); 122 123 String body = Rfc822Output.buildBodyText(mMockContext, msg, false); 124 assertEquals(TEXT + mReplyIntro, body); 125 126 // Save a different message with no reply body (so we reset the id) 127 msg.mId = -1; 128 msg.mTextReply = null; 129 msg.save(mMockContext); 130 body = Rfc822Output.buildBodyText(mMockContext, msg, false); 131 assertEquals(TEXT + mReplyIntro, body); 132 } 133 134 /** 135 * Test for buildBodyText(). 136 * Compare with expected values. 137 */ 138 public void testBuildBodyTextWithForward() { 139 Message msg = new Message(); 140 msg.mText = TEXT; 141 msg.mFrom = SENDER; 142 msg.mTo = RECIPIENT_TO; 143 msg.mCc = RECIPIENT_CC; 144 msg.mSubject = SUBJECT; 145 msg.mFlags = Message.FLAG_TYPE_FORWARD; 146 msg.mTextReply = BODY; 147 msg.mIntroText = mForwardIntro; 148 msg.save(mMockContext); 149 String body = Rfc822Output.buildBodyText(mMockContext, msg, true); 150 assertEquals(TEXT + mForwardIntro + BODY, body); 151 } 152 153 public void testWriteToText() throws IOException, MessagingException { 154 // Create a simple text message 155 Message msg = new Message(); 156 msg.mText = TEXT; 157 msg.mFrom = SENDER; 158 // Save this away 159 msg.save(mMockContext); 160 161 // Write out an Rfc822 message 162 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 163 Rfc822Output.writeTo(mMockContext, msg.mId, byteStream, false, false); 164 165 // Get the message and create a mime4j message from it 166 // We'll take advantage of its parsing capabilities 167 ByteArrayInputStream messageInputStream = 168 new ByteArrayInputStream(byteStream.toByteArray()); 169 org.apache.james.mime4j.message.Message mimeMessage = 170 new org.apache.james.mime4j.message.Message(messageInputStream); 171 172 // Make sure its structure is correct 173 checkMimeVersion(mimeMessage); 174 assertFalse(mimeMessage.isMultipart()); 175 assertEquals("text/plain", mimeMessage.getMimeType()); 176 } 177 178 @SuppressWarnings("unchecked") 179 public void testWriteToAlternativePart() throws IOException, MessagingException { 180 // Create a message with alternative part 181 Message msg = new Message(); 182 msg.mText = TEXT; 183 msg.mFrom = SENDER; 184 msg.mAttachments = new ArrayList<Attachment>(); 185 // Attach a meeting invitation, which needs to be sent as multipart/alternative 186 Attachment att = new Attachment(); 187 att.mContentBytes = "__CONTENT__".getBytes("UTF-8"); 188 att.mFlags = Attachment.FLAG_ICS_ALTERNATIVE_PART; 189 att.mMimeType = "text/calendar"; 190 att.mFileName = "invite.ics"; 191 msg.mAttachments.add(att); 192 // Save this away 193 msg.save(mMockContext); 194 195 // Write out an Rfc822 message 196 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 197 Rfc822Output.writeTo(mMockContext, msg.mId, byteStream, false, false); 198 199 // Get the message and create a mime4j message from it 200 // We'll take advantage of its parsing capabilities 201 ByteArrayInputStream messageInputStream = 202 new ByteArrayInputStream(byteStream.toByteArray()); 203 org.apache.james.mime4j.message.Message mimeMessage = 204 new org.apache.james.mime4j.message.Message(messageInputStream); 205 206 // Make sure its structure is correct 207 checkMimeVersion(mimeMessage); 208 assertTrue(mimeMessage.isMultipart()); 209 Header header = mimeMessage.getHeader(); 210 Field contentType = header.getField("content-type"); 211 assertTrue(contentType.getBody().contains("multipart/alternative")); 212 Multipart multipart = (Multipart)mimeMessage.getBody(); 213 List<Body> partList = multipart.getBodyParts(); 214 assertEquals(2, partList.size()); 215 Entity part = (Entity)partList.get(0); 216 assertEquals("text/plain", part.getMimeType()); 217 part = (Entity)partList.get(1); 218 assertEquals("text/calendar", part.getMimeType()); 219 header = part.getHeader(); 220 assertNull(header.getField("content-disposition")); 221 } 222 223 @SuppressWarnings("unchecked") 224 public void testWriteToMixedPart() throws IOException, MessagingException { 225 // Create a message with a mixed part 226 Message msg = new Message(); 227 msg.mText = TEXT; 228 msg.mFrom = SENDER; 229 msg.mAttachments = new ArrayList<Attachment>(); 230 // Attach a simple html "file" 231 Attachment att = new Attachment(); 232 att.mContentBytes = "<html>Hi</html>".getBytes("UTF-8"); 233 att.mMimeType = "text/html"; 234 att.mFileName = "test.html"; 235 msg.mAttachments.add(att); 236 // Save this away 237 msg.save(mMockContext); 238 239 // Write out an Rfc822 message 240 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 241 Rfc822Output.writeTo(mMockContext, msg.mId, byteStream, false, false); 242 243 // Get the message and create a mime4j message from it 244 // We'll take advantage of its parsing capabilities 245 ByteArrayInputStream messageInputStream = 246 new ByteArrayInputStream(byteStream.toByteArray()); 247 org.apache.james.mime4j.message.Message mimeMessage = 248 new org.apache.james.mime4j.message.Message(messageInputStream); 249 250 // Make sure its structure is correct 251 checkMimeVersion(mimeMessage); 252 assertTrue(mimeMessage.isMultipart()); 253 Header header = mimeMessage.getHeader(); 254 Field contentType = header.getField("content-type"); 255 assertTrue(contentType.getBody().contains("multipart/mixed")); 256 Multipart multipart = (Multipart)mimeMessage.getBody(); 257 List<Body> partList = multipart.getBodyParts(); 258 assertEquals(2, partList.size()); 259 Entity part = (Entity)partList.get(0); 260 assertEquals("text/plain", part.getMimeType()); 261 part = (Entity)partList.get(1); 262 assertEquals("text/html", part.getMimeType()); 263 header = part.getHeader(); 264 assertNotNull(header.getField("content-disposition")); 265 } 266 267 /** 268 * Confirm that the constructed message includes "MIME-VERSION: 1.0" 269 */ 270 private void checkMimeVersion(org.apache.james.mime4j.message.Message mimeMessage) { 271 Header header = mimeMessage.getHeader(); 272 Field contentType = header.getField("MIME-VERSION"); 273 assertTrue(contentType.getBody().equals("1.0")); 274 } 275} 276