commit
41e90e35d0
11 changed files with 189 additions and 384 deletions
19
CHANGELOG
19
CHANGELOG
|
@ -1,6 +1,25 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.5.0
|
||||
-----
|
||||
|
||||
* Compatible with Java 10
|
||||
* Bump kemitix-parent from 1.1.0 to 5.1.1
|
||||
* Use kemitix-checkstyle-ruleset 4.1.1
|
||||
* Don't throw generic exceptions
|
||||
* Add mon 0.12.0 as dependency
|
||||
* Bump tiles-maven-plugin from 2.11 to 2.12
|
||||
* [testing] Use a free port for test mail server
|
||||
* [testing] Bump mockito-core from 1.10.19 to 2.21.0
|
||||
* [testing] Bump spring-context-support from 4.2.6.RELEASE to 5.0.8.RELEASE
|
||||
* [testing] Bump simple-java-mail from 3.0.1 to 3.1.1
|
||||
* [admin] Simpliify .gitignore
|
||||
* [admin] Remove old netbeans config
|
||||
* [admin] Switch to trunk based development
|
||||
* [admin] Stop submitting coverage reports to coveralls
|
||||
* [admin] Switch to Jenkins for CI/CD
|
||||
|
||||
0.4.0
|
||||
------
|
||||
|
||||
|
|
207
checkstyle.xml
207
checkstyle.xml
|
@ -1,207 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!-- Template checkstyle rules primarily intented for use with projects based on the kemitix-parent POM -->
|
||||
<!-- -->
|
||||
<!-- See http://checkstyle.sourceforge.net/checks.html for documentation on each rule. -->
|
||||
|
||||
<module name="Checker">
|
||||
|
||||
<module name="JavadocPackage"/> <!-- package-info.java must exist -->
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="lineSeparator" value="lf"/> <!-- must use unix line endings -->
|
||||
</module>
|
||||
<module name="FileLength"/> <!-- files must be less than 2000 lines -->
|
||||
<module name="FileTabCharacter"/> <!-- tabs not allowed -->
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
</module>
|
||||
<module name="SuppressWarningsFilter"/> <!-- enable @SuppressWarnings for checkstyle rules -->
|
||||
|
||||
<module name="TreeWalker">
|
||||
|
||||
<module name="AbbreviationAsWordInName"/> <!-- enforce proper CamelCase -->
|
||||
<module name="AbstractClassName"/> <!-- enforce Abstract.* in abstract class names -->
|
||||
<module name="AnnotationLocation"/> <!-- annotations should be on line by themselves -->
|
||||
<module name="AnnotationUseStyle"/> <!-- annotations should only use () and named attributes when needed -->
|
||||
<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)-->
|
||||
<module name="ArrayTypeStyle"/> <!-- enforce Java style arrays -->
|
||||
<module name="AtclauseOrder"/> <!-- enforce standard order for javadoc elements -->
|
||||
<module name="AvoidEscapedUnicodeCharacters"> <!-- prevent use of obscure escape codes -->
|
||||
<property name="allowEscapesForControlCharacters" value="true"/> <!-- unless non-printable controls -->
|
||||
</module>
|
||||
<module name="AvoidNestedBlocks"/> <!-- avoid unnecessary blocks {} -->
|
||||
<module name="AvoidStarImport"/> <!-- import package.* is not allowed -->
|
||||
<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 -->
|
||||
</module>
|
||||
<module name="BooleanExpressionComplexity"> <!-- restrict number of &&, ||, &, | and ^ expressions -->
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<module name="CatchParameterName"/> <!-- restrict parameter names when catching an Exception -->
|
||||
<module name="ClassDataAbstractionCoupling"/> <!-- restrict number of classes instantiated per class to 7 -->
|
||||
<module name="ClassFanOutComplexity"/> <!-- restrict class dependencies to 20 -->
|
||||
<module name="ClassTypeParameterName"/> <!-- restrict class type parameters (i.e. generics) to ^[A-Z]$ -->
|
||||
<module name="ConstantName"/> <!-- force all uppercase for static final fields -->
|
||||
<module name="CommentsIndentation"/> <!-- enforce comment indentation to match surrounding code -->
|
||||
<module name="CovariantEquals"/> <!-- ensure correct version of equals() is implemented -->
|
||||
<module name="CyclomaticComplexity"> <!-- limit complexity score -->
|
||||
<property name="max" value="5"/>
|
||||
</module>
|
||||
<module name="DeclarationOrder"/> <!-- enforce order: static variables, variables, constructors, methods -->
|
||||
<module name="DefaultComesLast"/> <!-- enforce default as last option in switch statement -->
|
||||
<module name="DesignForExtension"/> <!-- protect against bad subclassing - use interfaces for mocking in unit tests -->
|
||||
<module name="EmptyBlock"/> <!-- checks for empty blocks -->
|
||||
<module name="EmptyCatchBlock"> <!-- checks the catch blocks contain comment -->
|
||||
<property name="commentFormat" value="expected|ignore"/>
|
||||
</module>
|
||||
<module name="EmptyForInitializerPad"/> <!-- empty for loop initializer must have no spaces -->
|
||||
<module name="EmptyForIteratorPad"/> <!-- empty for loop iterator muse have have no spaces -->
|
||||
<module name="EmptyLineSeparator"/> <!-- enforce blank lines after header, fields, constructors, methods, etc -->
|
||||
<module name="EmptyStatement"/> <!-- prevent standalone ";" semicolons -->
|
||||
<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 -->
|
||||
<module name="FallThrough"/> <!-- checks that each switch case fall-through is commented as such -->
|
||||
<module name="FinalClass"/> <!-- class which has only private constructors is declared as final -->
|
||||
<!--<module name="FinalLocalVariable"/> <!– incompatible with lombok's val - local variables that never change must be declared final –>-->
|
||||
<module name="FinalParameters"/> <!-- parameters that never change must be declared final -->
|
||||
<module name="GenericWhitespace"/> <!-- generic tokens are spaced correctly -->
|
||||
<module name="HiddenField">
|
||||
<property name="ignoreConstructorParameter" value="true"/>
|
||||
<property name="ignoreSetter" value="true"/>
|
||||
</module>
|
||||
<module name="HideUtilityClassConstructor"/> <!-- suppress for class with public static void main(...) -->
|
||||
<module name="IllegalCatch"/> <!-- prevent generic catches (i.e. Exception, Throwable, RuntimeException) -->
|
||||
<module name="IllegalImport"/> <!-- prevent imports from the sun.* package -->
|
||||
<module name="IllegalThrows"/> <!-- prevent generic throws (i.e. Exception, Throwable, RuntimeException) -->
|
||||
<module name="IllegalType"/> <!-- prevents variables, returns or parameters of non-interface Collections classes -->
|
||||
<!--<module name="Indentation"/> <!– incompatible with preferred indentation - correct indentation of Java code –>-->
|
||||
<module name="InnerAssignment"/> <!-- prevent assignments in subexpressions (i.e. while((line = read()){}) -->
|
||||
<module name="InnerTypeLast"/> <!-- inner classes appear after methods and fields -->
|
||||
<module name="InterfaceIsType"/> <!-- interface must define method not just constants -->
|
||||
<module name="JavaNCSS"/> <!-- Non-Commenting Source Statements complexity analysis -->
|
||||
<module name="JavadocMethod"> <!-- methods should have javadoc block -->
|
||||
<property name="scope" value="public"/> <!-- if they are public -->
|
||||
</module>
|
||||
<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 -->
|
||||
<module name="LeftCurly"/> <!-- placement of left curly braces ('{') for code blocks at end of line -->
|
||||
<module name="LineLength"/> <!-- lines can't be longer the 80 -->
|
||||
<module name="LocalFinalVariableName"/> <!-- validates identifiers for local, final variables, including catch parameters -->
|
||||
<module name="LocalVariableName"/> <!-- validates non-final identifiers -->
|
||||
<module name="MagicNumber"/> <!-- checks for magic numbers -->
|
||||
<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"/> <!– broken in sevntu 1.20 - limit child blocks to 80% of parent block –>-->
|
||||
<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>
|
|
@ -1,39 +0,0 @@
|
|||
<?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>
|
6
pom.xml
6
pom.xml
|
@ -49,9 +49,15 @@
|
|||
<jacoco-class-line-covered-ratio>0</jacoco-class-line-covered-ratio>
|
||||
<jacoco-class-instruction-covered-ratio>0</jacoco-class-instruction-covered-ratio>
|
||||
<jacoco-class-missed-count-maximum>1</jacoco-class-missed-count-maximum>
|
||||
<mon.version>0.12.0</mon.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.kemitix</groupId>
|
||||
<artifactId>mon</artifactId>
|
||||
<version>${mon.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Paul Campbell
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies
|
||||
* or substantial portions of the Software.
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Assertions caused by errors while parsing mime message content.
|
||||
*
|
||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||
*/
|
||||
public class MimeMessageException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Create an assertion with a message.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
public MimeMessageException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Paul Campbell
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies
|
||||
* or substantial portions of the Software.
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Assertions caused by {@link WiserAssertions}.
|
||||
*
|
||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||
*/
|
||||
public class WiserAssertionException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Create a wrapper for the cause.
|
||||
*
|
||||
* @param cause the original exception
|
||||
*/
|
||||
public WiserAssertionException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,12 +21,14 @@
|
|||
|
||||
package net.kemitix.wiser.assertions;
|
||||
|
||||
import net.kemitix.mon.maybe.Maybe;
|
||||
import org.subethamail.wiser.Wiser;
|
||||
import org.subethamail.wiser.WiserMessage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
@ -71,8 +73,10 @@ import javax.mail.internet.MimeMultipart;
|
|||
@SuppressWarnings("methodcount")
|
||||
public final class WiserAssertions {
|
||||
|
||||
private static final String ERROR_MESSAGE_SUBJECT
|
||||
= "No message with subject [{0}] found!";
|
||||
private static final String ERROR_MESSAGE_SUBJECT = "No message with subject [{0}] found!";
|
||||
private static final String ERROR_MESSAGE_CONTENT_CONTAINS = "No message with content containing [{0}] found!";
|
||||
private static final String ERROR_MESSAGE_CONTENT = "No message with content [{0}] found!";
|
||||
private static final String ERROR_MESSAGE_TO = "No message to [{0}] found!";
|
||||
|
||||
/**
|
||||
* The messages received by Wiser.
|
||||
|
@ -109,25 +113,15 @@ public final class WiserAssertions {
|
|||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions from(final String sender) {
|
||||
findFirstOrElseThrow(m -> m.getEnvelopeSender().equals(sender),
|
||||
assertionError("No message from [{0}] found!", sender));
|
||||
messageMatches(m -> m.getEnvelopeSender().equals(sender))
|
||||
.orElseThrow(assertionError("No message from [{0}] found!", sender));
|
||||
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()
|
||||
private Optional<WiserMessage> messageMatches(final Predicate<WiserMessage> predicate) {
|
||||
return messages.stream()
|
||||
.filter(predicate)
|
||||
.findFirst()
|
||||
.orElseThrow(exceptionSupplier);
|
||||
.findAny();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,10 +135,8 @@ public final class WiserAssertions {
|
|||
*/
|
||||
@SuppressWarnings(
|
||||
{"ThrowableInstanceNotThrown", "ThrowableInstanceNeverThrown"})
|
||||
private static Supplier<AssertionError> assertionError(
|
||||
final String errorMessage, final Object... args) {
|
||||
return () -> new AssertionError(
|
||||
MessageFormat.format(errorMessage, args));
|
||||
private static Supplier<AssertionError> assertionError(final String errorMessage, final Object... args) {
|
||||
return () -> new AssertionError(MessageFormat.format(errorMessage, args));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,8 +148,8 @@ public final class WiserAssertions {
|
|||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions to(final String recipient) {
|
||||
findFirstOrElseThrow(m -> m.getEnvelopeReceiver().equals(recipient),
|
||||
assertionError("No message to [{0}] found!", recipient));
|
||||
messageMatches(m -> m.getEnvelopeReceiver().equals(recipient))
|
||||
.orElseThrow(assertionError(ERROR_MESSAGE_TO, recipient));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -170,44 +162,19 @@ public final class WiserAssertions {
|
|||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions withSubject(final String subject) {
|
||||
Predicate<WiserMessage> predicate = m -> subject.equals(
|
||||
unchecked(getMimeMessage(m)::getSubject));
|
||||
findFirstOrElseThrow(predicate,
|
||||
assertionError(ERROR_MESSAGE_SUBJECT, subject));
|
||||
messageMatches(m -> subject(m).equals(subject))
|
||||
.orElseThrow(assertionError(ERROR_MESSAGE_SUBJECT, subject));
|
||||
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) {
|
||||
private String subject(final WiserMessage wiserMessage) {
|
||||
try {
|
||||
return supplier.get();
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
return wiserMessage.getMimeMessage().getSubject();
|
||||
} catch (MessagingException e) {
|
||||
throw new IllegalArgumentException("Invalid email message", 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
|
||||
* contains the search text.
|
||||
|
@ -217,10 +184,8 @@ public final class WiserAssertions {
|
|||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions withSubjectContains(final String subject) {
|
||||
Predicate<WiserMessage> predicate = m -> unchecked(
|
||||
getMimeMessage(m)::getSubject).contains(subject);
|
||||
findFirstOrElseThrow(predicate,
|
||||
assertionError(ERROR_MESSAGE_SUBJECT, subject));
|
||||
messageMatches(m -> subject(m).contains(subject))
|
||||
.orElseThrow(assertionError(ERROR_MESSAGE_SUBJECT, subject));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -233,14 +198,51 @@ public final class WiserAssertions {
|
|||
* @return the {@code WiserAssertions} instance
|
||||
*/
|
||||
public WiserAssertions withContent(final String content) {
|
||||
findFirstOrElseThrow(m -> {
|
||||
ThrowingSupplier<String> contentAsString = () -> getMimeMessageBody(
|
||||
m).trim();
|
||||
return content.equals(unchecked(contentAsString));
|
||||
}, assertionError("No message with content [{0}] found!", content));
|
||||
messageMatches(m -> messageBody(m).trim().equals(content.trim()))
|
||||
.orElseThrow(assertionError(ERROR_MESSAGE_CONTENT, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
private String messageBody(final WiserMessage m) {
|
||||
try {
|
||||
return messageBody(m.getMimeMessage().getContent());
|
||||
} catch (IOException | MessagingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String messageBody(final Object content) {
|
||||
return contentAsString(content)
|
||||
.or(() -> contentAsMimeMessage(content))
|
||||
.or(() -> contentAsMultiPartMime(content))
|
||||
.orElseThrow(() -> new RuntimeException("Unexpected MimeMessage content"));
|
||||
}
|
||||
|
||||
private Maybe<String> contentAsString(final Object content) {
|
||||
if (content instanceof String) {
|
||||
return Maybe.just((String) content);
|
||||
}
|
||||
return Maybe.nothing();
|
||||
}
|
||||
|
||||
private Maybe<String> contentAsMimeMessage(final Object content) {
|
||||
if (content instanceof MimeMessage) {
|
||||
return Maybe.just(content.toString());
|
||||
}
|
||||
return Maybe.nothing();
|
||||
}
|
||||
|
||||
private Maybe<String> contentAsMultiPartMime(final Object content) {
|
||||
if (content instanceof MimeMultipart) {
|
||||
try {
|
||||
return Maybe.just(getMimeMultipartAsString((MimeMultipart) content));
|
||||
} catch (MessagingException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return Maybe.nothing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that there was at least one email received that contains the search
|
||||
* text.
|
||||
|
@ -250,48 +252,11 @@ public final class WiserAssertions {
|
|||
* @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));
|
||||
messageMatches((WiserMessage m) -> messageBody(m).trim().contains(content))
|
||||
.orElseThrow(assertionError(ERROR_MESSAGE_CONTENT_CONTAINS, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@SuppressWarnings("npathcomplexity")
|
||||
private String getMimeMessageBody(final WiserMessage message)
|
||||
throws IOException, MessagingException {
|
||||
Object content = getMimeMessage(message).getContent();
|
||||
String result = null;
|
||||
if (content instanceof String) {
|
||||
result = (String) content;
|
||||
}
|
||||
if (content instanceof MimeMessage) {
|
||||
result = content.toString();
|
||||
}
|
||||
if (content instanceof MimeMultipart) {
|
||||
result = getMimeMultipartAsString((MimeMultipart) content);
|
||||
}
|
||||
if (result == null) {
|
||||
throw new RuntimeException("Unexpected MimeMessage content");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link MimeMultipart} into a {@link String} stripping out the
|
||||
* mime part boundary and headers..
|
||||
|
@ -317,22 +282,4 @@ public final class WiserAssertions {
|
|||
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
|
||||
*/
|
||||
@SuppressWarnings("illegalthrows")
|
||||
T get() throws Throwable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ abstract class AbstractWiserTest {
|
|||
*
|
||||
* @return the wiser assertions
|
||||
*/
|
||||
protected WiserAssertions getAssertions() {
|
||||
protected WiserAssertions assertReceivedMessage() {
|
||||
return WiserAssertions.assertReceivedMessage(wiser);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ public class Issue1Test extends AbstractWiserTest {
|
|||
//when
|
||||
mailer.sendMail(email);
|
||||
//then
|
||||
getAssertions().withContentContains("Hi Carl");
|
||||
assertReceivedMessage().withContentContains("Hi Carl");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ public class Issue6Test extends AbstractWiserTest {
|
|||
//when
|
||||
sender.send(message);
|
||||
//then
|
||||
getAssertions().from("bob@a.com").to("carl@b.com")
|
||||
.withSubject("Subject")
|
||||
.withContentContains("Hi Carl");
|
||||
assertReceivedMessage().from("bob@a.com").to("carl@b.com")
|
||||
.withSubject("Subject")
|
||||
.withContentContains("Hi Carl");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject", body);
|
||||
//then
|
||||
getAssertions().withContent(body);
|
||||
assertReceivedMessage().withContent(body);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,7 +82,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject", body);
|
||||
//then
|
||||
getAssertions().withContent("Other body");
|
||||
assertReceivedMessage().withContent("Other body");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,7 +96,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject", body);
|
||||
//then
|
||||
getAssertions().withContentContains("age bo");
|
||||
assertReceivedMessage().withContentContains("age bo");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,7 +110,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject", body);
|
||||
//then
|
||||
getAssertions().withContentContains("agebo");
|
||||
assertReceivedMessage().withContentContains("agebo");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +126,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage(from, "to", "subject", "body");
|
||||
//then
|
||||
getAssertions().from(from);
|
||||
assertReceivedMessage().from(from);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,7 +140,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage(from, "to", "subject", "body");
|
||||
//then
|
||||
getAssertions().from("lisa@c.com");
|
||||
assertReceivedMessage().from("lisa@c.com");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,7 +149,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
*/
|
||||
@Test
|
||||
public void testInstantiate() {
|
||||
assertNotNull(getAssertions());
|
||||
assertNotNull(assertReceivedMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +164,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
sendMimeMultipartMessage(
|
||||
"from", "to", "subject " + fragment + " tail", "body");
|
||||
//then
|
||||
getAssertions().withSubjectContains(fragment);
|
||||
assertReceivedMessage().withSubjectContains(fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,7 +178,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", "to", "subject tail", "body");
|
||||
//then
|
||||
getAssertions().withSubjectContains(fragment);
|
||||
assertReceivedMessage().withSubjectContains(fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -192,7 +192,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", "to", subject, "body");
|
||||
//then
|
||||
getAssertions().withSubject(subject);
|
||||
assertReceivedMessage().withSubject(subject);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,7 +206,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", "to", subject, "body");
|
||||
//then
|
||||
getAssertions().withSubject("other subject");
|
||||
assertReceivedMessage().withSubject("other subject");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -220,7 +220,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", to, "subject", "body");
|
||||
//then
|
||||
getAssertions().to(to);
|
||||
assertReceivedMessage().to(to);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,7 +235,7 @@ public class WiserAssertionsTest extends AbstractWiserTest {
|
|||
//when
|
||||
sendMimeMultipartMessage("from", to, "subject", "body");
|
||||
//then
|
||||
getAssertions().to("bob@a.com");
|
||||
assertReceivedMessage().to("bob@a.com");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue