• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.emailcommon.internet;
18 
19 import android.content.Context;
20 import android.test.ProviderTestCase2;
21 import android.test.suitebuilder.annotation.Suppress;
22 
23 import com.android.email.R;
24 import com.android.email.provider.EmailProvider;
25 import com.android.emailcommon.mail.MessagingException;
26 import com.android.emailcommon.provider.EmailContent;
27 import com.android.emailcommon.provider.EmailContent.Attachment;
28 import com.android.emailcommon.provider.EmailContent.Body;
29 import com.android.emailcommon.provider.EmailContent.Message;
30 
31 import org.apache.james.mime4j.field.Field;
32 import org.apache.james.mime4j.message.BodyPart;
33 import org.apache.james.mime4j.message.Entity;
34 import org.apache.james.mime4j.message.Header;
35 import org.apache.james.mime4j.message.Multipart;
36 
37 import java.io.ByteArrayInputStream;
38 import java.io.ByteArrayOutputStream;
39 import java.io.IOException;
40 import java.util.ArrayList;
41 import java.util.List;
42 
43 
44 /**
45  * Tests of the Rfc822Output (used for sending mail)
46  *
47  * You can run this entire test case with:
48  *   runtest -c com.android.email.mail.transport.Rfc822OutputTests email
49  */
50 @Suppress
51 public class Rfc822OutputTests extends ProviderTestCase2<EmailProvider> {
52     private static final String SENDER = "sender@android.com";
53     private static final String RECIPIENT_TO = "recipient-to@android.com";
54     private static final String RECIPIENT_CC = "recipient-cc@android.com";
55     private static final String SUBJECT = "This is the subject";
56     private static final String REPLY_TEXT_BODY = "This is the body.  This is also the body.";
57     private static final String TEXT = "Here is some new text.";
58 
59     // Full HTML document
60     private static final String HTML_FULL_BODY = "<html><head><title>MyTitle</title></head>"
61             + "<body bgcolor=\"#ffffff\" text=\"#000000\">"
62             + "<a href=\"google.com\">test1</a></body></html>";
63     private static final String HTML_FULL_RESULT = "<a href=\"google.com\">test1</a>";
64     // <body/> element w/ content
65     private static final String HTML_BODY_BODY =
66             "<body bgcolor=\"#ffffff\" text=\"#000000\"><a href=\"google.com\">test2</a></body>";
67     private static final String HTML_BODY_RESULT = "<a href=\"google.com\">test2</a>";
68     // No <body/> tag; just content
69     private static final String HTML_NO_BODY_BODY =
70             "<a href=\"google.com\">test3</a>";
71     private static final String HTML_NO_BODY_RESULT = "<a href=\"google.com\">test3</a>";
72 
73     private Context mMockContext;
74     private String mForwardIntro;
75 
Rfc822OutputTests()76     public Rfc822OutputTests () {
77         super(EmailProvider.class, EmailContent.AUTHORITY);
78     }
79 
80     @Override
setUp()81     public void setUp() throws Exception {
82         super.setUp();
83         mMockContext = getMockContext();
84         mForwardIntro = mMockContext.getString(R.string.message_compose_fwd_header_fmt, SUBJECT,
85                 SENDER, RECIPIENT_TO, RECIPIENT_CC);
86     }
87 
88     // TODO Create more tests here.  Specifically, we should test to make sure that forward works
89     // properly instead of just reply
90 
91     // TODO Write test that ensures that bcc is handled properly (i.e. sent/not send depending
92     // on the flag passed to writeTo
93 
createTestBody(Message message)94     private Body createTestBody(Message message) {
95         return Body.restoreBodyWithMessageId(mMockContext, message.mId);
96     }
97 
98     /**
99      * Test for buildBodyText().
100      * Compare with expected values.
101      */
testBuildBodyTextWithForward()102     public void testBuildBodyTextWithForward() {
103         Message msg = new Message();
104         msg.mText = TEXT;
105         msg.mFrom = SENDER;
106         msg.mTo = RECIPIENT_TO;
107         msg.mCc = RECIPIENT_CC;
108         msg.mSubject = SUBJECT;
109         msg.mFlags = Message.FLAG_TYPE_FORWARD;
110         msg.save(mMockContext);
111         Body body = createTestBody(msg);
112         String[] bodyParts = Rfc822Output.buildBodyText(body, false);
113         assertEquals(TEXT + mForwardIntro + REPLY_TEXT_BODY, bodyParts[0]);
114     }
115 
testWriteToText()116     public void testWriteToText() throws IOException, MessagingException {
117         // Create a simple text message
118         Message msg = new Message();
119         msg.mText = TEXT;
120         msg.mFrom = SENDER;
121         // Save this away
122         msg.save(mMockContext);
123 
124         // Write out an Rfc822 message
125         ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
126         Rfc822Output.writeTo(mMockContext, msg, byteStream, true, false, null);
127 
128         // Get the message and create a mime4j message from it
129         // We'll take advantage of its parsing capabilities
130         ByteArrayInputStream messageInputStream =
131             new ByteArrayInputStream(byteStream.toByteArray());
132         org.apache.james.mime4j.message.Message mimeMessage =
133             new org.apache.james.mime4j.message.Message(messageInputStream);
134 
135         // Make sure its structure is correct
136         checkMimeVersion(mimeMessage);
137         assertFalse(mimeMessage.isMultipart());
138         assertEquals("text/plain", mimeMessage.getMimeType());
139     }
140 
141     @SuppressWarnings("unchecked")
testWriteToAlternativePart()142     public void testWriteToAlternativePart() throws IOException, MessagingException {
143         // Create a message with alternative part
144         Message msg = new Message();
145         msg.mText = TEXT;
146         msg.mFrom = SENDER;
147         msg.mAttachments = new ArrayList<Attachment>();
148         // Attach a meeting invitation, which needs to be sent as multipart/alternative
149         Attachment att = new Attachment();
150         att.mContentBytes = "__CONTENT__".getBytes("UTF-8");
151         att.mFlags = Attachment.FLAG_ICS_ALTERNATIVE_PART;
152         att.mMimeType = "text/calendar";
153         att.mFileName = "invite.ics";
154         msg.mAttachments.add(att);
155         // Save this away
156         msg.save(mMockContext);
157 
158         // Write out an Rfc822 message
159         ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
160         Rfc822Output.writeTo(mMockContext, msg, byteStream, true, false, null);
161 
162         // Get the message and create a mime4j message from it
163         // We'll take advantage of its parsing capabilities
164         ByteArrayInputStream messageInputStream =
165             new ByteArrayInputStream(byteStream.toByteArray());
166         org.apache.james.mime4j.message.Message mimeMessage =
167             new org.apache.james.mime4j.message.Message(messageInputStream);
168 
169         // Make sure its structure is correct
170         checkMimeVersion(mimeMessage);
171         assertTrue(mimeMessage.isMultipart());
172         Header header = mimeMessage.getHeader();
173         Field contentType = header.getField("content-type");
174         assertTrue(contentType.getBody().contains("multipart/alternative"));
175         Multipart multipart = (Multipart)mimeMessage.getBody();
176         List<BodyPart> partList = multipart.getBodyParts();
177         assertEquals(2, partList.size());
178         Entity part = partList.get(0);
179         assertEquals("text/plain", part.getMimeType());
180         part = partList.get(1);
181         assertEquals("text/calendar", part.getMimeType());
182         header = part.getHeader();
183         assertNull(header.getField("content-disposition"));
184     }
185 
186     @SuppressWarnings("unchecked")
testWriteToMixedPart()187     public void testWriteToMixedPart() throws IOException, MessagingException {
188         // Create a message with a mixed part
189         Message msg = new Message();
190         msg.mText = TEXT;
191         msg.mFrom = SENDER;
192         msg.mAttachments = new ArrayList<Attachment>();
193         // Attach a simple html "file"
194         Attachment att = new Attachment();
195         att.mContentBytes = "<html>Hi</html>".getBytes("UTF-8");
196         att.mMimeType = "text/html";
197         att.mFileName = "test.html";
198         msg.mAttachments.add(att);
199         // Save this away
200         msg.save(mMockContext);
201 
202         // Write out an Rfc822 message
203         ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
204         Rfc822Output.writeTo(mMockContext, msg, byteStream, true, false, null);
205 
206         // Get the message and create a mime4j message from it
207         // We'll take advantage of its parsing capabilities
208         ByteArrayInputStream messageInputStream =
209             new ByteArrayInputStream(byteStream.toByteArray());
210         org.apache.james.mime4j.message.Message mimeMessage =
211             new org.apache.james.mime4j.message.Message(messageInputStream);
212 
213         // Make sure its structure is correct
214         checkMimeVersion(mimeMessage);
215         assertTrue(mimeMessage.isMultipart());
216         Header header = mimeMessage.getHeader();
217         Field contentType = header.getField("content-type");
218         assertTrue(contentType.getBody().contains("multipart/mixed"));
219         Multipart multipart = (Multipart)mimeMessage.getBody();
220         List<BodyPart> partList = multipart.getBodyParts();
221         assertEquals(2, partList.size());
222         Entity part = partList.get(0);
223         assertEquals("text/plain", part.getMimeType());
224         part = partList.get(1);
225         assertEquals("text/html", part.getMimeType());
226         header = part.getHeader();
227         assertNotNull(header.getField("content-disposition"));
228     }
229 
230     /**
231      * Tests various types of HTML reply text -- with full <html/> tags,
232      * with just the <body/> tags and without any surrounding tags.
233      */
testGetHtmlBody()234     public void testGetHtmlBody() {
235         String actual;
236         actual = Rfc822Output.getHtmlBody(HTML_FULL_BODY);
237         assertEquals(HTML_FULL_RESULT, actual);
238         actual = Rfc822Output.getHtmlBody(HTML_BODY_BODY);
239         assertEquals(HTML_BODY_RESULT, actual);
240         actual = Rfc822Output.getHtmlBody(HTML_NO_BODY_BODY);
241         assertEquals(HTML_NO_BODY_RESULT, actual);
242     }
243 
244     /**
245      * Test the boundary digit. We modify it indirectly.
246      */
testBoundaryDigit()247     public void testBoundaryDigit() {
248         // Use getBoundary() to update the boundary digit
249         Rfc822Output.sBoundaryDigit = 0; // ensure it starts at a known value
250 
251         Rfc822Output.getNextBoundary();
252         assertEquals(1, Rfc822Output.sBoundaryDigit);
253         Rfc822Output.getNextBoundary();
254         assertEquals(2, Rfc822Output.sBoundaryDigit);
255         Rfc822Output.getNextBoundary();
256         assertEquals(3, Rfc822Output.sBoundaryDigit);
257         Rfc822Output.getNextBoundary();
258         assertEquals(4, Rfc822Output.sBoundaryDigit);
259         Rfc822Output.getNextBoundary();
260         assertEquals(5, Rfc822Output.sBoundaryDigit);
261         Rfc822Output.getNextBoundary();
262         assertEquals(6, Rfc822Output.sBoundaryDigit);
263         Rfc822Output.getNextBoundary();
264         assertEquals(7, Rfc822Output.sBoundaryDigit);
265         Rfc822Output.getNextBoundary();
266         assertEquals(8, Rfc822Output.sBoundaryDigit);
267         Rfc822Output.getNextBoundary();
268         assertEquals(9, Rfc822Output.sBoundaryDigit);
269         Rfc822Output.getNextBoundary(); // roll over
270         assertEquals(0, Rfc822Output.sBoundaryDigit);
271     }
272 
273     private static final int BOUNDARY_COUNT = 12;
testGetNextBoundary()274     public void testGetNextBoundary() {
275         String[] resultArray = new String[BOUNDARY_COUNT];
276         for (int i = 0; i < BOUNDARY_COUNT; i++) {
277             resultArray[i] = Rfc822Output.getNextBoundary();
278         }
279         for (int i = 0; i < BOUNDARY_COUNT; i++) {
280             final String result1 = resultArray[i];
281             for (int j = 0; j < BOUNDARY_COUNT; j++) {
282                 if (i == j) {
283                     continue; // Don't verify the same result
284                 }
285                 final String result2 = resultArray[j];
286                 assertFalse(result1.equals(result2));
287             }
288         }
289     }
290 
291     /**
292      * Confirm that the constructed message includes "MIME-VERSION: 1.0"
293      */
checkMimeVersion(org.apache.james.mime4j.message.Message mimeMessage)294     private void checkMimeVersion(org.apache.james.mime4j.message.Message mimeMessage) {
295         Header header = mimeMessage.getHeader();
296         Field contentType = header.getField("MIME-VERSION");
297         assertTrue(contentType.getBody().equals("1.0"));
298     }
299 }
300