Merge branch 'develop' into report-coverage-results-to-coveralls

This commit is contained in:
Paul Campbell 2016-06-02 21:33:23 +01:00
commit 52d4ede96d
3 changed files with 305 additions and 277 deletions

View file

@ -1,192 +1,207 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!DOCTYPE module PUBLIC <!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN" "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<!-- <!-- Template checkstyle rules primarily intented for use with projects based on the kemitix-parent POM -->
<!-- -->
Checkstyle configuration that checks the sun coding conventions from: <!-- See http://checkstyle.sourceforge.net/checks.html for documentation on each rule. -->
- 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"> <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}"/> <module name="JavadocPackage"/> <!-- package-info.java must exist -->
--> <module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf"/> <!-- must use unix line endings -->
<!-- Checks that a package-info.java file exists for each package. --> </module>
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage --> <module name="FileLength"/> <!-- files must be less than 2000 lines -->
<module name="JavadocPackage"/> <module name="FileTabCharacter"/> <!-- tabs not allowed -->
<!-- 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"> <module name="RegexpSingleline">
<property name="format" value="\s+$"/> <property name="format" value="\s+$"/>
<property name="minimum" value="0"/>
<property name="maximum" value="0"/>
<property name="message" value="Line has trailing spaces."/> <property name="message" value="Line has trailing spaces."/>
</module> </module>
<module name="SuppressWarningsFilter"/> <!-- enable @SuppressWarnings for checkstyle rules -->
<!-- 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"> <module name="TreeWalker">
<!-- Support @SuppressWarnings annotation --> <module name="AbbreviationAsWordInName"/> <!-- enforce proper CamelCase -->
<!-- See http://checkstyle.sourceforge.net/config.html --> <module name="AbstractClassName"/> <!-- enforce Abstract.* in abstract class names -->
<module name="SuppressWarningsHolder"/> <module name="AnnotationLocation"/> <!-- annotations should be on line by themselves -->
<module name="AnnotationUseStyle"/> <!-- annotations should only use () and named attributes when needed -->
<module name="FileContentsHolder"/> <module name="AnonInnerLength"/> <!-- limits anonymous inner classes to 20 lines -->
<module name="ArrayTrailingComma"/> <!-- arrays should have a trailing comma (unless braces are on same line)-->
<!-- Checks for Javadoc comments. --> <module name="ArrayTypeStyle"/> <!-- enforce Java style arrays -->
<!-- See http://checkstyle.sf.net/config_javadoc.html --> <module name="AtclauseOrder"/> <!-- enforce standard order for javadoc elements -->
<module name="JavadocMethod"> <module name="AvoidEscapedUnicodeCharacters"> <!-- prevent use of obscure escape codes -->
<property name="scope" value="public"/> <property name="allowEscapesForControlCharacters" value="true"/> <!-- unless non-printable controls -->
</module> </module>
<module name="JavadocType"/> <module name="AvoidNestedBlocks"/> <!-- avoid unnecessary blocks {} -->
<!--<module name="JavadocVariable"/>--> <module name="AvoidStarImport"/> <!-- import package.* is not allowed -->
<module name="JavadocStyle"/> <module name="AvoidStaticImport"> <!-- import static ... is not allowed -->
<property name="excludes"
value="org.assertj.core.api.Assertions.assertThat,org.mockito.BDDMockito.given,org.mockito.Mockito.*,org.mockito.Matchers.*,org.mockito.Mockito.*"/> <!-- unless selected testing shorthands -->
<!-- Checks for Naming Conventions. --> </module>
<!-- See http://checkstyle.sf.net/config_naming.html --> <module name="BooleanExpressionComplexity"> <!-- restrict number of &&, ||, &, | and ^ expressions -->
<module name="ConstantName"/> <property name="max" value="2"/>
<module name="LocalFinalVariableName"/> </module>
<module name="LocalVariableName"/> <module name="CatchParameterName"/> <!-- restrict parameter names when catching an Exception -->
<module name="MemberName"/> <module name="ClassDataAbstractionCoupling"/> <!-- restrict number of classes instantiated per class to 7 -->
<module name="MethodName"/> <module name="ClassFanOutComplexity"/> <!-- restrict class dependencies to 20 -->
<module name="PackageName"/> <module name="ClassTypeParameterName"/> <!-- restrict class type parameters (i.e. generics) to ^[A-Z]$ -->
<module name="ParameterName"/> <module name="ConstantName"/> <!-- force all uppercase for static final fields -->
<module name="StaticVariableName"/> <module name="CommentsIndentation"/> <!-- enforce comment indentation to match surrounding code -->
<module name="TypeName"/> <module name="CovariantEquals"/> <!-- ensure correct version of equals() is implemented -->
<module name="CyclomaticComplexity"> <!-- limit complexity score -->
<property name="max" value="5"/>
<!-- Checks for imports --> </module>
<!-- See http://checkstyle.sf.net/config_import.html --> <module name="DeclarationOrder"/> <!-- enforce order: static variables, variables, constructors, methods -->
<module name="AvoidStarImport"/> <module name="DefaultComesLast"/> <!-- enforce default as last option in switch statement -->
<module name="IllegalImport"/> <!-- defaults to sun.* packages --> <module name="DesignForExtension"/> <!-- protect against bad subclassing - use interfaces for mocking in unit tests -->
<module name="RedundantImport"/> <module name="EmptyBlock"/> <!-- checks for empty blocks -->
<module name="UnusedImports"/> <module name="EmptyCatchBlock"> <!-- checks the catch blocks contain comment -->
<property name="commentFormat" value="expected|ignore"/>
</module>
<!-- Checks for Size Violations. --> <module name="EmptyForInitializerPad"/> <!-- empty for loop initializer must have no spaces -->
<!-- See http://checkstyle.sf.net/config_sizes.html --> <module name="EmptyForIteratorPad"/> <!-- empty for loop iterator muse have have no spaces -->
<module name="LineLength"/> <module name="EmptyLineSeparator"/> <!-- enforce blank lines after header, fields, constructors, methods, etc -->
<module name="MethodLength"/> <module name="EmptyStatement"/> <!-- prevent standalone ";" semicolons -->
<module name="ParameterNumber"/> <module name="EqualsHashCode"/> <!-- if equals() is overridden then so must hashCode() be -->
<module name="ExecutableStatementCount"/> <!-- limit executable statements to 30 per method -->
<module name="ExplicitInitialization"/> <!-- avoid initializing a field twice to the same value -->
<!-- Checks for whitespace --> <module name="FallThrough"/> <!-- checks that each switch case fall-through is commented as such -->
<!-- See http://checkstyle.sf.net/config_whitespace.html --> <module name="FinalClass"/> <!-- class which has only private constructors is declared as final -->
<module name="EmptyForIteratorPad"/> <!--<module name="FinalLocalVariable"/> &lt;!&ndash; incompatible with lombok's val - local variables that never change must be declared final &ndash;&gt;-->
<module name="GenericWhitespace"/> <module name="FinalParameters"/> <!-- parameters that never change must be declared final -->
<module name="MethodParamPad"/> <module name="GenericWhitespace"/> <!-- generic tokens are spaced correctly -->
<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="HiddenField">
<property name="ignoreConstructorParameter" value="true"/> <property name="ignoreConstructorParameter" value="true"/>
<property name="ignoreSetter" value="true"/> <property name="ignoreSetter" value="true"/>
<property name="setterCanReturnItsClass" value="true"/>
</module> </module>
<module name="IllegalInstantiation"/> <module name="HideUtilityClassConstructor"/> <!-- suppress for class with public static void main(...) -->
<module name="InnerAssignment"/> <module name="IllegalCatch"/> <!-- prevent generic catches (i.e. Exception, Throwable, RuntimeException) -->
<module name="MagicNumber"/> <module name="IllegalImport"/> <!-- prevent imports from the sun.* package -->
<module name="MissingSwitchDefault"/> <module name="IllegalThrows"/> <!-- prevent generic throws (i.e. Exception, Throwable, RuntimeException) -->
<module name="SimplifyBooleanExpression"/> <module name="IllegalType"/> <!-- prevents variables, returns or parameters of non-interface Collections classes -->
<module name="SimplifyBooleanReturn"/> <!--<module name="Indentation"/> &lt;!&ndash; incompatible with preferred indentation - correct indentation of Java code &ndash;&gt;-->
<module name="InnerAssignment"/> <!-- prevent assignments in subexpressions (i.e. while((line = read()){}) -->
<!-- Checks for class design --> <module name="InnerTypeLast"/> <!-- inner classes appear after methods and fields -->
<!-- See http://checkstyle.sf.net/config_design.html --> <module name="InterfaceIsType"/> <!-- interface must define method not just constants -->
<!--<module name="DesignForExtension"/>--> <module name="JavaNCSS"/> <!-- Non-Commenting Source Statements complexity analysis -->
<module name="FinalClass"/> <module name="JavadocMethod"> <!-- methods should have javadoc block -->
<module name="HideUtilityClassConstructor"/> <property name="scope" value="public"/> <!-- if they are public -->
<module name="InterfaceIsType"/> </module>
<module name="VisibilityModifier"/> <module name="JavadocParagraph"/> <!-- javadoc paragraphs have opening <p> elements -->
<module name="JavadocStyle"/> <!-- javadoc comments are well formed -->
<module name="JavadocType"/> <!-- jacvadoc is present for classes, interfaces and enums -->
<!-- Miscellaneous other checks. --> <module name="LeftCurly"/> <!-- placement of left curly braces ('{') for code blocks at end of line -->
<!-- See http://checkstyle.sf.net/config_misc.html --> <module name="LineLength"/> <!-- lines can't be longer the 80 -->
<module name="ArrayTypeStyle"/> <module name="LocalFinalVariableName"/> <!-- validates identifiers for local, final variables, including catch parameters -->
<module name="FinalParameters"/> <module name="LocalVariableName"/> <!-- validates non-final identifiers -->
<module name="TodoComment"/> <module name="MagicNumber"/> <!-- checks for magic numbers -->
<module name="UpperEll"/> <module name="MemberName"/> <!-- instance variable names conform to ^[a-z][a-zA-Z0-9]*$ -->
<module name="MethodCount"> <!-- restrict the number of methods in a class -->
<property name="maxTotal" value="30"/>
</module>
<module name="MethodLength"> <!-- restrict the number of lines in a method -->
<property name="max" value="60"/>
</module>
<module name="MethodName"/> <!-- method names conform to ^[a-z][a-zA-Z0-9]*$ -->
<module name="MethodParamPad"/> <!-- verifies padding around method parameters -->
<module name="MissingDeprecated"/> <!-- @Deprecated annotation must be accompanied by javadoc @deprecated -->
<module name="MissingSwitchDefault"/> <!-- switch must have a default -->
<module name="ModifiedControlVariable"/> <!-- prevent for loop control being modified inside loop -->
<module name="ModifierOrder"/> <!-- enforce order: public protected private abstract static final transient volatile synchronized native strictfp -->
<module name="MultipleStringLiterals"/> <!-- merge string literals -->
<module name="MultipleVariableDeclarations"/> <!-- declare variables separately -->
<module name="MutableException"/> <!-- prevent changing an exception once created -->
<module name="NPathComplexity"> <!-- restrict method complexity -->
<property name="max" value="400"/>
</module>
<module name="NeedBraces"/> <!-- braces around code blocks -->
<module name="NestedForDepth"/> <!-- prevent nested for loops -->
<module name="NestedIfDepth"/> <!-- prevent nested if-else blocks -->
<module name="NestedTryDepth"/> <!-- prevent nested try blocks -->
<module name="NoClone"/> <!-- prevent overriding Object.clone() -->
<module name="NonEmptyAtclauseDescription"/> <!-- javadoc tags have descriptions -->
<module name="NoWhitespaceAfter"/> <!-- prevent white space after tokens -->
<module name="NoWhitespaceBefore"/> <!-- prevent white space before tokens -->
<module name="OneStatementPerLine"/> <!-- only one statement per line -->
<module name="OneTopLevelClass"/> <!-- one top-level class per file -->
<module name="OperatorWrap"/> <!-- when line wrapping on an operator, the operator is on the new line -->
<module name="OuterTypeFilename"/> <!-- class name and filename must match -->
<module name="OverloadMethodsDeclarationOrder"/> <!-- group overloaded methods together -->
<module name="PackageDeclaration"/> <!-- class must have package and it must match the directory -->
<module name="PackageName"/> <!-- validate package name format -->
<module name="ParameterName"/> <!-- validate parameter name format -->
<module name="ParameterNumber"/> <!-- limits the number of parameters to 7 -->
<module name="ParenPad"/> <!-- parentheses should have no padding spaces -->
<module name="RedundantImport"/> <!-- checks for redundant imports (i.e. in the same package) -->
<module name="RedundantModifier"/> <!-- checks for redundant modifies (e.g. public methods in an interface) -->
<module name="ReturnCount"/> <!-- Restricts return statements to 2 per method (1 if return type is void) -->
<module name="RightCurly"/> <!-- placement of right curly braces ('}') for code blocks at end of line -->
<module name="SingleSpaceSeparator"/> <!-- Checks that non-whitespace characters are separated by only 1 character -->
<module name="SeparatorWrap"> <!-- checks line wrapping on separators (,) have separator at the end of the line -->
<property name="tokens" value="COMMA"/>
<property name="option" value="eol"/>
</module>
<module name="SeparatorWrap"> <!-- checks line wrapping on separators (.) have separator on the new line -->
<property name="tokens" value="DOT"/>
<property name="option" value="nl"/>
</module>
<module name="SimplifyBooleanExpression"/> <!-- finds code like if (b == true), b || true, !false, etc. -->
<module name="SimplifyBooleanReturn"/> <!-- overly complicated boolean return statements. -->
<module name="StaticVariableName"/> <!-- Static non-finals should be formatted like normal identifiers -->
<module name="StringLiteralEquality"/> <!-- use .equals(...) when comparing strings for equality -->
<module name="SuppressWarningsHolder"/> <!-- holds all @SuppressWarnings found for SuppressWarningsFilter -->
<module name="ThrowsCount"/> <!-- Restricts throws statements to 4 -->
<module name="TodoComment"> <!-- no to do or fix me comments -->
<property name="format" value="(TODO)|(FIXME)"/>
</module>
<module name="TrailingComment"/> <!-- no end-line comments (the irony!) -->
<module name="TypeName"/> <!-- validates class, interface, enum and annotation names -->
<module name="TypecastParenPad"/> <!-- no spaces in type casting parentheses -->
<module name="UnnecessaryParentheses"/> <!-- unnecessary parentheses -->
<module name="UnusedImports"/> <!-- checks for import that aren't used -->
<module name="UpperEll"/> <!-- long constants have an 'L' suffix -->
<module name="VariableDeclarationUsageDistance"/> <!-- distance between declaration of variable and first usage -->
<module name="VisibilityModifier"/> <!-- visibility of class members -->
<module name="WhitespaceAfter"/> <!-- comma, semicolon, and type cast are followed by a space -->
<module name="WhitespaceAround"/> <!-- selected token are surrounded by a space -->
<!-- Sevntu checks -->
<!-- sevntu/coding -->
<module name="AvoidConstantAsFirstOperandInConditionCheck"/> <!-- avoid code like if(12 == value){...} -->
<module name="AvoidHidingCauseExceptionCheck"/> <!-- ensure exceptions are propagated as cause in subsequent exceptions -->
<module name="AvoidNotShortCircuitOperatorsForBooleanCheck"/> <!-- limits using of not short-circuit operators -->
<module name="ConfusingConditionCheck"/> <!-- prevents negation within an "if" expression if "else" is present -->
<module name="DiamondOperatorForVariableDefinitionCheck"/> <!-- use the diamond operator -->
<module name="EitherLogOrThrowCheck"/> <!-- log or throw an exception - don't do both -->
<module name="ForbidCCommentsInMethodsCheck"/> <!-- prevent /* C-style */ comments inside methods -->
<module name="ForbidReturnInFinallyBlockCheck"/> <!-- returns in finally override returns elsewhere in method -->
<module name="ForbidThrowAnonymousExceptionsCheck"/> <!-- only throw concrete exceptions -->
<module name="LogicConditionNeedOptimizationCheck"/> <!-- prevent placement of local variables and fields after call to method in logical conditionals -->
<module name="MapIterationInForEachLoopCheck"/> <!-- warns of unoptimised map iteration -->
<module name="NameConventionForJunit4TestClassesCheck"/> <!-- checks names of test classes -->
<module name="NoNullForCollectionReturnCheck"/> <!-- don't return null when should be an empty collection -->
<module name="NumericLiteralNeedsUnderscoreCheck"/> <!-- long numeric literals have underscore spacers -->
<module name="OverridableMethodInConstructorCheck"/> <!-- don't call overridable method from constructor -->
<module name="RedundantReturnCheck"/> <!-- returns at end of void methods is pointless -->
<module name="ReturnBooleanFromTernaryCheck"/> <!-- use value inside condition -->
<module name="ReturnNullInsteadOfBooleanCheck"/> <!-- Boolean is NOT a ternary state object -->
<module name="SimpleAccessorNameNotationCheck"/> <!-- setters and getters must match to the field of the same name and type -->
<module name="SingleBreakOrContinueCheck"/> <!-- avoid complicated flow control -->
<module name="TernaryPerExpressionCountCheck"/> <!-- prevent nested ternary expressions -->
<module name="UselessSingleCatchCheck"/> <!-- prevent single catch blocks that just rethrow the original exception -->
<module name="UselessSuperCtorCallCheck"/> <!-- detects calls to super() when not needed -->
<!-- sevntu/design -->
<module name="AvoidConditionInversionCheck"/> <!-- catch condition inversion which could be more readable -->
<!--<module name="ChildBlockLengthCheck"/> &lt;!&ndash; broken in sevntu 1.20 - limit child blocks to 80% of parent block &ndash;&gt;-->
<module name="ConstructorWithoutParamsCheck"/> <!-- Exception classes must take parameters -->
<module name="ForbidWildcardAsReturnTypeCheck"/> <!-- forbid <? extends|super Object> generics as return types on public, protected and package methods -->
<module name="NestedSwitchCheck"/> <!-- prevent nested switch statements -->
<module name="NoMainMethodInAbstractClassCheck"/> <!-- Forbids main methods in abstract classes -->
<module name="PublicReferenceToPrivateTypeCheck"/> <!-- prevent attempt to expose private type -->
<!-- sevntu/naming -->
<module name="EnumValueNameCheck"/> <!-- validate enum value format -->
</module> </module>
<module name="SuppressWarningsFilter"/>
<module name="SuppressionCommentFilter"/>
</module> </module>

View file

@ -27,7 +27,7 @@
<parent> <parent>
<groupId>net.kemitix</groupId> <groupId>net.kemitix</groupId>
<artifactId>kemitix-parent</artifactId> <artifactId>kemitix-parent</artifactId>
<version>1.1.0</version> <version>1.2.0</version>
</parent> </parent>
<properties> <properties>

View file

@ -16,36 +16,56 @@ import javax.mail.internet.MimeMultipart;
/** /**
* Provides a set of assertions for checking the status of any messages received * Provides a set of assertions for checking the status of any messages received
* by subethamail's Wiser. * by subethamail's Wiser.
*
* <pre> * <pre>
* {@code * <code>
* {@literal @}Before * {@literal @}Before
* public void setUp() throws IOException { * public void setUp() throws IOException {
* wiser = new Wiser(PORT); * wiser = new Wiser(PORT);
* wiser.start(); * wiser.start();
* } * }
* *
* {@literal @}After public void tearDown() { wiser.stop(); } * {@literal @}After
* public void tearDown() {
* wiser.stop();
* }
* *
* {@literal @}Test public void testMail() { //given ... * {@literal @}Test
* * public void testMail() {
* //when ... * //given ...
* * //when ...
* //then WiserAssertions.assertReceivedMessage(wiser) .from(sender) * //then
* .to(recipient_alpha) .to(recipient_beta) .withSubjectContains(subject_prefix) * WiserAssertions.assertReceivedMessage(wiser)
* .withSubjectContains(subject_suffix) .withContentContains(message_element_1) * .from(sender)
* .withContentContains(message_element_2) * .to(recipient_alpha)
* .withContentContains(message_element_3); } * .to(recipient_beta)
* } * .withSubjectContains(subject_prefix)
* .withSubjectContains(subject_suffix)
* .withContentContains(message_element_1)
* .withContentContains(message_element_2)
* .withContentContains(message_element_3);
* }
* </code>
* </pre> * </pre>
*/ */
public final class WiserAssertions { public final class WiserAssertions {
private static final String ERROR_MESSAGE_SUBJECT
= "No message with subject [{0}] found!";
/** /**
* The messages received by Wiser. * The messages received by Wiser.
*/ */
private final List<WiserMessage> messages; private final List<WiserMessage> messages;
/**
* Private constructor.
*
* @param wiserMessages the messages to be tested by the assertions
*/
private WiserAssertions(final List<WiserMessage> wiserMessages) {
this.messages = wiserMessages;
}
/** /**
* Creates an instance of {@code} WiserAssertions} ready to make assertions * Creates an instance of {@code} WiserAssertions} ready to make assertions
* on any messages received by the {@link Wiser} server. * on any messages received by the {@link Wiser} server.
@ -58,15 +78,6 @@ public final class WiserAssertions {
return new WiserAssertions(wiser.getMessages()); return new WiserAssertions(wiser.getMessages());
} }
/**
* Private constructor.
*
* @param wiserMessages the messages to be tested by the assertions
*/
private WiserAssertions(final List<WiserMessage> wiserMessages) {
this.messages = wiserMessages;
}
/** /**
* Checks that there was at least one email received that was sent from the * Checks that there was at least one email received that was sent from the
* {@code sender}. * {@code sender}.
@ -81,6 +92,39 @@ public final class WiserAssertions {
return this; return this;
} }
/**
* 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);
}
/**
* 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));
}
/** /**
* Checks that there was at least one email received that was sent to the * Checks that there was at least one email received that was sent to the
* {@code recipient}. * {@code recipient}.
@ -104,14 +148,44 @@ public final class WiserAssertions {
* @return the {@code WiserAssertions} instance * @return the {@code WiserAssertions} instance
*/ */
public WiserAssertions withSubject(final String subject) { public WiserAssertions withSubject(final String subject) {
Predicate<WiserMessage> predicate Predicate<WiserMessage> predicate = m -> subject.equals(
= m -> subject.equals(unchecked(getMimeMessage(m)::getSubject)); unchecked(getMimeMessage(m)::getSubject));
findFirstOrElseThrow(predicate, findFirstOrElseThrow(predicate,
assertionError("No message with subject [{0}] found!", assertionError(ERROR_MESSAGE_SUBJECT, subject));
subject));
return this; return this;
} }
/**
* 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
*/
@SuppressWarnings("illegalCatch")
public static <T> T unchecked(final ThrowingSupplier<T> supplier) {
try {
return supplier.get();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 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);
}
/** /**
* Checks that there was at least one email received that has a subject that * Checks that there was at least one email received that has a subject that
* contains the search text. * contains the search text.
@ -121,12 +195,10 @@ public final class WiserAssertions {
* @return the {@code WiserAssertions} instance * @return the {@code WiserAssertions} instance
*/ */
public WiserAssertions withSubjectContains(final String subject) { public WiserAssertions withSubjectContains(final String subject) {
Predicate<WiserMessage> predicate Predicate<WiserMessage> predicate = m -> unchecked(
= m -> unchecked(getMimeMessage(m)::getSubject) getMimeMessage(m)::getSubject).contains(subject);
.contains(subject);
findFirstOrElseThrow(predicate, findFirstOrElseThrow(predicate,
assertionError("No message with subject [{0}] found!", assertionError(ERROR_MESSAGE_SUBJECT, subject));
subject));
return this; return this;
} }
@ -140,8 +212,8 @@ public final class WiserAssertions {
*/ */
public WiserAssertions withContent(final String content) { public WiserAssertions withContent(final String content) {
findFirstOrElseThrow(m -> { findFirstOrElseThrow(m -> {
ThrowingSupplier<String> contentAsString ThrowingSupplier<String> contentAsString = () -> getMimeMessageBody(
= () -> getMimeMessageBody(m).trim(); m).trim();
return content.equals(unchecked(contentAsString)); return content.equals(unchecked(contentAsString));
}, assertionError("No message with content [{0}] found!", content)); }, assertionError("No message with content [{0}] found!", content));
return this; return this;
@ -158,8 +230,8 @@ public final class WiserAssertions {
public WiserAssertions withContentContains(final String content) { public WiserAssertions withContentContains(final String content) {
StringBuilder messageContent = new StringBuilder(); StringBuilder messageContent = new StringBuilder();
findFirstOrElseThrow((WiserMessage m) -> { findFirstOrElseThrow((WiserMessage m) -> {
ThrowingSupplier<String> contentAsString ThrowingSupplier<String> contentAsString = () -> getMimeMessageBody(
= () -> getMimeMessageBody(m).trim(); m).trim();
messageContent.append(unchecked(contentAsString)); messageContent.append(unchecked(contentAsString));
return unchecked(contentAsString).contains(content); return unchecked(contentAsString).contains(content);
}, assertionError( }, assertionError(
@ -181,80 +253,20 @@ public final class WiserAssertions {
private String getMimeMessageBody(final WiserMessage message) private String getMimeMessageBody(final WiserMessage message)
throws IOException, MessagingException { throws IOException, MessagingException {
Object content = getMimeMessage(message).getContent(); Object content = getMimeMessage(message).getContent();
String result = null;
if (content instanceof String) { if (content instanceof String) {
return (String) content; result = (String) content;
} }
if (content instanceof MimeMessage) { if (content instanceof MimeMessage) {
return content.toString(); result = content.toString();
} }
if (content instanceof MimeMultipart) { if (content instanceof MimeMultipart) {
return getMimeMultipartAsString((MimeMultipart) content); result = getMimeMultipartAsString((MimeMultipart) content);
} }
throw new RuntimeException("Unexpected MimeMessage content"); if (result == null) {
} throw new RuntimeException("Unexpected MimeMessage content");
/**
* 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);
}
/**
* 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);
}
/**
* 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));
}
/**
* 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) {
throw new RuntimeException(e);
} }
return result;
} }
/** /**
@ -297,6 +309,7 @@ public final class WiserAssertions {
* *
* @throws Throwable on error * @throws Throwable on error
*/ */
@SuppressWarnings("illegalthrows")
T get() throws Throwable; T get() throws Throwable;
} }
} }