Merge branch release/0.2.0 into master
4d01349
Add tests with improved conversion of MIME Multipart messages to stringd72ca46
Apply Checkstyle formatting (modified sun_checks) rules and add javadoc Signed-off-by: Paul Campbell <paulcampbell@fife.ac.uk>
This commit is contained in:
commit
7b9f291be1
9 changed files with 798 additions and 117 deletions
3
.travis.yml
Normal file
3
.travis.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
19
CHANGELOG
Normal file
19
CHANGELOG
Normal file
|
@ -0,0 +1,19 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.2.0
|
||||
------
|
||||
|
||||
* 4d01349 Add tests with improved conversion of MIME Multipart messages to string
|
||||
* d72ca46 Apply Checkstyle formatting (modified sun_checks) rules and add javadoc
|
||||
|
||||
0.1.1
|
||||
-----
|
||||
|
||||
* Upgrade javax.mail to 1.4.7
|
||||
|
||||
0.1.0
|
||||
-----
|
||||
|
||||
* Initial release
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
# wiser-assertions
|
||||
Assertions for Wiser SMTP test server from subethamail
|
||||
|
||||
## Origin
|
||||
|
||||
Taken from Rafal Browiec [WiserAssertions] class.
|
||||
|
||||
## Usage
|
||||
|
||||
@Before
|
||||
|
@ -33,3 +37,5 @@ Assertions for Wiser SMTP test server from subethamail
|
|||
.withContentContains(message_element_2)
|
||||
.withContentContains(message_element_3);
|
||||
}
|
||||
|
||||
[WiserAssertions]:http://blog.codeleak.pl/2014/09/testing-mail-code-in-spring-boot.html
|
188
checkstyle.xml
Normal file
188
checkstyle.xml
Normal file
|
@ -0,0 +1,188 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
Checkstyle configuration that checks the sun coding conventions from:
|
||||
|
||||
- the Java Language Specification at
|
||||
http://java.sun.com/docs/books/jls/second_edition/html/index.html
|
||||
|
||||
- the Sun Code Conventions at http://java.sun.com/docs/codeconv/
|
||||
|
||||
- the Javadoc guidelines at
|
||||
http://java.sun.com/j2se/javadoc/writingdoccomments/index.html
|
||||
|
||||
- the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html
|
||||
|
||||
- some best practices
|
||||
|
||||
Checkstyle is very configurable. Be sure to read the documentation at
|
||||
http://checkstyle.sf.net (or in your downloaded distribution).
|
||||
|
||||
Most Checks are configurable, be sure to consult the documentation.
|
||||
|
||||
To completely disable a check, just comment it out or delete it from the file.
|
||||
|
||||
Finally, it is worth reading the documentation.
|
||||
|
||||
-->
|
||||
|
||||
<module name="Checker">
|
||||
<!--
|
||||
If you set the basedir property below, then all reported file
|
||||
names will be relative to the specified directory. See
|
||||
http://checkstyle.sourceforge.net/5.x/config.html#Checker
|
||||
|
||||
<property name="basedir" value="${basedir}"/>
|
||||
-->
|
||||
|
||||
<!-- Checks that a package-info.java file exists for each package. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->
|
||||
<module name="JavadocPackage"/>
|
||||
|
||||
<!-- Checks whether files end with a new line. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
|
||||
<module name="NewlineAtEndOfFile"/>
|
||||
|
||||
<!-- Checks that property files contain the same keys. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
|
||||
<module name="Translation"/>
|
||||
|
||||
<!-- Checks for Size Violations. -->
|
||||
<!-- See http://checkstyle.sf.net/config_sizes.html -->
|
||||
<module name="FileLength"/>
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<module name="FileTabCharacter"/>
|
||||
|
||||
<!-- Miscellaneous other checks. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html -->
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="minimum" value="0"/>
|
||||
<property name="maximum" value="0"/>
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
</module>
|
||||
|
||||
|
||||
<!-- Checks for Headers -->
|
||||
<!-- See http://checkstyle.sf.net/config_header.html -->
|
||||
<!-- <module name="Header"> -->
|
||||
<!-- <property name="headerFile" value="${checkstyle.header.file}"/> -->
|
||||
<!-- <property name="fileExtensions" value="java"/> -->
|
||||
<!-- </module> -->
|
||||
|
||||
<module name="TreeWalker">
|
||||
|
||||
<!-- Support @SuppressWarnings annotation -->
|
||||
<!-- See http://checkstyle.sourceforge.net/config.html -->
|
||||
<module name="SuppressWarningsHolder"/>
|
||||
|
||||
<!-- Checks for Javadoc comments. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||
<module name="JavadocMethod"/>
|
||||
<module name="JavadocType"/>
|
||||
<module name="JavadocVariable"/>
|
||||
<module name="JavadocStyle"/>
|
||||
|
||||
|
||||
<!-- Checks for Naming Conventions. -->
|
||||
<!-- See http://checkstyle.sf.net/config_naming.html -->
|
||||
<module name="ConstantName"/>
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName"/>
|
||||
<module name="MethodName"/>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName"/>
|
||||
<module name="StaticVariableName"/>
|
||||
<module name="TypeName"/>
|
||||
|
||||
|
||||
<!-- Checks for imports -->
|
||||
<!-- See http://checkstyle.sf.net/config_import.html -->
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
|
||||
<module name="RedundantImport"/>
|
||||
<module name="UnusedImports"/>
|
||||
|
||||
|
||||
<!-- Checks for Size Violations. -->
|
||||
<!-- See http://checkstyle.sf.net/config_sizes.html -->
|
||||
<module name="LineLength">
|
||||
<!-- Allow for long imports for Spring Batch -->
|
||||
<!-- EnableBatchProcessing, JobBuilderFactory -->
|
||||
<!-- and StepBuilderFactory -->
|
||||
<property name="ignorePattern" value="^import"/>
|
||||
</module>
|
||||
<module name="MethodLength"/>
|
||||
<module name="ParameterNumber"/>
|
||||
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="GenericWhitespace"/>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="NoWhitespaceAfter"/>
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="OperatorWrap"/>
|
||||
<module name="ParenPad"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<module name="WhitespaceAround"/>
|
||||
|
||||
|
||||
<!-- Modifier Checks -->
|
||||
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="RedundantModifier"/>
|
||||
|
||||
|
||||
<!-- Checks for blocks. You know, those {}'s -->
|
||||
<!-- See http://checkstyle.sf.net/config_blocks.html -->
|
||||
<module name="AvoidNestedBlocks"/>
|
||||
<module name="EmptyBlock"/>
|
||||
<module name="LeftCurly"/>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="RightCurly"/>
|
||||
|
||||
|
||||
<!-- Checks for common coding problems -->
|
||||
<!-- See http://checkstyle.sf.net/config_coding.html -->
|
||||
<module name="AvoidInlineConditionals"/>
|
||||
<module name="EmptyStatement"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
<module name="HiddenField"/>
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="MagicNumber"/>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
|
||||
<!-- Checks for class design -->
|
||||
<!-- See http://checkstyle.sf.net/config_design.html -->
|
||||
<!--<module name="DesignForExtension"/>-->
|
||||
<module name="FinalClass"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
<module name="InterfaceIsType"/>
|
||||
<module name="VisibilityModifier"/>
|
||||
|
||||
|
||||
<!-- Miscellaneous other checks. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html -->
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<module name="FinalParameters"/>
|
||||
<module name="TodoComment"/>
|
||||
<module name="UpperEll"/>
|
||||
|
||||
</module>
|
||||
|
||||
<module name="SuppressWarningsFilter"/>
|
||||
|
||||
</module>
|
39
nb-configuration.xml
Normal file
39
nb-configuration.xml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-shared-configuration>
|
||||
<!--
|
||||
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||
The configuration is intended to be shared among all the users of project and
|
||||
therefore it is assumed to be part of version control checkout.
|
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||
-->
|
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||
<!--
|
||||
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||
-->
|
||||
<netbeans.checkstyle.format>true</netbeans.checkstyle.format>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder>*;static *;java;javax;org.springframework;uk.ac.fife</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.separateStaticImports>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.separateStaticImports>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLinesAfterFields>1</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLinesAfterFields>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLineAfterJavadocReturnTag>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLineAfterJavadocReturnTag>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignJavadocExceptionDescriptions>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignJavadocExceptionDescriptions>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.enableBlockCommentFormatting>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.enableBlockCommentFormatting>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignJavadocReturnDescription>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignJavadocReturnDescription>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLineAfterJavadocParameterDescriptions>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLineAfterJavadocParameterDescriptions>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignJavadocParameterDescriptions>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignJavadocParameterDescriptions>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLinesBeforeFields>1</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLinesBeforeFields>
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>8</org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>true</org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.sortMembersInGroups>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.sortMembersInGroups>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classMemberInsertionPoint>ORDERED_IN_CATEGORY</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classMemberInsertionPoint>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeCatchOnNewLine>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeCatchOnNewLine>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeFinallyOnNewLine>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeFinallyOnNewLine>
|
||||
</properties>
|
||||
</project-shared-configuration>
|
96
pom.xml
96
pom.xml
|
@ -3,7 +3,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.kemitix</groupId>
|
||||
<artifactId>wiser-assertions</artifactId>
|
||||
<version>0.1.1</version>
|
||||
<version>0.2.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>wiser-assertions</name>
|
||||
|
@ -11,28 +11,8 @@
|
|||
|
||||
<url>https://github.com/kemitix/wiser-assertions</url>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Paul Campbell</name>
|
||||
<email>pcampbell@kemitix.net</email>
|
||||
<organization>Kemitix</organization>
|
||||
<organizationUrl>https://github.com/kemitix/</organizationUrl>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>http://www.opensource.org/licenses/mit-license.php</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<inceptionYear>2015</inceptionYear>
|
||||
|
||||
<prerequisites>
|
||||
<maven>3.0.4</maven>
|
||||
</prerequisites>
|
||||
|
||||
<issueManagement>
|
||||
<url>https://github.com/kemitix/wiser-assertions/issues</url>
|
||||
<system>GitHub Issues</system>
|
||||
|
@ -46,14 +26,12 @@
|
|||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>9</version>
|
||||
<groupId>net.kemitix</groupId>
|
||||
<artifactId>kemitix-spring-parent</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -67,59 +45,17 @@
|
|||
<artifactId>subethasmtp</artifactId>
|
||||
<version>3.1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release-sign-artifacts</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>performRelease</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<configuration>
|
||||
<passphrase>${gpg.passphrase}</passphrase>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.10.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -1,61 +1,144 @@
|
|||
package net.kemitix.wiser.assertions;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import org.subethamail.wiser.Wiser;
|
||||
import org.subethamail.wiser.WiserMessage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import org.subethamail.wiser.Wiser;
|
||||
import org.subethamail.wiser.WiserMessage;
|
||||
|
||||
/**
|
||||
* Taken from the WiserAssetions class from Rafal Browiec at
|
||||
* http://blog.codeleak.pl/2014/09/testing-mail-code-in-spring-boot.html
|
||||
* Provides a set of assertions for checking the status of any messages received
|
||||
* by subethamail's Wiser.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* {@literal @}Before
|
||||
* public void setUp() throws IOException {
|
||||
* wiser = new Wiser(PORT);
|
||||
* wiser.start();
|
||||
* }
|
||||
*
|
||||
* {@literal @}After public void tearDown() { wiser.stop(); }
|
||||
*
|
||||
* {@literal @}Test public void testMail() { //given ...
|
||||
*
|
||||
* //when ...
|
||||
*
|
||||
* //then WiserAssertions.assertReceivedMessage(wiser) .from(sender)
|
||||
* .to(recipient_alpha) .to(recipient_beta) .withSubjectContains(subject_prefix)
|
||||
* .withSubjectContains(subject_suffix) .withContentContains(message_element_1)
|
||||
* .withContentContains(message_element_2)
|
||||
* .withContentContains(message_element_3); }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class WiserAssertions {
|
||||
public final class WiserAssertions {
|
||||
|
||||
/**
|
||||
* The messages received by Wiser.
|
||||
*/
|
||||
private final List<WiserMessage> messages;
|
||||
|
||||
public static WiserAssertions assertReceivedMessage(Wiser wiser) {
|
||||
/**
|
||||
* Creates an instance of {@code} WiserAssertions} ready to make assertions
|
||||
* on any messages received by the {@link Wiser} server.
|
||||
*
|
||||
* @param wiser the SMTP server instance
|
||||
*
|
||||
* @return an instance of {@code WiserAssertions}
|
||||
*/
|
||||
public static WiserAssertions assertReceivedMessage(final Wiser wiser) {
|
||||
return new WiserAssertions(wiser.getMessages());
|
||||
}
|
||||
|
||||
private WiserAssertions(List<WiserMessage> messages) {
|
||||
this.messages = messages;
|
||||
/**
|
||||
* Private constructor.
|
||||
*
|
||||
* @param wiserMessages the messages to be tested by the assertions
|
||||
*/
|
||||
private WiserAssertions(final List<WiserMessage> wiserMessages) {
|
||||
this.messages = wiserMessages;
|
||||
}
|
||||
|
||||
public WiserAssertions from(String from) {
|
||||
findFirstOrElseThrow(m -> m.getEnvelopeSender().equals(from),
|
||||
assertionError("No message from [{0}] found!", from));
|
||||
/**
|
||||
* Checks that there was at least one email received that was sent from the
|
||||
* {@code sender}.
|
||||
*
|
||||
* @param sender email address to search for
|
||||
*
|
||||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions from(final String sender) {
|
||||
findFirstOrElseThrow(m -> m.getEnvelopeSender().equals(sender),
|
||||
assertionError("No message from [{0}] found!", sender));
|
||||
return this;
|
||||
}
|
||||
|
||||
public WiserAssertions to(String to) {
|
||||
findFirstOrElseThrow(m -> m.getEnvelopeReceiver().equals(to),
|
||||
assertionError("No message to [{0}] found!", to));
|
||||
/**
|
||||
* Checks that there was at least one email received that was sent to the
|
||||
* {@code recipient}.
|
||||
*
|
||||
* @param recipient email address to search for
|
||||
*
|
||||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions to(final String recipient) {
|
||||
findFirstOrElseThrow(m -> m.getEnvelopeReceiver().equals(recipient),
|
||||
assertionError("No message to [{0}] found!", recipient));
|
||||
return this;
|
||||
}
|
||||
|
||||
public WiserAssertions withSubject(String subject) {
|
||||
Predicate<WiserMessage> predicate = m -> subject.equals(unchecked(getMimeMessage(m)::getSubject));
|
||||
/**
|
||||
* Checks that there was at least one email received that has the required
|
||||
* subject.
|
||||
*
|
||||
* @param subject the subject line to search for
|
||||
*
|
||||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions withSubject(final String subject) {
|
||||
Predicate<WiserMessage> predicate
|
||||
= m -> subject.equals(unchecked(getMimeMessage(m)::getSubject));
|
||||
findFirstOrElseThrow(predicate,
|
||||
assertionError("No message with subject [{0}] found!", subject));
|
||||
assertionError("No message with subject [{0}] found!",
|
||||
subject));
|
||||
return this;
|
||||
}
|
||||
|
||||
public WiserAssertions withSubjectContains(String subject) {
|
||||
Predicate<WiserMessage> predicate = m -> unchecked(getMimeMessage(m)::getSubject).contains(subject);
|
||||
/**
|
||||
* Checks that there was at least one email received that has a subject that
|
||||
* contains the search text.
|
||||
*
|
||||
* @param subject the text to search for in the subject
|
||||
*
|
||||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions withSubjectContains(final String subject) {
|
||||
Predicate<WiserMessage> predicate
|
||||
= m -> unchecked(getMimeMessage(m)::getSubject)
|
||||
.contains(subject);
|
||||
findFirstOrElseThrow(predicate,
|
||||
assertionError("No message with subject [{0}] found!", subject));
|
||||
assertionError("No message with subject [{0}] found!",
|
||||
subject));
|
||||
return this;
|
||||
}
|
||||
|
||||
public WiserAssertions withContent(String content) {
|
||||
/**
|
||||
* Check that there was at least one email received that has a body that
|
||||
* matches the content.
|
||||
*
|
||||
* @param content the body of the email to search for
|
||||
*
|
||||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions withContent(final String content) {
|
||||
findFirstOrElseThrow(m -> {
|
||||
ThrowingSupplier<String> contentAsString
|
||||
= () -> getMimeMessageBody(m).trim();
|
||||
|
@ -64,21 +147,42 @@ public class WiserAssertions {
|
|||
return this;
|
||||
}
|
||||
|
||||
public WiserAssertions withContentContains(String content) {
|
||||
/**
|
||||
* Check that there was at least one email received that contains the search
|
||||
* text.
|
||||
*
|
||||
* @param content the text to search for in the body of the email
|
||||
*
|
||||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions withContentContains(final String content) {
|
||||
StringBuilder messageContent = new StringBuilder();
|
||||
findFirstOrElseThrow((WiserMessage m) -> {
|
||||
ThrowingSupplier<String> contentAsString
|
||||
= () -> getMimeMessageBody(m).trim();
|
||||
messageContent.append(unchecked(contentAsString));
|
||||
return unchecked(contentAsString).contains(content);
|
||||
}, assertionError("No message with content containing [{0}] found! Was {1}", content, messageContent));
|
||||
}, assertionError(
|
||||
"No message with content containing [{0}] found! Was {1}",
|
||||
content, messageContent));
|
||||
return this;
|
||||
}
|
||||
|
||||
private String getMimeMessageBody(WiserMessage m) throws IOException, MessagingException {
|
||||
Object content = getMimeMessage(m).getContent();
|
||||
/**
|
||||
* Returns the body of the message.
|
||||
*
|
||||
* @param message the message
|
||||
*
|
||||
* @return the body of the message
|
||||
*
|
||||
* @throws IOException if error extracting the mime message
|
||||
* @throws MessagingException if the message type is not known
|
||||
*/
|
||||
private String getMimeMessageBody(final WiserMessage message)
|
||||
throws IOException, MessagingException {
|
||||
Object content = getMimeMessage(message).getContent();
|
||||
if (content instanceof MimeMessage) {
|
||||
return (String) content;
|
||||
return content.toString();
|
||||
}
|
||||
if (content instanceof MimeMultipart) {
|
||||
return getMimeMultipartAsString((MimeMultipart) content);
|
||||
|
@ -86,20 +190,63 @@ public class WiserAssertions {
|
|||
throw new RuntimeException("Unexpected MimeMessage content");
|
||||
}
|
||||
|
||||
private void findFirstOrElseThrow(Predicate<WiserMessage> predicate, Supplier<AssertionError> exceptionSupplier) {
|
||||
/**
|
||||
* Checks that at least on message matches the predicate or the supplied
|
||||
* exception will be thrown.
|
||||
*
|
||||
* @param predicate the condition a message must match
|
||||
* @param exceptionSupplier the supplier of the exception
|
||||
*/
|
||||
private void findFirstOrElseThrow(
|
||||
final Predicate<WiserMessage> predicate,
|
||||
final Supplier<AssertionError> exceptionSupplier
|
||||
) {
|
||||
messages.stream().filter(predicate)
|
||||
.findFirst().orElseThrow(exceptionSupplier);
|
||||
}
|
||||
|
||||
private MimeMessage getMimeMessage(WiserMessage wiserMessage) {
|
||||
/**
|
||||
* Returns the mime message within the {@link WiserMessage} converting any
|
||||
* {@link MessagingException}s into {@link RuntimeException}s.
|
||||
*
|
||||
* @param wiserMessage the message
|
||||
*
|
||||
* @return the mime message
|
||||
*/
|
||||
private MimeMessage getMimeMessage(final WiserMessage wiserMessage) {
|
||||
return unchecked(wiserMessage::getMimeMessage);
|
||||
}
|
||||
|
||||
private static Supplier<AssertionError> assertionError(String errorMessage, Object... args) {
|
||||
return () -> new AssertionError(MessageFormat.format(errorMessage, args));
|
||||
/**
|
||||
* Returns a {@link Supplier} for an {@link AssertionError}.
|
||||
*
|
||||
* @param errorMessage the message for the exception
|
||||
* @param args the parameters to insert into the message using
|
||||
* {@link MessageFormat}
|
||||
*
|
||||
* @return a supplier of an {@link AssertionError}
|
||||
*/
|
||||
@SuppressWarnings(
|
||||
{"ThrowableInstanceNotThrown", "ThrowableInstanceNeverThrown"})
|
||||
private static Supplier<AssertionError> assertionError(
|
||||
final String errorMessage,
|
||||
final Object... args
|
||||
) {
|
||||
return ()
|
||||
-> new AssertionError(MessageFormat.format(errorMessage, args));
|
||||
}
|
||||
|
||||
public static <T> T unchecked(ThrowingSupplier<T> supplier) {
|
||||
/**
|
||||
* Convert any checked Exceptions into unchecked Exceptions.
|
||||
*
|
||||
* @param <T> the item type to be returned after suppressing any
|
||||
* checked exceptions
|
||||
* @param supplier the source of the return value that could cause a checked
|
||||
* exception
|
||||
*
|
||||
* @return the product of the supplier
|
||||
*/
|
||||
public static <T> T unchecked(final ThrowingSupplier<T> supplier) {
|
||||
try {
|
||||
return supplier.get();
|
||||
} catch (Throwable e) {
|
||||
|
@ -107,14 +254,41 @@ public class WiserAssertions {
|
|||
}
|
||||
}
|
||||
|
||||
private String getMimeMultipartAsString(MimeMultipart mimeMultipart) throws MessagingException, IOException {
|
||||
OutputStream os = new ByteArrayOutputStream();
|
||||
mimeMultipart.writeTo(os);
|
||||
return os.toString();
|
||||
/**
|
||||
* Converts a {@link MimeMultipart} into a {@link String} stripping out the
|
||||
* mime part boundary and headers..
|
||||
*
|
||||
* @param mimeMultipart the message part to convert
|
||||
*
|
||||
* @return the message part as a string
|
||||
*
|
||||
* @throws MessagingException if the part is empty
|
||||
* @throws IOException if there is another error
|
||||
*/
|
||||
private String getMimeMultipartAsString(final MimeMultipart mimeMultipart)
|
||||
throws MessagingException, IOException {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < mimeMultipart.getCount(); i++) {
|
||||
sb.append(mimeMultipart.getBodyPart(i).getContent());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for providing a value that could thrown an exception when
|
||||
* sought.
|
||||
*
|
||||
* @param <T> the type of value to be supplied
|
||||
*/
|
||||
public interface ThrowingSupplier<T> {
|
||||
|
||||
/**
|
||||
* Returns the value.
|
||||
*
|
||||
* @return the value
|
||||
*
|
||||
* @throws Throwable on error
|
||||
*/
|
||||
T get() throws Throwable;
|
||||
}
|
||||
}
|
||||
|
|
28
src/main/java/net/kemitix/wiser/assertions/package-info.java
Normal file
28
src/main/java/net/kemitix/wiser/assertions/package-info.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Provides {@link WiserAssertions} to check for messages received by the Wiser
|
||||
* SMTP test server from subethamail.
|
||||
*
|
||||
* <p>
|
||||
* The MIT License.
|
||||
* <p>
|
||||
* Copyright 2015 pcampbell.
|
||||
* <p>
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* <p>
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package net.kemitix.wiser.assertions;
|
|
@ -0,0 +1,288 @@
|
|||
package net.kemitix.wiser.assertions;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.subethamail.wiser.Wiser;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
|
||||
/**
|
||||
* Tests for {@link WiserAssertions}.
|
||||
*
|
||||
* @author pcampbell
|
||||
*/
|
||||
public class WiserAssertionsTest {
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger LOG
|
||||
= Logger.getLogger(WiserAssertionsTest.class.getName());
|
||||
|
||||
/**
|
||||
* Test mail server.
|
||||
*/
|
||||
private Wiser wiser;
|
||||
|
||||
/**
|
||||
* Prepare each test.
|
||||
*/
|
||||
@Before
|
||||
@SuppressWarnings("magicnumber")
|
||||
public void setUp() {
|
||||
wiser = new Wiser(PORT);
|
||||
wiser.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test mail server port.
|
||||
*/
|
||||
private static final int PORT = 12345;
|
||||
|
||||
/**
|
||||
* Clean up after each test.
|
||||
*/
|
||||
@After
|
||||
public void tearDown() {
|
||||
wiser.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a mime multipart message to the Wiser server.
|
||||
*
|
||||
* @param from the sender
|
||||
* @param to the recipient
|
||||
* @param subject the subject of the email
|
||||
* @param body the body of the email
|
||||
*/
|
||||
private void sendMimeMultipartMessage(
|
||||
final String from,
|
||||
final String to,
|
||||
final String subject,
|
||||
final String body) {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("mail.smtp.host", "localhost");
|
||||
properties.setProperty("mail.smtp.port", "" + PORT);
|
||||
Session session = Session.getDefaultInstance(properties);
|
||||
try {
|
||||
MimeMessage message = new MimeMessage(session);
|
||||
message.setFrom(new InternetAddress(from));
|
||||
message.setRecipients(Message.RecipientType.TO, to);
|
||||
message.setSubject(subject, "UTF-8");
|
||||
final Multipart mimeMultipart = new MimeMultipart();
|
||||
final MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
mimeBodyPart.setText(body);
|
||||
mimeMultipart.addBodyPart(mimeBodyPart);
|
||||
message.setContent(mimeMultipart);
|
||||
Transport.send(message);
|
||||
} catch (MessagingException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the WiserAssertions.
|
||||
*
|
||||
* @return the wiser assertions
|
||||
*/
|
||||
private WiserAssertions getAssertions() {
|
||||
return WiserAssertions.assertReceivedMessage(wiser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#withContent(java.lang.String)} where the
|
||||
* content of the email matches.
|
||||
*/
|
||||
@Test
|
||||
public void testContentMatches() {
|
||||
//given
|
||||
final String body = "message body";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject", body);
|
||||
//then
|
||||
getAssertions().withContent(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#withContent(java.lang.String)} where the
|
||||
* content of the email does not match.
|
||||
*/
|
||||
@Test(expected = AssertionError.class)
|
||||
public void testContentNotMatches() {
|
||||
//given
|
||||
final String body = "message body";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject", body);
|
||||
//then
|
||||
getAssertions().withContent("Other body");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#withContentContains(String)} where the
|
||||
* content of the email matches.
|
||||
*/
|
||||
@Test
|
||||
public void testContentContainsMatches() {
|
||||
//given
|
||||
final String body = "message body";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject", body);
|
||||
//then
|
||||
getAssertions().withContentContains("age bo");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#withContentContains(String)} where the
|
||||
* content of the email does not match.
|
||||
*/
|
||||
@Test(expected = AssertionError.class)
|
||||
public void testContentContainsNotMatches() {
|
||||
//given
|
||||
final String body = "message body";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject", body);
|
||||
//then
|
||||
getAssertions().withContentContains("agebo");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#from(java.lang.String)} can detect when mail
|
||||
* is sent from a user.
|
||||
*
|
||||
* @throws java.io.IOException if error delivering test message
|
||||
*/
|
||||
@Test
|
||||
public void testFromMatches() throws IOException {
|
||||
//given
|
||||
final String from = "bob@a.com";
|
||||
//when
|
||||
sendMimeMultipartMessage(from, "to", "subject", "body");
|
||||
//then
|
||||
getAssertions().from(from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#from(java.lang.String)} can detect when mail
|
||||
* is not sent from a user.
|
||||
*/
|
||||
@Test(expected = AssertionError.class)
|
||||
public void testFromNotMatches() {
|
||||
//given
|
||||
final String from = "bob@a.com";
|
||||
//when
|
||||
sendMimeMultipartMessage(from, "to", "subject", "body");
|
||||
//then
|
||||
getAssertions().from("lisa@c.com");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#assertReceivedMessage(Wiser)} creates and
|
||||
* returns a WiserAssertions instance.
|
||||
*/
|
||||
@Test
|
||||
public void testInstantiate() {
|
||||
assertNotNull(getAssertions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#withSubjectContains(java.lang.String)} where
|
||||
* the subject contains the expected fragment.
|
||||
*/
|
||||
@Test
|
||||
public void testSubjectContainsMatches() {
|
||||
//given
|
||||
final String fragment = "foo";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject " + fragment + " tail", "body");
|
||||
//then
|
||||
getAssertions().withSubjectContains(fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#withSubjectContains(java.lang.String)} where
|
||||
* the subject does not contain the expected fragment.
|
||||
*/
|
||||
@Test(expected = AssertionError.class)
|
||||
public void testSubjectContainsNotMatches() {
|
||||
//given
|
||||
final String fragment = "foo";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject tail", "body");
|
||||
//then
|
||||
getAssertions().withSubjectContains(fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#withSubject(java.lang.String)} where the
|
||||
* message has the subject expected.
|
||||
*/
|
||||
@Test
|
||||
public void testSubjectMatches() {
|
||||
//given
|
||||
final String subject = "message subject";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", "to", subject, "body");
|
||||
//then
|
||||
getAssertions().withSubject(subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#withSubject(java.lang.String)} where the
|
||||
* message does not have the subject expected.
|
||||
*/
|
||||
@Test(expected = AssertionError.class)
|
||||
public void testSubjectNotMatches() {
|
||||
//given
|
||||
final String subject = "message subject";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", "to", subject, "body");
|
||||
//then
|
||||
getAssertions().withSubject("other subject");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#from(java.lang.String)} can detect when mail
|
||||
* is sent to a user.
|
||||
*/
|
||||
@Test
|
||||
public void testToMatches() {
|
||||
//given
|
||||
final String to = "carl@b.com";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", to, "subject", "body");
|
||||
//then
|
||||
getAssertions().to(to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link WiserAssertions#from(java.lang.String)} can detect when mail
|
||||
* is not sent from a user.
|
||||
*
|
||||
*/
|
||||
@Test(expected = AssertionError.class)
|
||||
public void testToNotMatches() {
|
||||
//given
|
||||
final String to = "carl@b.com";
|
||||
//when
|
||||
sendMimeMultipartMessage("from", to, "subject", "body");
|
||||
//then
|
||||
getAssertions().to("bob@a.com");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue