View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.imap;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.io.IOException;
26  import java.util.stream.Stream;
27  
28  import org.apache.commons.net.MalformedServerReplyException;
29  import org.junit.jupiter.api.Test;
30  import org.junit.jupiter.params.ParameterizedTest;
31  import org.junit.jupiter.params.provider.Arguments;
32  import org.junit.jupiter.params.provider.MethodSource;
33  
34  public class IMAPReplyTest {
35  
36      private static Stream<String> invalidLiteralCommands() {
37          return Stream.of(
38                  "",
39                  "{",
40                  "}",
41                  "{}",
42                  "{foobar}",
43                  "STORE +FLAGS.SILENT \\DELETED {",
44                  "STORE +FLAGS.SILENT \\DELETED }",
45                  "STORE +FLAGS.SILENT \\DELETED {-1}",
46                  "STORE +FLAGS.SILENT \\DELETED {-10}",
47                  "STORE +FLAGS.SILENT \\DELETED {-2147483648}"
48          );
49      }
50  
51      private static Stream<Arguments> literalCommands() {
52          return Stream.of(
53                  Arguments.of(310, "A003 APPEND saved-messages (\\Seen) {310}"),
54                  Arguments.of(6, "A284 SEARCH CHARSET UTF-8 TEXT {6}"),
55                  Arguments.of(7, "FRED FOOBAR {7}"),
56                  Arguments.of(102856, "A044 BLURDYBLOOP {102856}"),
57                  Arguments.of(342, "* 12 FETCH (BODY[HEADER] {342}"),
58                  Arguments.of(0, "X999 LOGIN {0}"),
59                  Arguments.of(Integer.MAX_VALUE, "X999 LOGIN {2147483647}")
60          );
61      }
62  
63      @ParameterizedTest(name = "reply line `{1}` contains literal {0}")
64      @MethodSource("literalCommands")
65      public void literalCount(final int expectedLiteral, final String replyLine) {
66          assertEquals(expectedLiteral, IMAPReply.literalCount(replyLine));
67      }
68  
69      @ParameterizedTest(name = "reply line `{0}` does not contain any literal")
70      @MethodSource("invalidLiteralCommands")
71      public void literalCountInvalid(final String replyLine) {
72          assertEquals(-1, IMAPReply.literalCount(replyLine));
73      }
74  
75      @Test
76      public void testGetReplyCodeBadLine() throws IOException {
77          final String badLine = "A044 BAD No such command as \"FOOBAR\"";
78          assertEquals(IMAPReply.BAD, IMAPReply.getReplyCode(badLine));
79      }
80  
81      @Test
82      public void testGetReplyCodeContinuationLine() throws IOException {
83          final String continuationLine = "+ Ready for additional command text";
84          assertEquals(IMAPReply.CONT, IMAPReply.getReplyCode(continuationLine));
85      }
86  
87      @Test
88      public void testGetReplyCodeMalformedLine() {
89          final String malformedTaggedLine = "A064 FOO-BAR 0";
90          final MalformedServerReplyException replyException = assertThrows(MalformedServerReplyException.class,
91                  () -> IMAPReply.getReplyCode(malformedTaggedLine));
92          assertEquals("Received unexpected IMAP protocol response from server: 'A064 FOO-BAR 0'.", replyException.getMessage());
93      }
94  
95      @Test
96      public void testGetReplyCodeNoLine() throws IOException {
97          final String noLine = "A223 NO COPY failed: disk is full";
98          assertEquals(IMAPReply.NO, IMAPReply.getReplyCode(noLine));
99      }
100 
101     @Test
102     public void testGetReplyCodeOkLine() throws IOException {
103         assertEquals(IMAPReply.OK, IMAPReply.getReplyCode("A001 OK LOGIN completed"));
104         assertEquals(IMAPReply.OK, IMAPReply.getReplyCode("AAAA OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT"
105                 + " SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT" + " MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS"
106                 + " LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN"
107                 + " CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY PREVIEW"
108                 + " STATUS=SIZE SAVEDATE XLIST LITERAL+ NOTIFY SPECIAL-USE] Logged in"));
109         // [NET-734] IMAP login fails with 3.11.1
110         assertEquals(IMAPReply.OK, IMAPReply.getReplyCode(
111                 "CBJJ OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ENABLE IDLE ID SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT"
112                         + " MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT"
113                         + " SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE STATUS=SIZE SAVEDATE LITERAL+ QUOTA] Logged in"));
114     }
115 
116     @Test
117     public void testGetUntaggedReplyCodeBadLine() throws IOException {
118         final String badLine = "* BAD Empty command line";
119         assertEquals(IMAPReply.BAD, IMAPReply.getUntaggedReplyCode(badLine));
120     }
121 
122     @Test
123     public void testGetUntaggedReplyCodeContinuationLine() throws IOException {
124         final String continuationLine = "+ Ready for additional command text";
125         assertEquals(IMAPReply.CONT, IMAPReply.getUntaggedReplyCode(continuationLine));
126     }
127 
128     @Test
129     public void testGetUntaggedReplyCodeMalformedLine() {
130         // invalid experimental comm response (missing X prefix)
131         final String malformedUntaggedLine = "* FOO-BAR hello-world";
132         final MalformedServerReplyException replyException = assertThrows(MalformedServerReplyException.class,
133                 () -> IMAPReply.getUntaggedReplyCode(malformedUntaggedLine));
134         assertEquals("Received unexpected IMAP protocol response from server: '* FOO-BAR hello-world'.", replyException.getMessage());
135     }
136 
137     @Test
138     public void testGetUntaggedReplyCodeNoLine() throws IOException {
139         final String noLine = "* NO Disk is 98% full, please delete unnecessary data";
140         assertEquals(IMAPReply.NO, IMAPReply.getUntaggedReplyCode(noLine));
141     }
142 
143     @Test
144     public void testGetUntaggedReplyCodeOkLine() throws IOException {
145         assertEquals(IMAPReply.OK, IMAPReply.getUntaggedReplyCode("* OK Salvage successful, no data lost"));
146         assertEquals(IMAPReply.OK,
147                 IMAPReply.getUntaggedReplyCode("* OK The Microsoft Exchange IMAP4 service is ready. [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]"));
148         assertEquals(IMAPReply.OK, IMAPReply.getUntaggedReplyCode("* OK The Microsoft Exchange IMAP4 service is ready. " +
149                 "[TQBXADIAUABSADIAMQAwADEAQwBBADAAMAAzADYALgBuAGEAbQBwAHIAZAAyADEALgBwAHIAbwBkAC4AbwB1AHQAbABvAG8AawAuAGMAbwBtAA==]"));
150     }
151 
152     @Test
153     public void testIsContinuationReplyCode() {
154         final int replyCode = 3;
155         assertTrue(IMAPReply.isContinuation(replyCode));
156     }
157 
158     @Test
159     public void testIsContinuationReplyCodeInvalidCode() {
160         final int invalidContinuationReplyCode = 1;
161         assertFalse(IMAPReply.isContinuation(invalidContinuationReplyCode));
162     }
163 
164     @Test
165     public void testIsContinuationReplyLine() {
166         final String replyLine = "+FLAGS completed";
167         assertTrue(IMAPReply.isContinuation(replyLine));
168     }
169 
170     @Test
171     public void testIsContinuationReplyLineInvalidLine() {
172         final String invalidContinuationReplyLine = "* 22 EXPUNGE";
173         assertFalse(IMAPReply.isContinuation(invalidContinuationReplyLine));
174     }
175 
176     @Test
177     public void testIsSuccessReplyCode() {
178         final int successfulReplyCode = 0;
179         assertTrue(IMAPReply.isSuccess(successfulReplyCode));
180     }
181 
182     @Test
183     public void testIsSuccessReplyCodeUnsuccessfulCode() {
184         final int unsuccessfulReplyCode = 2;
185         assertFalse(IMAPReply.isSuccess(unsuccessfulReplyCode));
186     }
187 
188     @Test
189     public void testIsUntaggedReplyLine() {
190         final String replyLine = "* 18 EXISTS";
191         assertTrue(IMAPReply.isUntagged(replyLine));
192     }
193 
194     @Test
195     public void testIsUntaggedReplyLineInvalidLine() {
196         final String taggedLine = "a001 OK LOGOUT completed";
197         assertFalse(IMAPReply.isUntagged(taggedLine));
198     }
199 
200 }