3434import static org .hamcrest .Matchers .*;
3535
3636import java .io .IOException ;
37+ import java .io .InputStream ;
38+ import java .io .InputStreamReader ;
39+ import java .io .Reader ;
3740import java .util .HashMap ;
3841import java .util .Map ;
3942import java .util .UUID ;
5356import com .google .common .collect .ObjectArrays ;
5457
5558/**
56- * Integration test for POP3
59+ * Integration test for POP3.
60+ *
61+ * Some parts of these code are taken from Apache JAMES Protocols project.
5762 *
5863 * @author Rustam Aliyev
5964 */
@@ -240,10 +245,10 @@ public void testRset() throws IOException
240245 info = client .listMessages ();
241246 assertThat (info .length , equalTo (0 ));
242247
243- // RSET. After this the deleted mark should be removed again
244- boolean resetRestult = client .reset ();
248+ // RSET. After this the deleted mark should be removed again
249+ boolean resetRestult = client .reset ();
245250 assertThat (resetRestult , is (true ));
246-
251+
247252 // LIST all messages
248253 info = client .listMessages ();
249254 assertThat (info .length , equalTo (1 ));
@@ -252,4 +257,232 @@ public void testRset() throws IOException
252257 boolean logoutSuccess = client .logout ();
253258 assertThat (logoutSuccess , is (true ));
254259 }
260+
261+ @ Test
262+ public void testStat () throws IOException
263+ {
264+ initAccount ();
265+
266+ // load messages with POP3 label
267+ long mailSizeRegular = getResourceSize (EMAIL_REGULAR );
268+ long mailSizeAttach = getResourceSize (EMAIL_LARGE_ATT );
269+
270+ Integer labelId = ReservedLabels .POP3 .getId ();
271+ RestV2IT .addMessage (EMAIL_REGULAR , labelId );
272+ RestV2IT .addMessage (EMAIL_LARGE_ATT , labelId );
273+
274+ // initialize POP3 client
275+ POP3Client client = new POP3Client ();
276+ client .connect (POP3_HOST , POP3_PORT );
277+
278+ boolean loginSuccess = client .login (TEST_ACCOUNT , "valid" );
279+ assertThat (loginSuccess , is (true ));
280+
281+ POP3MessageInfo info = client .status ();
282+ assertThat (info .size , equalTo ((int ) (mailSizeRegular + mailSizeAttach )));
283+ assertThat (info .number , equalTo (2 ));
284+
285+ // Logout
286+ boolean logoutSuccess = client .logout ();
287+ assertThat (logoutSuccess , is (true ));
288+ }
289+
290+ @ Test
291+ public void testRetr () throws IOException
292+ {
293+ initAccount ();
294+
295+ Integer labelId = ReservedLabels .POP3 .getId ();
296+ RestV2IT .addMessage (EMAIL_SIMPLE , labelId );
297+
298+ // initialize POP3 client
299+ POP3Client client = new POP3Client ();
300+ client .connect (POP3_HOST , POP3_PORT );
301+
302+ // Login
303+ boolean loginSuccess = client .login (TEST_ACCOUNT , "valid" );
304+ assertThat (loginSuccess , is (true ));
305+
306+ // RETR message
307+ Reader retrMessage = client .retrieveMessage (1 );
308+ assertThat (retrMessage , notNullValue ());
309+
310+ checkMessage (EMAIL_SIMPLE , retrMessage );
311+ retrMessage .close ();
312+
313+ // RETR non-existing message
314+ retrMessage = client .retrieveMessage (10 );
315+ assertThat (retrMessage , nullValue ());
316+
317+ // Delete and RETR the message again
318+ boolean deleteResult = client .deleteMessage (1 );
319+ assertThat (deleteResult , is (true ));
320+
321+ retrMessage = client .retrieveMessage (1 );
322+ assertThat (retrMessage , nullValue ());
323+ }
324+
325+ @ Test
326+ public void testTop () throws IOException
327+ {
328+ initAccount ();
329+
330+ Integer labelId = ReservedLabels .POP3 .getId ();
331+ RestV2IT .addMessage (EMAIL_SIMPLE , labelId );
332+
333+ // initialize POP3 client
334+ POP3Client client = new POP3Client ();
335+ client .connect (POP3_HOST , POP3_PORT );
336+
337+ // Login
338+ boolean loginSuccess = client .login (TEST_ACCOUNT , "valid" );
339+ assertThat (loginSuccess , is (true ));
340+
341+ // TOP message with all lines
342+ Reader topMessage = client .retrieveMessageTop (1 , 1000 );
343+ assertThat (topMessage , notNullValue ());
344+ checkMessage (EMAIL_SIMPLE , topMessage );
345+ topMessage .close ();
346+
347+ // TOP message with 5 lines
348+ topMessage = client .retrieveMessageTop (1 , 5 );
349+ assertThat (topMessage , notNullValue ());
350+ checkMessage (EMAIL_SIMPLE , topMessage , 5 );
351+ topMessage .close ();
352+
353+ // TOP non-existing message
354+ topMessage = client .retrieveMessageTop (10 , 10 );
355+ assertThat (topMessage , nullValue ());
356+
357+ // Delete and TOP the message again
358+ boolean deleteResult = client .deleteMessage (1 );
359+ assertThat (deleteResult , is (true ));
360+
361+ topMessage = client .retrieveMessageTop (1 , 1000 );
362+ assertThat (topMessage , nullValue ());
363+ }
364+
365+ private void checkMessage (String message , Reader reader ) throws IOException {
366+ checkMessage (message , reader , null );
367+ }
368+
369+ private void checkMessage (String message , Reader reader , Integer limit ) throws IOException
370+ {
371+ Reader orig ;
372+
373+ if (limit != null ) {
374+ orig = new InputStreamReader (new CountingBodyInputStream (
375+ this .getClass ().getResourceAsStream (message ), limit ), "US-ASCII" );
376+ } else {
377+ orig = new InputStreamReader (this .getClass ().getResourceAsStream (message ), "US-ASCII" );
378+ }
379+
380+ int i = -1 ;
381+ int j = -1 ;
382+
383+ while (((i = reader .read ()) != -1 ) && ((j = orig .read ()) != -1 )) {
384+ assertThat (j , equalTo (i ));
385+ }
386+
387+ // read final byte and assert
388+ j = orig .read ();
389+ assertThat (j , equalTo (i ));
390+
391+ orig .close ();
392+ }
393+
394+ /**
395+ * This {@link InputStream} implementation can be used to return all message
396+ * headers and limit the body lines which will be read from the wrapped
397+ * {@link InputStream}.
398+ */
399+ private final class CountingBodyInputStream extends InputStream
400+ {
401+ private int count = 0 ;
402+ private int limit = -1 ;
403+ private int lastChar ;
404+ private InputStream in ;
405+ private boolean isBody = false ; // starting from header
406+ private boolean isEmptyLine = false ;
407+
408+ /**
409+ *
410+ * @param in
411+ * InputStream to read from
412+ * @param limit
413+ * the lines to read. -1 is used for no limits
414+ */
415+ public CountingBodyInputStream (InputStream in , int limit ) {
416+ this .in = in ;
417+ this .limit = limit ;
418+ }
419+
420+ @ Override
421+ public int read () throws IOException
422+ {
423+ if (limit != -1 ) {
424+ if (count <= limit ) {
425+ int a = in .read ();
426+
427+ // check for empty line
428+ if (!isBody && isEmptyLine && lastChar == '\r' && a == '\n' ) {
429+ // reached body
430+ isBody = true ;
431+ }
432+
433+ if (lastChar == '\r' && a == '\n' ) {
434+ // reset empty line flag
435+ isEmptyLine = true ;
436+
437+ if (isBody ) {
438+ count ++;
439+ }
440+ } else if (lastChar == '\n' && a != '\r' ) {
441+ isEmptyLine = false ;
442+ }
443+
444+ lastChar = a ;
445+
446+ return a ;
447+ } else {
448+ return -1 ;
449+ }
450+ } else {
451+ return in .read ();
452+ }
453+
454+ }
455+
456+ @ Override
457+ public long skip (long n ) throws IOException {
458+ return in .skip (n );
459+ }
460+
461+ @ Override
462+ public int available () throws IOException {
463+ return in .available ();
464+ }
465+
466+ @ Override
467+ public void close () throws IOException {
468+ in .close ();
469+ }
470+
471+ @ Override
472+ public void mark (int readlimit ) {
473+ // not supported
474+ }
475+
476+ @ Override
477+ public void reset () throws IOException {
478+ // do nothing as mark is not supported
479+ }
480+
481+ @ Override
482+ public boolean markSupported () {
483+ return false ;
484+ }
485+
486+ }
487+
255488}
0 commit comments