17e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki/*
27e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * Copyright (C) 2010 The Android Open Source Project
37e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki *
47e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License");
57e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * you may not use this file except in compliance with the License.
67e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * You may obtain a copy of the License at
77e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki *
87e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki *      http://www.apache.org/licenses/LICENSE-2.0
97e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki *
107e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * Unless required by applicable law or agreed to in writing, software
117e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS,
127e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * See the License for the specific language governing permissions and
147e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki * limitations under the License.
157e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki */
167e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
177e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukipackage com.android.email.mail.store.imap;
187e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
197e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport static com.android.email.mail.store.imap.ImapTestUtils.assertElement;
207e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport static com.android.email.mail.store.imap.ImapTestUtils.buildList;
217e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport static com.android.email.mail.store.imap.ImapTestUtils.buildResponse;
227e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport static com.android.email.mail.store.imap.ImapTestUtils.createFixedLengthInputStream;
237e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
247e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport com.android.email.mail.store.imap.ImapResponseParser.ByeException;
257e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport com.android.email.mail.transport.DiscourseLogger;
2631d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.TempDirectory;
272193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessagingException;
2831d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.utility.Utility;
297e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
307e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport android.test.AndroidTestCase;
317e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport android.test.suitebuilder.annotation.SmallTest;
327e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
337e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport java.io.ByteArrayInputStream;
347e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukiimport java.io.IOException;
357e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
367e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki@SmallTest
377e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onukipublic class ImapResponseParserTest extends AndroidTestCase {
387e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    private static ImapResponseParser generateParser(int literalKeepInMemoryThreshold,
397e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            String responses) {
407e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        return new ImapResponseParser(new ByteArrayInputStream(Utility.toAscii(responses)),
417e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new DiscourseLogger(4), literalKeepInMemoryThreshold);
427e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
437e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
447e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    @Override
457e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    protected void setUp() throws Exception {
467e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        super.setUp();
4731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank        TempDirectory.setTempDirectory(getContext());
487e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
497e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
507e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testExpect() throws Exception {
517e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000, "abc");
527e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        p.expect('a');
537e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        p.expect('b');
547e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        try {
557e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            p.expect('C');
567e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            fail();
577e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        } catch (IOException e) {
587e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            // OK
597e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        }
607e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
617e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
627e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testreadUntil() throws Exception {
637e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000, "!ab!c!!def!");
647e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("", p.readUntil('!'));
657e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("ab", p.readUntil('!'));
667e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("c", p.readUntil('!'));
677e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("", p.readUntil('!'));
687e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("def", p.readUntil('!'));
697e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
707e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
717e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testBasic() throws Exception {
727e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
737e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000,
747e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* STATUS \"INBOX\" (UNSEEN 2)\r\n" +
757e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "100 OK STATUS completed\r\n" +
767e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "+ continuation request+(\r\n" +
777e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* STATUS {5}\r\n" +
787e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "IN%OX (UNSEEN 10) \"a b c\"\r\n" +
797e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "101 OK STATUS completed %!(\r\n" +
807e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "102 OK 1\r\n" +
817e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* 1 FETCH\r\n" +
827e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "103 OK\r\n" + // shortest OK
837e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* a\r\n" // shortest response
847e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
857e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
867e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
877e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("STATUS"),
887e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("INBOX"),
897e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                buildList(
907e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("UNSEEN"),
917e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("2")
927e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        )
937e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
947e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
957e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
967e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse("100", false,
977e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("OK"),
987e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("STATUS completed") // one string
997e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1007e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1017e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1027e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, true,
1037e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("continuation request+(") // one string
1047e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1057e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1067e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1077e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
1087e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("STATUS"),
1097e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapMemoryLiteral(createFixedLengthInputStream("IN%OX")),
1107e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                buildList(
1117e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("UNSEEN"),
1127e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("10")
1137e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        ),
1147e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("a b c")
1157e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1167e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1177e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1187e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse("101", false,
1197e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("OK"),
1207e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("STATUS completed %!(") // one string
1217e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1227e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1237e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1247e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse("102", false,
1257e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("OK"),
1267e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("1")
1277e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1287e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1297e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1307e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
1317e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("1"),
1327e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("FETCH")
1337e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1347e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1357e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1367e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse("103", false,
1377e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("OK")
1387e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1397e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1407e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1417e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
1427e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("a")
1437e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1447e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
1457e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1467e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testNil() throws Exception {
1477e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
1487e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000,
1497e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* nil nil NIL \"NIL\" {3}\r\n" +
1507e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "NIL\r\n"
1517e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
1527e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1537e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1547e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
1557e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ImapString.EMPTY,
1567e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ImapString.EMPTY,
1577e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ImapString.EMPTY,
1587e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("NIL"),
1597e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapMemoryLiteral(createFixedLengthInputStream("NIL"))
1607e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1617e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
1627e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1637e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testBareLf() throws Exception {
1647e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
1657e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1667e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        // Threshold = 3 bytes: use in memory literal.
1677e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponseParser p = generateParser(3,
1687e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* a b\n" + // Bare LF -- should be treated like CRLF
1697e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* x y\r\n"
1707e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
1717e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1727e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
1737e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("a"),
1747e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("b")
1757e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1767e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1777e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1787e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
1797e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("x"),
1807e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("y")
1817e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1827e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
1837e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1847e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testLiteral() throws Exception {
1857e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
1867e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1877e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        // Threshold = 3 bytes: use in memory literal.
1887e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponseParser p = generateParser(3,
1897e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* test {3}\r\n" +
1907e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "ABC\r\n"
1917e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
1927e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
1937e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
1947e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("test"),
1957e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapMemoryLiteral(createFixedLengthInputStream("ABC"))
1967e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
1977e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
1987e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        // Threshold = 2 bytes: use temp file literal.
1997e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        p = generateParser(2,
2007e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* test {3}\r\n" +
2017e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "ABC\r\n"
2027e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
2037e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
2047e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
2057e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("test"),
2067e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapTempFileLiteral(createFixedLengthInputStream("ABC"))
2077e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
2087e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
2097e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        // 2 literals in a line
2107e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        p = generateParser(0,
2117e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* test {3}\r\n" +
2127e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "ABC {4}\r\n" +
2137e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "wxyz\r\n"
2147e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
2157e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
2167e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
2177e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("test"),
2187e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapTempFileLiteral(createFixedLengthInputStream("ABC")),
2197e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapTempFileLiteral(createFixedLengthInputStream("wxyz"))
2207e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
2217e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
2227e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
2237e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testAlert() throws Exception {
2247e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
2257e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000,
2267e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* OK [ALERT]\r\n" + // No message
2277e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* OK [ALERT] alert ( message ) %*\r\n" +
2287e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* OK [ABC] not alert\r\n"
2297e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
2307e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
2317e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertTrue(r.isOk());
2327e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertTrue(r.getAlertTextOrEmpty().isEmpty());
2337e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
2347e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
2357e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertTrue(r.isOk());
2367e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("alert ( message ) %*", r.getAlertTextOrEmpty().getString());
2377e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
2387e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
2397e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertTrue(r.isOk());
2407e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertTrue(r.getAlertTextOrEmpty().isEmpty());
2417e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
2427e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
2437e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    /**
2447e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki     * If a [ appears in the middle of a string, the following string until the next ']' will
2457e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki     * be considered a part of the string.
2467e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki     */
2477e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testBracket() throws Exception {
2487e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
2497e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000,
2507e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* AAA BODY[HEADER.FIELDS (\"DATE\" \"SUBJECT\")]\r\n" +
2517e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* BBB B[a b c]d e f\r\n"
2527e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
2537e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
2547e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("BODY[HEADER.FIELDS (\"DATE\" \"SUBJECT\")]",
2557e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                r.getStringOrEmpty(1).getString());
2567e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
2577e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
2587e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("B[a b c]d", r.getStringOrEmpty(1).getString());
2597e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
2607e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
2617e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testNest() throws Exception {
2627e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
2637e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000,
2647e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* A (a B () DEF) (a (ab)) ((() ())) ((a) ab) ((x y ZZ) () [] [A B] (A B C))" +
2657e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                " ([abc] a[abc])\r\n"
2667e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                );
2677e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        r = p.readResponse();
2687e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertElement(buildResponse(null, false,
2697e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                new ImapSimpleString("A"),
2707e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                buildList(
2717e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("a"),
2727e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("B"),
2737e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(),
2747e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("DEF")
2757e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        ),
2767e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                buildList(
2777e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("a"),
2787e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(
2797e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("ab")
2807e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                )
2817e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        ),
2827e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                buildList(
2837e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(
2847e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                buildList(),
2857e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                buildList()
2867e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                )
2877e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        ),
2887e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                buildList(
2897e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(
2907e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("a")
2917e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                ),
2927e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("ab")
2937e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        ),
2947e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                buildList(
2957e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(
2967e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("x"),
2977e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("y"),
2987e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("ZZ")
2997e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                ),
3007e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(),
3017e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(),
3027e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(
3037e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("A"),
3047e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("B")
3057e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                ),
3067e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(
3077e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("A"),
3087e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("B"),
3097e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("C")
3107e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                )
3117e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        ),
3127e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                buildList(
3137e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        buildList(
3147e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                new ImapSimpleString("abc")
3157e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                                ),
3167e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        new ImapSimpleString("a[abc]")
3177e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                        )
3187e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                ), r);
3197e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
3207e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3217e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    /**
3227e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki     * Parser shouldn't crash for any response.  Should just throw IO/MessagingException.
3237e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki     */
3247e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testMalformedResponse() throws Exception {
3257e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("");
3267e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("\r");
3277e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("\r\n");
3287e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3297e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("*\r\n");
3307e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("1\r\n");
3317e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3327e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* \r\n");
3337e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("1 \r\n");
3347e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3357e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A (\r\n");
3367e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A )\r\n");
3377e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A (()\r\n");
3387e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A ())\r\n");
3397e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A [\r\n");
3407e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A ]\r\n");
3417e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A [[]\r\n");
3427e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A []]\r\n");
3437e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3447e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A ([)]\r\n");
3457e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3467e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* A");
3477e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* {3}");
3487e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        expectMessagingException("* {3}\r\nab");
3497e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
3507e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3517e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    private static void expectMessagingException(String response) throws Exception {
3527e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000, response);
3537e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        try {
3547e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            p.readResponse();
3557e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            fail("Didn't throw Exception: response='" + response + "'");
3567e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        } catch (MessagingException ok) {
3577e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            return;
3587e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        } catch (IOException ok) {
3597e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            return;
3607e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        }
3617e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
3627e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3637e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    // Compatibility tests...
3647e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3657e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    /**
3667e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki     * OK response with a long message that contains special chars. (including tabs)
3677e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki     */
3687e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testOkWithLongMessage() throws Exception {
3697e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
3707e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000,
3717e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* OK [CAPABILITY IMAP4 IMAP4rev1 LITERAL+ ID STARTTLS AUTH=PLAIN AUTH=LOGIN" +
3727e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "AUTH=CRAM-MD5] server.domain.tld\tCyrus IMAP4 v2.3.8-OS X Server 10.5:"
3737e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                +"  \t\t\t9F33 server ready %%\r\n");
3747e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertTrue(p.readResponse().isOk());
3757e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
3767e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3777e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    /** Make sure literals and strings are interchangeable. */
3787e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testLiteralStringConversion() throws Exception {
3797e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        ImapResponse r;
3807e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000,
3817e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* XXX {5}\r\n" +
3827e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "a b c\r\n");
3837e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        assertEquals("a b c", p.readResponse().getStringOrEmpty(1).getString());
3847e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
3857e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki
3867e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    public void testByeReceived() throws Exception {
3877e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        final ImapResponseParser p = generateParser(100000,
3887e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki                "* BYE Autologout timer; idle for too long\r\n");
3897e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        try {
3907e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            p.readResponse();
3917e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki            fail("Didn't throw ByeException");
3927e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        } catch (ByeException ok) {
3937e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki        }
3947e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki    }
3957e5ba0e1eaee76ab6e6c7ea9362348f660796596Makoto Onuki}
396