/*
* Copyright (c) 2011-2012 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.service.email;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import org.jmock.Expectations;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Before;
import org.junit.Test;
/**
* Tests MessageContentExtractor.
*/
public class MessageContentExtractorTest
{
/** Test data. */
private static final String BASIC_MARKER = "\r\nFrom: ";
/** Test data. */
private static final String REGEX_MARKER = "\r\n-+\\s*Original Message\\s*-+\r\n";
/** Test data. */
private static final String TEXT_TO_FIND = "This is the text to find.";
/** Used for mocking objects. */
private final JUnit4Mockery context = new JUnit4Mockery()
{
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/** Used for making unique mock names. */
private int uniqueIndex = 0;
/** SUT. */
private MessageContentExtractor sut;
/**
* Helper method: builds a multipart email part.
*
* @param topLevel
* If part should be a Message.
* @param parts
* Child parts to include.
* @return Multipart part.
* @throws MessagingException
* Won't.
* @throws IOException
* Won't.
*/
private Part makeMultipart(final boolean topLevel, final Part... parts) throws MessagingException, IOException
{
final Part bp = context.mock((topLevel ? Message.class : BodyPart.class), "BodyPart-" + (++uniqueIndex));
final Multipart mp = new Multipart()
{
@Override
public void writeTo(final OutputStream inOs) throws IOException, MessagingException
{
}
};
context.checking(new Expectations()
{
{
allowing(bp).getDisposition();
will(returnValue(null));
allowing(bp).getContentType();
will(returnValue("multipart/alternative;\r\nboundary=something"));
allowing(bp).getContent();
will(returnValue(mp));
}
});
for (int i = 0; i < parts.length; i++)
{
mp.addBodyPart((BodyPart) parts[i]);
}
return bp;
}
/**
* Helper method: builds a content email part.
*
* @param type
* MIME type string.
* @param isAttachment
* If part holds an attachment (vs inline content).
* @param content
* The content.
* @return The part.
* @throws MessagingException
* Won't.
* @throws IOException
* Won't.
*/
private Part makeContentPart(final String type, final boolean isAttachment, final Object content)
throws MessagingException, IOException
{
final Part bp = context.mock(BodyPart.class, "BodyPart-" + (++uniqueIndex));
context.checking(new Expectations()
{
{
allowing(bp).getDisposition();
will(returnValue(isAttachment ? "attachment" : null));
allowing(bp).getContentType();
will(returnValue(type));
allowing(bp).getContent();
will(returnValue(content));
}
});
return bp;
}
/**
* Setup before each test.
*/
@Before
public void setUp()
{
}
/**
* Tests a successful search and parse.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testSuccess() throws MessagingException, IOException
{
sut = new MessageContentExtractor(Collections.singletonList(BASIC_MARKER), null);
Message msg = (Message) makeMultipart(
true,
makeContentPart("text/plain", true, "Not this"),
makeContentPart("text/plain", false, " \t\r\n \t \r\nFrom: blah"),
makeMultipart(
false,
makeContentPart("text/plain", true, ""),
makeContentPart("image/png", false, new byte[12]),
makeContentPart("text/plain", true, "From: xyz"),
makeMultipart(false, makeContentPart("text/html", false, "<head></head>"),
makeContentPart("text/plain", false, TEXT_TO_FIND)),
makeContentPart("text/plain", false, "Not this")),
makeContentPart("text/plain", false, "Not this either"),
makeContentPart("text/html", false, "<p>Not this</p>"));
String result = sut.extract(msg);
context.assertIsSatisfied();
assertEquals(TEXT_TO_FIND, result);
}
/**
* Tests a search and parse yielding no applicable content.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testNoneFound() throws MessagingException, IOException
{
sut = new MessageContentExtractor(Collections.singletonList(BASIC_MARKER), null);
Message msg = (Message) makeMultipart(
true,
makeContentPart("text/plain", true, "Not this"),
makeContentPart("text/plain", false, " \t\r\n \t \r\nFrom: blah"),
makeMultipart(false, makeContentPart("text/plain", true, ""),
makeContentPart("image/png", false, new byte[12]),
makeContentPart("text/plain", true, "From: xyz"),
makeMultipart(false, makeContentPart("text/html", false, "<head></head>"))),
makeContentPart("text/html", false, "<p>Not this</p>"));
String result = sut.extract(msg);
context.assertIsSatisfied();
assertNull(result);
}
/**
* Tests parsing: 'From' must be at start of line to be a header.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testParse1() throws MessagingException, IOException
{
sut = new MessageContentExtractor(Collections.singletonList(BASIC_MARKER), null);
Message msg = (Message) makeMultipart(
true,
makeContentPart("text/plain", false,
" From: A\r\n\tFrom: B\r\n \t\t From: C\r\n\r\n From: D\r\nFrom: E"));
String result = sut.extract(msg);
context.assertIsSatisfied();
assertEquals("From: A\r\n\tFrom: B\r\n \t\t From: C\r\n\r\n From: D", result);
}
/**
* Tests parsing: "Original Message" check.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testParse2() throws MessagingException, IOException
{
sut = new MessageContentExtractor(Collections.singletonList(BASIC_MARKER),
Collections.singletonList(REGEX_MARKER));
Message msg = (Message) makeMultipart(
true,
makeContentPart("text/plain", false,
" From: A\r\n\tFrom: B\r\n-----Original Message-----\r\nFrom: C\r\n\r\n From: D\r\nFrom: E"));
String result = sut.extract(msg);
context.assertIsSatisfied();
assertEquals("From: A\r\n\tFrom: B", result);
}
/**
* Common parts of several parsing tests.
*
* @param input
* String to parse.
* @param expected
* Expected extraction.
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
private void commonParseTest(final String input, final String expected) throws MessagingException, IOException
{
sut = new MessageContentExtractor(Arrays.asList("abc", "def"), Arrays.asList("\\d+", "mo+"));
Message msg = (Message) makeMultipart(true, makeContentPart("text/plain", false, input));
String result = sut.extract(msg);
context.assertIsSatisfied();
assertEquals(expected, result);
}
/**
* Tests parsing.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testParse3() throws MessagingException, IOException
{
commonParseTest("asdf jklabcghi111", "asdf jkl");
}
/**
* Tests parsing.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testParse4() throws MessagingException, IOException
{
commonParseTest("asdf MOOOOjklabcghi111", "asdf");
}
/**
* Tests parsing.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testParse5() throws MessagingException, IOException
{
commonParseTest("asdf jdefklabcghi111mo", "asdf j");
}
/**
* Tests parsing.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testParse6() throws MessagingException, IOException
{
commonParseTest("asdf jklabbcghi@@", "asdf jklabbcghi@@");
}
/**
* Tests null lists.
*
* @throws IOException
* Won't.
* @throws MessagingException
* Won't.
*/
@Test
public void testCtor() throws MessagingException, IOException
{
sut = new MessageContentExtractor(null, null);
Message msg = (Message) makeMultipart(true,
makeContentPart("text/plain", false, "stuff\r\nmore\r\nDate: 1/1/11"));
String result = sut.extract(msg);
context.assertIsSatisfied();
assertEquals("stuff\r\nmore\r\nDate: 1/1/11", result);
}
}