Home | History | Annotate | Download | only in internet
      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 (at) android.com";
     53     private static final String RECIPIENT_TO = "recipient-to (at) android.com";
     54     private static final String RECIPIENT_CC = "recipient-cc (at) 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 
     76     public Rfc822OutputTests () {
     77         super(EmailProvider.class, EmailContent.AUTHORITY);
     78     }
     79 
     80     @Override
     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 
     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      */
    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 
    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")
    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")
    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      */
    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      */
    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;
    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      */
    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