196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/*
296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License.
696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at
796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and
1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License.
1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
172193962ca2b3157e79f731736afa2a0c972e778aMarc Blankpackage com.android.emailcommon.internet;
1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
192193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.MimeBodyPart;
202193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.MimeHeader;
212193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.MimeUtility;
222193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.TextBody;
232193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.BodyPart;
242193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Message;
252193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessageTestUtils;
262193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessagingException;
272193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Part;
282193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessageTestUtils.MessageBuilder;
292193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessageTestUtils.MultipartBuilder;
3096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
3196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.test.suitebuilder.annotation.SmallTest;
3296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
3339121c758dcc919b5fde4c893d488916e26d3140Todd Kennedyimport java.util.ArrayList;
3439121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy
3596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport junit.framework.TestCase;
3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
3796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/**
3896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is a series of unit tests for the MimeUtility class.  These tests must be locally
3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * complete - no server(s) required.
4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project@SmallTest
4296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class MimeUtilityTest extends TestCase {
4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
448aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /** up arrow, down arrow, left arrow, right arrow */
458aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    private final String SHORT_UNICODE = "\u2191\u2193\u2190\u2192";
468aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    private final String SHORT_UNICODE_ENCODED = "=?UTF-8?B?4oaR4oaT4oaQ4oaS?=";
477037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
48d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    /** dollar and euro sign */
49d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    private final String PADDED2_UNICODE = "$\u20AC";
50d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    private final String PADDED2_UNICODE_ENCODED = "=?UTF-8?B?JOKCrA==?=";
51d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    private final String PADDED1_UNICODE = "$$\u20AC";
52d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    private final String PADDED1_UNICODE_ENCODED = "=?UTF-8?B?JCTigqw=?=";
53d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    private final String PADDED0_UNICODE = "$$$\u20AC";
54d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    private final String PADDED0_UNICODE_ENCODED = "=?UTF-8?B?JCQk4oKs?=";
55d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka
568aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /** a string without any unicode */
578aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    private final String SHORT_PLAIN = "abcd";
587037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
5944cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    /** long subject which will be split into two MIME/Base64 chunks */
6044cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String LONG_UNICODE_SPLIT =
6144cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "$" +
6244cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC" +
6344cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC\u20AC";
6444cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String LONG_UNICODE_SPLIT_ENCODED =
6544cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "=?UTF-8?B?JOKCrOKCrOKCrOKCrOKCrOKCrOKCrOKCrA==?=" + "\r\n " +
6644cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "=?UTF-8?B?4oKs4oKs4oKs4oKs4oKs4oKs4oKs4oKs4oKs4oKs4oKs4oKs?=";
6744cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka
6844cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    /** strings that use supplemental characters and really stress encode/decode */
6944cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    // actually it's U+10400
7044cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String SHORT_SUPPLEMENTAL = "\uD801\uDC00";
7144cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String SHORT_SUPPLEMENTAL_ENCODED = "=?UTF-8?B?8JCQgA==?=";
7244cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String LONG_SUPPLEMENTAL = SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL +
7344cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL +
7444cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL;
7544cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String LONG_SUPPLEMENTAL_ENCODED =
767037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie        "=?UTF-8?B?8JCQgPCQkIDwkJCA8JCQgA==?=" + "\r\n " +
7744cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "=?UTF-8?B?8JCQgPCQkIDwkJCA8JCQgPCQkIDwkJCA?=";
7844cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String LONG_SUPPLEMENTAL_2 = "a" + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL +
7944cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL +
8044cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL + SHORT_SUPPLEMENTAL;
8144cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String LONG_SUPPLEMENTAL_ENCODED_2 =
8244cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "=?UTF-8?B?YfCQkIDwkJCA8JCQgPCQkIA=?=" + "\r\n " +
837037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie        "=?UTF-8?B?8JCQgPCQkIDwkJCA8JCQgPCQkIDwkJCA?=";
8444cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    // Earth is U+1D300.
8544cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String LONG_SUPPLEMENTAL_QP =
867037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie        "*Monogram for Earth \uD834\uDF00. Monogram for Human \u268b.";
8744cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    private final String LONG_SUPPLEMENTAL_QP_ENCODED =
8844cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "=?UTF-8?Q?*Monogram_for_Earth_?=" + "\r\n " +
8944cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        "=?UTF-8?Q?=F0=9D=8C=80._Monogram_for_Human_=E2=9A=8B.?=";
9044cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka
918aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /** a typical no-param header */
9287fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler    private final String HEADER_NO_PARAMETER =
938aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project            "header";
948aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /** a typical multi-param header */
9587fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler    private final String HEADER_MULTI_PARAMETER =
968aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project            "header; Param1Name=Param1Value; Param2Name=Param2Value";
9787fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler    /** a multi-param header with quoting */
9887fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler    private final String HEADER_QUOTED_MULTI_PARAMETER =
9987fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler            "header; Param1Name=\"Param1Value\"; Param2Name=\"Param2Value\"";
10087fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler    /** a malformed header we're seeing in production servers */
10187fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler    private final String HEADER_MALFORMED_PARAMETER =
10287fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler            "header; Param1Name=Param1Value; filename";
1037037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
104f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    /**
105f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     * a string generated by google calendar that contains two interesting gotchas:
106f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     * 1.  Uses windows-1252 encoding, and en-dash recoded appropriately (\u2013 / =96)
107f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     * 2.  Because the first encoded char requires '=XX' encoding, we create an "internal"
108f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     *     "?=" that the decoder must correctly skip over.
109f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     **/
1107037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie    private final String CALENDAR_SUBJECT_UNICODE =
111f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        "=?windows-1252?Q?=5BReminder=5D_test_=40_Fri_Mar_20_10=3A30am_=96_11am_=28andro?=" +
112f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        "\r\n\t" +
113f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        "=?windows-1252?Q?id=2Etr=40gmail=2Ecom=29?=";
114f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    private final String CALENDAR_SUBJECT_PLAIN =
115f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        "[Reminder] test @ Fri Mar 20 10:30am \u2013 11am (android.tr@gmail.com)";
1167037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
117f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    /**
118f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     * Some basic degenerate strings designed to exercise error handling in the decoder
119f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     */
120f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    private final String CALENDAR_DEGENERATE_UNICODE_1 =
121f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        "=?windows-1252?Q=5B?=";
122f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    private final String CALENDAR_DEGENERATE_UNICODE_2 =
123f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        "=?windows-1252Q?=5B?=";
124f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    private final String CALENDAR_DEGENERATE_UNICODE_3 =
125f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        "=?windows-1252?=";
126f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    private final String CALENDAR_DEGENERATE_UNICODE_4 =
127f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        "=?windows-1252";
1288aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project
1298aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /**
1308aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     * Test that decode/unfold is efficient when it can be
1318aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     */
1328aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    public void testEfficientUnfoldAndDecode() {
1338aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result1 = MimeUtility.unfold(SHORT_PLAIN);
1348aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result2 = MimeUtility.decode(SHORT_PLAIN);
1358aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result3 = MimeUtility.unfoldAndDecode(SHORT_PLAIN);
1367037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
1378aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertSame(SHORT_PLAIN, result1);
1388aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertSame(SHORT_PLAIN, result2);
1398aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertSame(SHORT_PLAIN, result3);
1408aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    }
1418aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project
1428aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    // TODO:  more tests for unfold(String s)
1437037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
1448aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /**
1458aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     * Test that decode is working for simple strings
1468aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     */
1478aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    public void testDecodeSimple() {
1488aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result1 = MimeUtility.decode(SHORT_UNICODE_ENCODED);
1498aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertEquals(SHORT_UNICODE, result1);
1508aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    }
1517037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
15296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    // TODO:  tests for decode(String s)
1538aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project
1548aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /**
1558aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     * Test that unfoldAndDecode is working for simple strings
1568aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     */
1578aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    public void testUnfoldAndDecodeSimple() {
1588aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result1 = MimeUtility.unfoldAndDecode(SHORT_UNICODE_ENCODED);
1598aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertEquals(SHORT_UNICODE, result1);
1608aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    }
1617037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
162f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    /**
163f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     * test decoding complex string from google calendar that has two gotchas for the decoder.
164f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     * also tests a couple of degenerate cases that should "fail" decoding and pass through.
165f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler     */
166f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    public void testComplexDecode() {
167f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        String result1 = MimeUtility.unfoldAndDecode(CALENDAR_SUBJECT_UNICODE);
168f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        assertEquals(CALENDAR_SUBJECT_PLAIN, result1);
1697037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
170f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        // These degenerate cases should "fail" and return the same string
171f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        String degenerate1 = MimeUtility.unfoldAndDecode(CALENDAR_DEGENERATE_UNICODE_1);
172f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        assertEquals("degenerate case 1", CALENDAR_DEGENERATE_UNICODE_1, degenerate1);
173f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        String degenerate2 = MimeUtility.unfoldAndDecode(CALENDAR_DEGENERATE_UNICODE_2);
174f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        assertEquals("degenerate case 2", CALENDAR_DEGENERATE_UNICODE_2, degenerate2);
175f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        String degenerate3 = MimeUtility.unfoldAndDecode(CALENDAR_DEGENERATE_UNICODE_3);
176f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        assertEquals("degenerate case 3", CALENDAR_DEGENERATE_UNICODE_3, degenerate3);
177f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        String degenerate4 = MimeUtility.unfoldAndDecode(CALENDAR_DEGENERATE_UNICODE_4);
178f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler        assertEquals("degenerate case 4", CALENDAR_DEGENERATE_UNICODE_4, degenerate4);
179f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    }
1807037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
181f7eead207407c25b41fe622e9bd4f29a2b50ee7bAndy Stadler    // TODO:  more tests for unfoldAndDecode(String s)
1828aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project
1838aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /**
1848aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     * Test that fold/encode is efficient when it can be
1858aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     */
1868aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    public void testEfficientFoldAndEncode() {
1878aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result1 = MimeUtility.foldAndEncode(SHORT_PLAIN);
1888aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result2 = MimeUtility.foldAndEncode2(SHORT_PLAIN, 10);
1898aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result3 = MimeUtility.fold(SHORT_PLAIN, 10);
1907037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
1918aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertSame(SHORT_PLAIN, result1);
1928aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertSame(SHORT_PLAIN, result2);
1938aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertSame(SHORT_PLAIN, result3);
1948aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    }
1958aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project
196d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    /**
197d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka     * Test about base64 padding variety.
198d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka     */
199d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    public void testPaddingOfFoldAndEncode2() {
200d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka        String result1 = MimeUtility.foldAndEncode2(PADDED2_UNICODE, 0);
201d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka        String result2 = MimeUtility.foldAndEncode2(PADDED1_UNICODE, 0);
202d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka        String result3 = MimeUtility.foldAndEncode2(PADDED0_UNICODE, 0);
2037037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
204d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka        assertEquals("padding 2", PADDED2_UNICODE_ENCODED, result1);
205d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka        assertEquals("padding 1", PADDED1_UNICODE_ENCODED, result2);
206d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka        assertEquals("padding 0", PADDED0_UNICODE_ENCODED, result3);
207d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka    }
208d351a92869438d937b84c27b026803a92923d1dbTadashi Takaoka
2098aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    // TODO:  more tests for foldAndEncode(String s)
2108aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project
2118aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /**
2128aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     * Test that foldAndEncode2 is working for simple strings
2138aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     */
2148aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    public void testFoldAndEncode2() {
2158aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        String result1 = MimeUtility.foldAndEncode2(SHORT_UNICODE, 10);
2168aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertEquals(SHORT_UNICODE_ENCODED, result1);
2178aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    }
2187037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
21944cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    /**
22044cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * Test that foldAndEncode2 is working for long strings which needs splitting.
22144cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     */
22244cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    public void testFoldAndEncode2WithLongSplit() {
2237037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie        String result = MimeUtility.foldAndEncode2(LONG_UNICODE_SPLIT, "Subject: ".length());
22444cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka
22544cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        assertEquals("long string", LONG_UNICODE_SPLIT_ENCODED, result);
22644cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    }
2277037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
22844cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    /**
22944cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * Tests of foldAndEncode2 that involve supplemental characters (UTF-32)
23044cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     *
23144cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * Note that the difference between LONG_SUPPLEMENTAL and LONG_SUPPLEMENTAL_2 is the
23244cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * insertion of a single character at the head of the string. This is intended to disrupt
23344cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * the code that splits the long string into multiple encoded words, and confirm that it
23444cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * properly applies the breaks between UTF-32 code points.
23544cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     */
23644cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    public void testFoldAndEncode2Supplemental() {
23744cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        String result1 = MimeUtility.foldAndEncode2(SHORT_SUPPLEMENTAL, "Subject: ".length());
23844cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        String result2 = MimeUtility.foldAndEncode2(LONG_SUPPLEMENTAL, "Subject: ".length());
23944cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        String result3 = MimeUtility.foldAndEncode2(LONG_SUPPLEMENTAL_2, "Subject: ".length());
24044cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        assertEquals("short supplemental", SHORT_SUPPLEMENTAL_ENCODED, result1);
24144cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        assertEquals("long supplemental", LONG_SUPPLEMENTAL_ENCODED, result2);
24244cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        assertEquals("long supplemental 2", LONG_SUPPLEMENTAL_ENCODED_2, result3);
24344cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    }
24444cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka
24544cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    /**
24644cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * Tests of foldAndEncode2 that involve supplemental characters (UTF-32)
24744cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     *
24844cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * Note that the difference between LONG_SUPPLEMENTAL and LONG_SUPPLEMENTAL_QP is that
24944cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     * the former will be encoded as base64 but the latter will be encoded as quoted printable.
25044cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka     */
25144cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    public void testFoldAndEncode2SupplementalQuotedPrintable() {
25244cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        String result = MimeUtility.foldAndEncode2(LONG_SUPPLEMENTAL_QP, "Subject: ".length());
25344cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka        assertEquals("long supplement quoted printable",
25444cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka                     LONG_SUPPLEMENTAL_QP_ENCODED, result);
25544cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka    }
25644cf2e2882d9d96e6f515c36334cac5ae8e2c305Tadashi Takaoka
2578aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    // TODO:  more tests for foldAndEncode2(String s)
2588aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    // TODO:  more tests for fold(String s, int usedCharacters)
2597037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
2608aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    /**
2618aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     * Basic tests of getHeaderParameter()
2627037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie     *
2638aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     * Typical header value:  multipart/mixed; boundary="----E5UGTXUQQJV80DR8SJ88F79BRA4S8K"
2647037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie     *
2658aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     * Function spec says:
2668aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     *  if header is null:  return null
2678aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     *  if name is null:    if params, return first param.  else return full field
2688aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     *  else:               if param is found (case insensitive) return it
2698aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     *                        else return null
2708aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project     */
2718aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    public void testGetHeaderParameter() {
2728aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        // if header is null, return null
2738aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        assertNull("null header check", MimeUtility.getHeaderParameter(null, "name"));
2747037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
2758aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        // if name is null, return first param or full header
2768aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        // NOTE:  The docs are wrong - it returns the header (no params) in that case
2777037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie//      assertEquals("null name first param per docs", "Param1Value",
2788aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project//              MimeUtility.getHeaderParameter(HEADER_MULTI_PARAMETER, null));
27987fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("null name first param per code", "header",
2808aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project                MimeUtility.getHeaderParameter(HEADER_MULTI_PARAMETER, null));
28187fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("null name full header", HEADER_NO_PARAMETER,
2828aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project                MimeUtility.getHeaderParameter(HEADER_NO_PARAMETER, null));
2837037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
2847037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie        // find name
28587fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("get 1st param", "Param1Value",
2868aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project                MimeUtility.getHeaderParameter(HEADER_MULTI_PARAMETER, "Param1Name"));
28787fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("get 2nd param", "Param2Value",
2888aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project                MimeUtility.getHeaderParameter(HEADER_MULTI_PARAMETER, "Param2Name"));
28987fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("get missing param", null,
2908aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project                MimeUtility.getHeaderParameter(HEADER_MULTI_PARAMETER, "Param3Name"));
2917037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
2928aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project        // case insensitivity
29387fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("get 2nd param all LC", "Param2Value",
2948aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project                MimeUtility.getHeaderParameter(HEADER_MULTI_PARAMETER, "param2name"));
29587fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("get 2nd param all UC", "Param2Value",
2968aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project                MimeUtility.getHeaderParameter(HEADER_MULTI_PARAMETER, "PARAM2NAME"));
29787fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler
29887fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        // quoting
29987fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("get 1st param", "Param1Value",
30087fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler                MimeUtility.getHeaderParameter(HEADER_QUOTED_MULTI_PARAMETER, "Param1Name"));
30187fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("get 2nd param", "Param2Value",
30287fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler                MimeUtility.getHeaderParameter(HEADER_QUOTED_MULTI_PARAMETER, "Param2Name"));
30387fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler
30487fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        // Don't fail when malformed
30587fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler        assertEquals("malformed filename param", null,
30687fcd03a1b266d3f6030347143f242b1eb524cf8Andrew Stadler                MimeUtility.getHeaderParameter(HEADER_MALFORMED_PARAMETER, "filename"));
3078aeb922462694d22f42c5890e5434e9de9dc3987The Android Open Source Project    }
3087037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
30996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    // TODO:  tests for findFirstPartByMimeType(Part part, String mimeType)
3103469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
3113469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    /** Tests for findPartByContentId(Part part, String contentId) */
3127037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie    public void brokentestCollectParts() throws MessagingException, Exception {
31339121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        // golden cases; these will marked as attachments
31439121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final String cid1 = "<i_12e8248b4f0874cb>";
31539121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final Part cid1bp = MessageTestUtils.bodyPart("image/gif; name=\"im1.gif\"", cid1);
31639121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final String cid2 = "<ii_12e8248b4f0874cb>";
31739121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final Part cid2bp = MessageTestUtils.bodyPart("image/gif", cid2);
31839121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        cid2bp.addHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "inline; filename=\"im2.gif\"");
31939121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final String cid3 = "<iii_12e8248b4f0874cb>";
32039121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final Part cid3bp = MessageTestUtils.bodyPart("image/gif", cid3);
32139121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        cid3bp.addHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "attachment; filename=\"im3.gif\"");
32239121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        // error cases; these will NOT be marked as attachments
32339121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final String cid4 = "<iv_12e8248b4f0874cb>";
32439121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final Part cid4bp = MessageTestUtils.bodyPart("image/gif", cid4);  // no name attr
32539121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final String cid5 = "<v_12e8248b4f0874cb>";
32639121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final Part cid5bp = MessageTestUtils.bodyPart("image/gif", cid5);
32739121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        cid5bp.addHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "inline"); // no filename attr
32839121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy
32939121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        // Default content disposition
33039121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> view1 = new ArrayList<Part>();
33139121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> attach1 = new ArrayList<Part>();
33239121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        MimeUtility.collectParts(cid1bp, view1, attach1);
33339121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        assertEquals(1, attach1.size());
33439121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        assertEquals(attach1.get(0), cid1bp);
33539121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy
33639121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        // Explicit content disposition of "inline"
33739121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> view2 = new ArrayList<Part>();
33839121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> attach2 = new ArrayList<Part>();
33939121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        MimeUtility.collectParts(cid2bp, view2, attach2);
34039121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        assertEquals(1, attach2.size());
34139121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        assertEquals(attach2.get(0), cid2bp);
34239121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy
34339121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        // Explicit content disposition of "attachment"
34439121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> view3 = new ArrayList<Part>();
34539121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> attach3 = new ArrayList<Part>();
34639121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        MimeUtility.collectParts(cid3bp, view3, attach3);
34739121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        assertEquals(1, attach3.size());
34839121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        assertEquals(attach3.get(0), cid3bp);
34939121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy
35039121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        // Default content disposition; missing name attribute on content-type
35139121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> view4 = new ArrayList<Part>();
35239121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> attach4 = new ArrayList<Part>();
35339121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        MimeUtility.collectParts(cid4bp, view4, attach4);
35439121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        assertEquals(0, attach4.size());
35539121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy
35639121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        // Content disposition of "inline"; missing filename attribute
35739121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> view5 = new ArrayList<Part>();
35839121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        final ArrayList<Part> attach5 = new ArrayList<Part>();
35939121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        MimeUtility.collectParts(cid5bp, view5, attach5);
36039121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy        assertEquals(0, attach5.size());
36139121c758dcc919b5fde4c893d488916e26d3140Todd Kennedy    }
3627037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
36396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /** Tests for getTextFromPart(Part part) */
36496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void testGetTextFromPartContentTypeCase() throws MessagingException {
36596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        final String theText = "This is the text of the part";
36696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        TextBody tb = new TextBody(theText);
36796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MimeBodyPart p = new MimeBodyPart();
3687037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 1. test basic text/plain mode
37096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "text/plain");
37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        p.setBody(tb);
37296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String gotText = MimeUtility.getTextFromPart(p);
37396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertEquals(theText, gotText);
3747037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
37596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 2. mixed case is OK
37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "TEXT/PLAIN");
37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        p.setBody(tb);
37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        gotText = MimeUtility.getTextFromPart(p);
37996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertEquals(theText, gotText);
3807037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
38196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 3. wildcards OK
38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "text/other");
38396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        p.setBody(tb);
38496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        gotText = MimeUtility.getTextFromPart(p);
38596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertEquals(theText, gotText);
38696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
3872517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
3882517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    /** Test for usage of Content-Type in getTextFromPart(Part part).
3897037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie     *
3902517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     * For example 'Content-Type: text/html; charset=utf-8'
3917037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie     *
3922517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *  If the body part has no mime-type, refuses to parse content as text.
3932517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *  If the mime-type does not match text/*, it will not get parsed.
3942517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *  Then, the charset parameter is used, with a default of ASCII.
3952517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *
3962517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *  This test works by using a string that is valid Unicode, and is also
3972517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *  valid when decoded from UTF-8 bytes into Windows-1252 (so that
3982517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *  auto-detection is not possible), and checks that the correct conversion
3992517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *  was made, based on the Content-Type header.
4007037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie     *
4012517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     */
4022517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    public void testContentTypeCharset() throws MessagingException {
4032517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        final String UNICODE_EXPECT = "This is some happy unicode text \u263a";
4042517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // What you get if you encode to UTF-8 (\xe2\x98\xba) and reencode with Windows-1252
4052517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        final String WINDOWS1252_EXPECT = "This is some happy unicode text \u00e2\u02dc\u00ba";
4062517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        TextBody tb = new TextBody(UNICODE_EXPECT);
4072517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        MimeBodyPart p = new MimeBodyPart();
4082517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4092517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        String gotText, mimeType, charset;
4102517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // TEST 0: Standard Content-Type header; no extraneous spaces or fields
4112517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setBody(tb);
4122517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // We call setHeader after setBody, since setBody overwrites Content-Type
4132517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "text/html; charset=utf-8");
4142517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        gotText = MimeUtility.getTextFromPart(p);
4152517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(MimeUtility.mimeTypeMatches(p.getMimeType(), "text/html"));
4162517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals(UNICODE_EXPECT, gotText);
4172517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4182517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setBody(tb);
4192517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "text/html; charset=windows-1252");
4202517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        gotText = MimeUtility.getTextFromPart(p);
4212517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(MimeUtility.mimeTypeMatches(p.getMimeType(), "text/html"));
4222517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals(WINDOWS1252_EXPECT, gotText);
4232517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4242517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // TEST 1: Extra fields and quotes in Content-Type (from RFC 2045)
4252517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setBody(tb);
4262517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
4272517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn                    "text/html; prop1 = \"test\"; charset = \"utf-8\"; prop2 = \"test\"");
4282517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        gotText = MimeUtility.getTextFromPart(p);
4292517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(MimeUtility.mimeTypeMatches(p.getMimeType(), "text/html"));
4302517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals(UNICODE_EXPECT, gotText);
4312517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4322517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setBody(tb);
4332517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
4342517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn                    "text/html; prop1 = \"test\"; charset = \"windows-1252\"; prop2 = \"test\"");
4352517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        gotText = MimeUtility.getTextFromPart(p);
4362517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(MimeUtility.mimeTypeMatches(p.getMimeType(), "text/html"));
4372517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals(WINDOWS1252_EXPECT, gotText);
4382517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4392517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // TEST 2: Mixed case in Content-Type header:
4402517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // RFC 2045 says that content types, subtypes and parameter names
4412517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // are case-insensitive.
4422517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4432517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setBody(tb);
4442517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "TEXT/HtmL ; CHARseT=utf-8");
4452517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        gotText = MimeUtility.getTextFromPart(p);
4462517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(MimeUtility.mimeTypeMatches(p.getMimeType(), "text/html"));
4472517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals(UNICODE_EXPECT, gotText);
4482517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4492517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setBody(tb);
4502517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "TEXT/HtmL ; CHARseT=windows-1252");
4512517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        gotText = MimeUtility.getTextFromPart(p);
4522517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(MimeUtility.mimeTypeMatches(p.getMimeType(), "text/html"));
4532517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals(WINDOWS1252_EXPECT, gotText);
4542517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4552517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // TEST 3: Comments in Content-Type header field (from RFC 2045)
4562517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // Thunderbird permits comments after the end of a parameter, as in this example.
4572517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // Not something that I have seen in the real world outside RFC 2045.
4582517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4592517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setBody(tb);
4602517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
4612517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn                    "text/html; charset=utf-8 (Plain text)");
4622517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        gotText = MimeUtility.getTextFromPart(p);
4632517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(MimeUtility.mimeTypeMatches(p.getMimeType(), "text/html"));
4642517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // Note: This test does not pass.
4652517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        //assertEquals(UNICODE_EXPECT, gotText);
4662517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4672517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setBody(tb);
4682517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        p.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
4692517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn                    "text/html; charset=windows-1252 (Plain text)");
4702517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        gotText = MimeUtility.getTextFromPart(p);
4712517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(MimeUtility.mimeTypeMatches(p.getMimeType(), "text/html"));
4722517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // Note: These tests does not pass.
4732517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        //assertEquals(WINDOWS1252_EXPECT, gotText);
4742517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    }
4757037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
47696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /** Tests for various aspects of mimeTypeMatches(String mimeType, String matchAgainst) */
47796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void testMimeTypeMatches() {
47896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 1. No match
47996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertFalse(MimeUtility.mimeTypeMatches("foo/bar", "TEXT/PLAIN"));
4807037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
48196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 2. Match
48296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("text/plain", "text/plain"));
4837037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
48496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 3. Match (mixed case)
48596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("text/plain", "TEXT/PLAIN"));
48696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("TEXT/PLAIN", "text/plain"));
4877037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
48896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 4. Match (wildcards)
48996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("text/plain", "*/plain"));
49096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("text/plain", "text/*"));
49196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("text/plain", "*/*"));
4927037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
49396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 5. No Match (wildcards)
49496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertFalse(MimeUtility.mimeTypeMatches("foo/bar", "*/plain"));
49596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertFalse(MimeUtility.mimeTypeMatches("foo/bar", "text/*"));
49696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
4977037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
49896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /** Tests for various aspects of mimeTypeMatches(String mimeType, String[] matchAgainst) */
49996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void testMimeTypeMatchesArray() {
50096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 1. Zero-length array
50196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String[] arrayZero = new String[0];
50296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertFalse(MimeUtility.mimeTypeMatches("text/plain", arrayZero));
5037037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
50496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 2. Single entry, no match
50596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String[] arrayOne = new String[] { "text/plain" };
50696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertFalse(MimeUtility.mimeTypeMatches("foo/bar", arrayOne));
5077037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
50896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 3. Single entry, match
50996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("text/plain", arrayOne));
5107037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
51196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 4. Multi entry, no match
51296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String[] arrayTwo = new String[] { "text/plain", "match/this" };
51396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertFalse(MimeUtility.mimeTypeMatches("foo/bar", arrayTwo));
5147037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
51596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 5. Multi entry, match first
51696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("text/plain", arrayTwo));
5177037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie
51896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // 6. Multi entry, match not first
51996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertTrue(MimeUtility.mimeTypeMatches("match/this", arrayTwo));
52096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
52196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
5227037a0bd3d8e925a9115f475f5c0d05ddae2eeeeJerry Xie    // TODO:  tests for decodeBody(InputStream in, String contentTransferEncoding)
52396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    // TODO:  tests for collectParts(Part part, ArrayList<Part> viewables, ArrayList<Part> attachments)
5243469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
52596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project}
526