Tidy up and refactoring

This commit is contained in:
Paul Campbell 2018-09-01 06:53:40 +01:00
parent 532499dbf4
commit e622a1b641

View file

@ -21,12 +21,14 @@
package net.kemitix.wiser.assertions; package net.kemitix.wiser.assertions;
import net.kemitix.mon.maybe.Maybe;
import org.subethamail.wiser.Wiser; import org.subethamail.wiser.Wiser;
import org.subethamail.wiser.WiserMessage; import org.subethamail.wiser.WiserMessage;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -71,8 +73,10 @@ import javax.mail.internet.MimeMultipart;
@SuppressWarnings("methodcount") @SuppressWarnings("methodcount")
public final class WiserAssertions { public final class WiserAssertions {
private static final String ERROR_MESSAGE_SUBJECT private static final String ERROR_MESSAGE_SUBJECT = "No message with subject [{0}] found!";
= "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. * The messages received by Wiser.
@ -109,26 +113,15 @@ public final class WiserAssertions {
* @return the {@code WiserAssertions} instance * @return the {@code WiserAssertions} instance
*/ */
public WiserAssertions from(final String sender) { public WiserAssertions from(final String sender) {
findFirstOrElseThrow(m -> m.getEnvelopeSender().equals(sender), messageMatches(m -> m.getEnvelopeSender().equals(sender))
assertionError("No message from [{0}] found!", sender)); .orElseThrow(assertionError("No message from [{0}] found!", sender));
return this; return this;
} }
/** private Optional<WiserMessage> messageMatches(final Predicate<WiserMessage> predicate) {
* 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
* @return the first WiserMessage
*/
private WiserMessage findFirstOrElseThrow(
final Predicate<WiserMessage> predicate,
final Supplier<AssertionError> exceptionSupplier) {
return messages.stream() return messages.stream()
.filter(predicate) .filter(predicate)
.findFirst() .findAny();
.orElseThrow(exceptionSupplier);
} }
/** /**
@ -142,10 +135,8 @@ public final class WiserAssertions {
*/ */
@SuppressWarnings( @SuppressWarnings(
{"ThrowableInstanceNotThrown", "ThrowableInstanceNeverThrown"}) {"ThrowableInstanceNotThrown", "ThrowableInstanceNeverThrown"})
private static Supplier<AssertionError> assertionError( private static Supplier<AssertionError> assertionError(final String errorMessage, final Object... args) {
final String errorMessage, final Object... args) { return () -> new AssertionError(MessageFormat.format(errorMessage, args));
return () -> new AssertionError(
MessageFormat.format(errorMessage, args));
} }
/** /**
@ -157,8 +148,8 @@ public final class WiserAssertions {
* @return the {@code WiserAssertions} instance * @return the {@code WiserAssertions} instance
*/ */
public WiserAssertions to(final String recipient) { public WiserAssertions to(final String recipient) {
findFirstOrElseThrow(m -> m.getEnvelopeReceiver().equals(recipient), messageMatches(m -> m.getEnvelopeReceiver().equals(recipient))
assertionError("No message to [{0}] found!", recipient)); .orElseThrow(assertionError(ERROR_MESSAGE_TO, recipient));
return this; return this;
} }
@ -171,44 +162,19 @@ 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 = m -> subject.equals( messageMatches(m -> subject(m).equals(subject))
unchecked(getMimeMessage(m)::getSubject)); .orElseThrow(assertionError(ERROR_MESSAGE_SUBJECT, subject));
findFirstOrElseThrow(predicate,
assertionError(ERROR_MESSAGE_SUBJECT, subject));
return this; return this;
} }
/** private String subject(final WiserMessage wiserMessage) {
* 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 { try {
return supplier.get(); return wiserMessage.getMimeMessage().getSubject();
} catch (Throwable e) { } catch (MessagingException e) {
throw new WiserAssertionException(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 * Checks that there was at least one email received that has a subject that
* contains the search text. * contains the search text.
@ -218,10 +184,8 @@ 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 = m -> unchecked( messageMatches(m -> subject(m).contains(subject))
getMimeMessage(m)::getSubject).contains(subject); .orElseThrow(assertionError(ERROR_MESSAGE_SUBJECT, subject));
findFirstOrElseThrow(predicate,
assertionError(ERROR_MESSAGE_SUBJECT, subject));
return this; return this;
} }
@ -234,14 +198,51 @@ public final class WiserAssertions {
* @return the {@code WiserAssertions} instance * @return the {@code WiserAssertions} instance
*/ */
public WiserAssertions withContent(final String content) { public WiserAssertions withContent(final String content) {
findFirstOrElseThrow(m -> { messageMatches(m -> messageBody(m).trim().equals(content.trim()))
ThrowingSupplier<String> contentAsString = () -> getMimeMessageBody( .orElseThrow(assertionError(ERROR_MESSAGE_CONTENT, content));
m).trim();
return content.equals(unchecked(contentAsString));
}, assertionError("No message with content [{0}] found!", content));
return this; 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 * Check that there was at least one email received that contains the search
* text. * text.
@ -251,48 +252,11 @@ public final class WiserAssertions {
* @return the {@code WiserAssertions} instance * @return the {@code WiserAssertions} instance
*/ */
public WiserAssertions withContentContains(final String content) { public WiserAssertions withContentContains(final String content) {
StringBuilder messageContent = new StringBuilder(); messageMatches((WiserMessage m) -> messageBody(m).trim().contains(content))
findFirstOrElseThrow((WiserMessage m) -> { .orElseThrow(assertionError(ERROR_MESSAGE_CONTENT_CONTAINS, content));
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));
return this; 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 {
final 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 MimeMessageException("Unexpected MimeMessage content");
}
return result;
}
/** /**
* Converts a {@link MimeMultipart} into a {@link String} stripping out the * Converts a {@link MimeMultipart} into a {@link String} stripping out the
* mime part boundary and headers.. * mime part boundary and headers..
@ -318,22 +282,4 @@ public final class WiserAssertions {
return sb.toString(); 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;
}
} }