• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.email.mail.store.imap;
18 
19 import static com.android.email.mail.store.imap.ImapTestUtils.assertElement;
20 import static com.android.email.mail.store.imap.ImapTestUtils.buildList;
21 import static com.android.email.mail.store.imap.ImapTestUtils.buildResponse;
22 import static com.android.email.mail.store.imap.ImapTestUtils.createFixedLengthInputStream;
23 
24 import com.android.email.mail.store.imap.ImapResponseParser.ByeException;
25 import com.android.email.mail.transport.DiscourseLogger;
26 import com.android.emailcommon.TempDirectory;
27 import com.android.emailcommon.mail.MessagingException;
28 import com.android.emailcommon.utility.Utility;
29 
30 import android.test.AndroidTestCase;
31 import android.test.suitebuilder.annotation.SmallTest;
32 
33 import java.io.ByteArrayInputStream;
34 import java.io.IOException;
35 
36 @SmallTest
37 public class ImapResponseParserTest extends AndroidTestCase {
generateParser(int literalKeepInMemoryThreshold, String responses)38     private static ImapResponseParser generateParser(int literalKeepInMemoryThreshold,
39             String responses) {
40         return new ImapResponseParser(new ByteArrayInputStream(Utility.toAscii(responses)),
41                 new DiscourseLogger(4), literalKeepInMemoryThreshold);
42     }
43 
44     @Override
setUp()45     protected void setUp() throws Exception {
46         super.setUp();
47         TempDirectory.setTempDirectory(getContext());
48     }
49 
testExpect()50     public void testExpect() throws Exception {
51         final ImapResponseParser p = generateParser(100000, "abc");
52         p.expect('a');
53         p.expect('b');
54         try {
55             p.expect('C');
56             fail();
57         } catch (IOException e) {
58             // OK
59         }
60     }
61 
testreadUntil()62     public void testreadUntil() throws Exception {
63         final ImapResponseParser p = generateParser(100000, "!ab!c!!def!");
64         assertEquals("", p.readUntil('!'));
65         assertEquals("ab", p.readUntil('!'));
66         assertEquals("c", p.readUntil('!'));
67         assertEquals("", p.readUntil('!'));
68         assertEquals("def", p.readUntil('!'));
69     }
70 
testBasic()71     public void testBasic() throws Exception {
72         ImapResponse r;
73         final ImapResponseParser p = generateParser(100000,
74                 "* STATUS \"INBOX\" (UNSEEN 2)\r\n" +
75                 "100 OK STATUS completed\r\n" +
76                 "+ continuation request+(\r\n" +
77                 "* STATUS {5}\r\n" +
78                 "IN%OX (UNSEEN 10) \"a b c\"\r\n" +
79                 "101 OK STATUS completed %!(\r\n" +
80                 "102 OK 1\r\n" +
81                 "* 1 FETCH\r\n" +
82                 "103 OK\r\n" + // shortest OK
83                 "* a\r\n" // shortest response
84                 );
85         r = p.readResponse();
86         assertElement(buildResponse(null, false,
87                 new ImapSimpleString("STATUS"),
88                 new ImapSimpleString("INBOX"),
89                 buildList(
90                         new ImapSimpleString("UNSEEN"),
91                         new ImapSimpleString("2")
92                         )
93                 ), r);
94 
95         r = p.readResponse();
96         assertElement(buildResponse("100", false,
97                 new ImapSimpleString("OK"),
98                 new ImapSimpleString("STATUS completed") // one string
99                 ), r);
100 
101         r = p.readResponse();
102         assertElement(buildResponse(null, true,
103                 new ImapSimpleString("continuation request+(") // one string
104                 ), r);
105 
106         r = p.readResponse();
107         assertElement(buildResponse(null, false,
108                 new ImapSimpleString("STATUS"),
109                 new ImapMemoryLiteral(createFixedLengthInputStream("IN%OX")),
110                 buildList(
111                         new ImapSimpleString("UNSEEN"),
112                         new ImapSimpleString("10")
113                         ),
114                 new ImapSimpleString("a b c")
115                 ), r);
116 
117         r = p.readResponse();
118         assertElement(buildResponse("101", false,
119                 new ImapSimpleString("OK"),
120                 new ImapSimpleString("STATUS completed %!(") // one string
121                 ), r);
122 
123         r = p.readResponse();
124         assertElement(buildResponse("102", false,
125                 new ImapSimpleString("OK"),
126                 new ImapSimpleString("1")
127                 ), r);
128 
129         r = p.readResponse();
130         assertElement(buildResponse(null, false,
131                 new ImapSimpleString("1"),
132                 new ImapSimpleString("FETCH")
133                 ), r);
134 
135         r = p.readResponse();
136         assertElement(buildResponse("103", false,
137                 new ImapSimpleString("OK")
138                 ), r);
139 
140         r = p.readResponse();
141         assertElement(buildResponse(null, false,
142                 new ImapSimpleString("a")
143                 ), r);
144     }
145 
testNil()146     public void testNil() throws Exception {
147         ImapResponse r;
148         final ImapResponseParser p = generateParser(100000,
149                 "* nil nil NIL \"NIL\" {3}\r\n" +
150                 "NIL\r\n"
151                 );
152 
153         r = p.readResponse();
154         assertElement(buildResponse(null, false,
155                 ImapString.EMPTY,
156                 ImapString.EMPTY,
157                 ImapString.EMPTY,
158                 new ImapSimpleString("NIL"),
159                 new ImapMemoryLiteral(createFixedLengthInputStream("NIL"))
160                 ), r);
161     }
162 
testBareLf()163     public void testBareLf() throws Exception {
164         ImapResponse r;
165 
166         // Threshold = 3 bytes: use in memory literal.
167         ImapResponseParser p = generateParser(3,
168                 "* a b\n" + // Bare LF -- should be treated like CRLF
169                 "* x y\r\n"
170                 );
171         r = p.readResponse();
172         assertElement(buildResponse(null, false,
173                 new ImapSimpleString("a"),
174                 new ImapSimpleString("b")
175                 ), r);
176 
177         r = p.readResponse();
178         assertElement(buildResponse(null, false,
179                 new ImapSimpleString("x"),
180                 new ImapSimpleString("y")
181                 ), r);
182     }
183 
testLiteral()184     public void testLiteral() throws Exception {
185         ImapResponse r;
186 
187         // Threshold = 3 bytes: use in memory literal.
188         ImapResponseParser p = generateParser(3,
189                 "* test {3}\r\n" +
190                 "ABC\r\n"
191                 );
192         r = p.readResponse();
193         assertElement(buildResponse(null, false,
194                 new ImapSimpleString("test"),
195                 new ImapMemoryLiteral(createFixedLengthInputStream("ABC"))
196                 ), r);
197 
198         // Threshold = 2 bytes: use temp file literal.
199         p = generateParser(2,
200                 "* test {3}\r\n" +
201                 "ABC\r\n"
202                 );
203         r = p.readResponse();
204         assertElement(buildResponse(null, false,
205                 new ImapSimpleString("test"),
206                 new ImapTempFileLiteral(createFixedLengthInputStream("ABC"))
207                 ), r);
208 
209         // 2 literals in a line
210         p = generateParser(0,
211                 "* test {3}\r\n" +
212                 "ABC {4}\r\n" +
213                 "wxyz\r\n"
214                 );
215         r = p.readResponse();
216         assertElement(buildResponse(null, false,
217                 new ImapSimpleString("test"),
218                 new ImapTempFileLiteral(createFixedLengthInputStream("ABC")),
219                 new ImapTempFileLiteral(createFixedLengthInputStream("wxyz"))
220                 ), r);
221     }
222 
testAlert()223     public void testAlert() throws Exception {
224         ImapResponse r;
225         final ImapResponseParser p = generateParser(100000,
226                 "* OK [ALERT]\r\n" + // No message
227                 "* OK [ALERT] alert ( message ) %*\r\n" +
228                 "* OK [ABC] not alert\r\n"
229                 );
230         r = p.readResponse();
231         assertTrue(r.isOk());
232         assertTrue(r.getAlertTextOrEmpty().isEmpty());
233 
234         r = p.readResponse();
235         assertTrue(r.isOk());
236         assertEquals("alert ( message ) %*", r.getAlertTextOrEmpty().getString());
237 
238         r = p.readResponse();
239         assertTrue(r.isOk());
240         assertTrue(r.getAlertTextOrEmpty().isEmpty());
241     }
242 
243     /**
244      * If a [ appears in the middle of a string, the following string until the next ']' will
245      * be considered a part of the string.
246      */
testBracket()247     public void testBracket() throws Exception {
248         ImapResponse r;
249         final ImapResponseParser p = generateParser(100000,
250                 "* AAA BODY[HEADER.FIELDS (\"DATE\" \"SUBJECT\")]\r\n" +
251                 "* BBB B[a b c]d e f\r\n"
252                 );
253         r = p.readResponse();
254         assertEquals("BODY[HEADER.FIELDS (\"DATE\" \"SUBJECT\")]",
255                 r.getStringOrEmpty(1).getString());
256 
257         r = p.readResponse();
258         assertEquals("B[a b c]d", r.getStringOrEmpty(1).getString());
259     }
260 
testNest()261     public void testNest() throws Exception {
262         ImapResponse r;
263         final ImapResponseParser p = generateParser(100000,
264                 "* A (a B () DEF) (a (ab)) ((() ())) ((a) ab) ((x y ZZ) () [] [A B] (A B C))" +
265                 " ([abc] a[abc])\r\n"
266                 );
267         r = p.readResponse();
268         assertElement(buildResponse(null, false,
269                 new ImapSimpleString("A"),
270                 buildList(
271                         new ImapSimpleString("a"),
272                         new ImapSimpleString("B"),
273                         buildList(),
274                         new ImapSimpleString("DEF")
275                         ),
276                 buildList(
277                         new ImapSimpleString("a"),
278                         buildList(
279                                 new ImapSimpleString("ab")
280                                 )
281                         ),
282                 buildList(
283                         buildList(
284                                 buildList(),
285                                 buildList()
286                                 )
287                         ),
288                 buildList(
289                         buildList(
290                                 new ImapSimpleString("a")
291                                 ),
292                         new ImapSimpleString("ab")
293                         ),
294                 buildList(
295                         buildList(
296                                 new ImapSimpleString("x"),
297                                 new ImapSimpleString("y"),
298                                 new ImapSimpleString("ZZ")
299                                 ),
300                         buildList(),
301                         buildList(),
302                         buildList(
303                                 new ImapSimpleString("A"),
304                                 new ImapSimpleString("B")
305                                 ),
306                         buildList(
307                                 new ImapSimpleString("A"),
308                                 new ImapSimpleString("B"),
309                                 new ImapSimpleString("C")
310                                 )
311                         ),
312                 buildList(
313                         buildList(
314                                 new ImapSimpleString("abc")
315                                 ),
316                         new ImapSimpleString("a[abc]")
317                         )
318                 ), r);
319     }
320 
321     /**
322      * Parser shouldn't crash for any response.  Should just throw IO/MessagingException.
323      */
testMalformedResponse()324     public void testMalformedResponse() throws Exception {
325         expectMessagingException("");
326         expectMessagingException("\r");
327         expectMessagingException("\r\n");
328 
329         expectMessagingException("*\r\n");
330         expectMessagingException("1\r\n");
331 
332         expectMessagingException("* \r\n");
333         expectMessagingException("1 \r\n");
334 
335         expectMessagingException("* A (\r\n");
336         expectMessagingException("* A )\r\n");
337         expectMessagingException("* A (()\r\n");
338         expectMessagingException("* A ())\r\n");
339         expectMessagingException("* A [\r\n");
340         expectMessagingException("* A ]\r\n");
341         expectMessagingException("* A [[]\r\n");
342         expectMessagingException("* A []]\r\n");
343 
344         expectMessagingException("* A ([)]\r\n");
345 
346         expectMessagingException("* A");
347         expectMessagingException("* {3}");
348         expectMessagingException("* {3}\r\nab");
349     }
350 
expectMessagingException(String response)351     private static void expectMessagingException(String response) throws Exception {
352         final ImapResponseParser p = generateParser(100000, response);
353         try {
354             p.readResponse();
355             fail("Didn't throw Exception: response='" + response + "'");
356         } catch (MessagingException ok) {
357             return;
358         } catch (IOException ok) {
359             return;
360         }
361     }
362 
363     // Compatibility tests...
364 
365     /**
366      * OK response with a long message that contains special chars. (including tabs)
367      */
testOkWithLongMessage()368     public void testOkWithLongMessage() throws Exception {
369         ImapResponse r;
370         final ImapResponseParser p = generateParser(100000,
371                 "* OK [CAPABILITY IMAP4 IMAP4rev1 LITERAL+ ID STARTTLS AUTH=PLAIN AUTH=LOGIN" +
372                 "AUTH=CRAM-MD5] server.domain.tld\tCyrus IMAP4 v2.3.8-OS X Server 10.5:"
373                 +"  \t\t\t9F33 server ready %%\r\n");
374         assertTrue(p.readResponse().isOk());
375     }
376 
377     /** Make sure literals and strings are interchangeable. */
testLiteralStringConversion()378     public void testLiteralStringConversion() throws Exception {
379         ImapResponse r;
380         final ImapResponseParser p = generateParser(100000,
381                 "* XXX {5}\r\n" +
382                 "a b c\r\n");
383         assertEquals("a b c", p.readResponse().getStringOrEmpty(1).getString());
384     }
385 
testByeReceived()386     public void testByeReceived() throws Exception {
387         final ImapResponseParser p = generateParser(100000,
388                 "* BYE Autologout timer; idle for too long\r\n");
389         try {
390             p.readResponse();
391             fail("Didn't throw ByeException");
392         } catch (ByeException ok) {
393         }
394     }
395 }
396