package fr.sii.ogham.assertion.email; import static fr.sii.ogham.assertion.AssertionHelper.assertThat; import static fr.sii.ogham.assertion.OghamAssertions.usingContext; import static fr.sii.ogham.helper.email.EmailUtils.getContent; import static java.util.Collections.list; import java.io.IOException; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; import javax.mail.Header; import javax.mail.MessagingException; import javax.mail.Part; import org.apache.commons.io.IOUtils; import org.hamcrest.Matcher; import com.google.common.base.Charsets; import fr.sii.ogham.assertion.HasParent; public class PartAssert<P> extends HasParent<P> { /** * The list of messages that will be used for assertions */ private final List<PartWithContext> actual; public PartAssert(PartWithContext actual, P parent) { this(Arrays.asList(actual), parent); } public PartAssert(List<PartWithContext> actual, P parent) { super(parent); this.actual = actual; } /** * Make assertions on the string content of a part (body, alternative or * attachment) of the message(s). UTF-8 charset is used to decode body * content. * * <pre> * .receivedMessages().message(0).body() * .contentAsString(is("foobar")) * </pre> * * Will check if the content of the body of the first message is exactly * "foobar". * * <pre> * .receivedMessages().forEach().body() * .contentAsString(is("foobar")) * </pre> * * Will check if the content of the body of every message is exactly * "foobar". * * @param matcher * the assertion to apply on string content * @return the fluent API for chaining assertions on received message(s) */ public PartAssert<P> contentAsString(Matcher<String> matcher) { return contentAsString(matcher, Charsets.UTF_8); } /** * Make assertions on the string content of a part (body, alternative or * attachment) of the message(s). * * <pre> * .receivedMessages().message(0).body() * .contentAsString(is("foobar"), Charset.forName("UTF-8")) * </pre> * * Will check if the content of the body of the first message is exactly * "foobar". * * <pre> * .receivedMessages().forEach().body() * .contentAsString(is("foobar"), Charset.forName("UTF-8")) * </pre> * * Will check if the content of the body of every message is exactly * "foobar". * * @param matcher * the assertion to apply on string content * @param charset * the charset used to decode the content * @return the fluent API for chaining assertions on received message(s) */ public PartAssert<P> contentAsString(Matcher<String> matcher, Charset charset) { try { String message = charset.name() + " content of ${partName} of message ${messageIndex}"; for (PartWithContext partWithContext : actual) { Part part = partWithContext.getPart(); assertThat(part == null ? null : IOUtils.toString(getContent(part), charset.name()), usingContext(message, partWithContext, matcher)); } return this; } catch (IOException | MessagingException e) { throw new AssertionError("Failed to get string content for part", e); } } /** * Make assertions on the raw content of a part (body, alternative or * attachment) of the message(s). * * <pre> * .receivedMessages().message(0).body() * .content(is(resource("path/to/expected/file")) * </pre> * * Will check if the content of the body of the first message is exactly the * same as the file resource available in the classpath. * * <pre> * .receivedMessages().forEach().body() * .content(is(resource("path/to/expected/file")) * </pre> * * Will check if the content of the body of every message is exactly the * same as the file resource available in the classpath. * * @param matcher * the assertion to apply on raw content * @return the fluent API for chaining assertions on received message(s) */ public PartAssert<P> content(Matcher<byte[]> matcher) { try { String message = "raw content of ${partName} of message ${messageIndex}"; for (PartWithContext partWithContext : actual) { Part part = partWithContext.getPart(); assertThat(part == null ? null : getContent(part), usingContext(message, partWithContext, matcher)); } return this; } catch (IOException | MessagingException e) { throw new AssertionError("Failed to get content for part", e); } } /** * Make assertions on the content-type of a part (body, alternative or * attachment) of the message(s). * * <pre> * .receivedMessages().message(0).body() * .contentType(is("text/html")) * </pre> * * Will check if the content-type of the body of the first message is * exactly "text/html". * * <pre> * .receivedMessages().forEach().body() * .contentType(is("text/html")) * </pre> * * Will check if the content-type of the body of every message is exactly * "text/html". * * @param matcher * the assertion to apply on content-type * @return the fluent API for chaining assertions on received message(s) */ public PartAssert<P> contentType(Matcher<String> matcher) { try { String message = "content-type of ${partName} of message ${messageIndex}"; for (PartWithContext partWithContext : actual) { Part part = partWithContext.getPart(); assertThat(part == null ? null : part.getContentType(), usingContext(message, partWithContext, matcher)); } return this; } catch (MessagingException e) { throw new AssertionError("Failed to get string content type for part", e); } } /** * Make assertions on the description of a part (body, alternative or * attachment) of the message(s). * * <pre> * .receivedMessages().message(0).body() * .description(is("foo bar")) * </pre> * * Will check if the description of the body of the first message is exactly * "foo bar". * * <pre> * .receivedMessages().forEach().body() * .description(is("foo bar")) * </pre> * * Will check if the description of the body of every message is exactly * "foo bar". * * @param matcher * the assertion to apply on description * @return the fluent API for chaining assertions on received message(s) */ public PartAssert<P> description(Matcher<String> matcher) { try { String message = "description of ${partName} of message ${messageIndex}"; for (PartWithContext partWithContext : actual) { Part part = partWithContext.getPart(); assertThat(part == null ? null : part.getDescription(), usingContext(message, partWithContext, matcher)); } return this; } catch (MessagingException e) { throw new AssertionError("Failed to get description of part", e); } } /** * Make assertions on the disposition of a part (body, alternative or * attachment) of the message(s). * * <pre> * .receivedMessages().message(0).body() * .disposition(is(INLINE_DISPOSITION)) * </pre> * * Will check if the disposition of the body of the first message is exactly * "inline". * * <pre> * .receivedMessages().forEach().body() * .disposition(is(INLINE_DISPOSITION)) * </pre> * * Will check if the disposition of the body of every message is exactly * "inline". * * @param matcher * the assertion to apply on disposition * @return the fluent API for chaining assertions on received message(s) */ public PartAssert<P> disposition(Matcher<String> matcher) { try { String message = "disposition of ${partName} of message ${messageIndex}"; for (PartWithContext partWithContext : actual) { Part part = partWithContext.getPart(); assertThat(part == null ? null : part.getDisposition(), usingContext(message, partWithContext, matcher)); } return this; } catch (MessagingException e) { throw new AssertionError("Failed to get disposition of part", e); } } /** * Make assertions on the filename of a part (body, alternative or * attachment) of the message(s). * * <pre> * .receivedMessages().message(0).attachment(0) * .filename(is("foo.pdf")) * </pre> * * Will check if the filename of the first attachment of the first message * is exactly "foo.pdf". * * <pre> * .receivedMessages().forEach().attachment(0) * .filename(is("foo.pdf")) * </pre> * * Will check if the filename of the first attachment of every message is * exactly "foo.pdf". * * @param matcher * the assertion to apply on filename * @return the fluent API for chaining assertions on received message(s) */ public PartAssert<P> filename(Matcher<String> matcher) { try { String message = "filename of ${partName} of message ${messageIndex}"; for (PartWithContext partWithContext : actual) { Part part = partWithContext.getPart(); assertThat(part == null ? null : part.getFileName(), usingContext(message, partWithContext, matcher)); } return this; } catch (MessagingException e) { throw new AssertionError("Failed to get filename of part", e); } } @SuppressWarnings("unchecked") public PartAssert<P> headers(Matcher<Iterable<? extends Header>> matcher) { try { String message = "headers of ${partName} of message ${messageIndex}"; for (PartWithContext partWithContext : actual) { Part part = partWithContext.getPart(); assertThat(part == null ? null : (Iterable<? extends Header>) list(part.getAllHeaders()), usingContext(message, partWithContext, matcher)); } return this; } catch (MessagingException e) { throw new AssertionError("Failed to get filename of part", e); } } }