This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 5a192d585c9a3ee26bdff2dc4a7501dbc87a77b5 Author: Benoit Tellier <btell...@linagora.com> AuthorDate: Wed Aug 21 15:04:20 2019 +0700 JAMES-2866 JSON serialization for Condition --- server/mailet/mock-smtp-server/pom.xml | 5 + .../apache/james/mock/smtp/server/Condition.java | 111 ++++++++++++++++----- .../apache/james/mock/smtp/server/Operator.java | 60 ++++++++++- .../james/mock/smtp/server/ConditionTest.java | 95 +++++++++++++++--- 4 files changed, 232 insertions(+), 39 deletions(-) diff --git a/server/mailet/mock-smtp-server/pom.xml b/server/mailet/mock-smtp-server/pom.xml index 8db2a69..bdcbea7 100644 --- a/server/mailet/mock-smtp-server/pom.xml +++ b/server/mailet/mock-smtp-server/pom.xml @@ -50,6 +50,11 @@ <artifactId>guava</artifactId> </dependency> <dependency> + <groupId>net.javacrumbs.json-unit</groupId> + <artifactId>json-unit-assertj</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>nl.jqno.equalsverifier</groupId> <artifactId>equalsverifier</artifactId> <scope>test</scope> diff --git a/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/Condition.java b/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/Condition.java index 422eea7..523794b 100644 --- a/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/Condition.java +++ b/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/Condition.java @@ -20,43 +20,106 @@ package org.apache.james.mock.smtp.server; import java.util.Objects; +import java.util.Optional; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.google.common.base.Preconditions; -class Condition { +@JsonDeserialize(builder = Condition.Builder.class) +interface Condition { + @JsonPOJOBuilder(withPrefix = "") + class Builder { + private Operator.OperatorName operator; + private Optional<String> matchingValue; - static final Condition MATCH_ALL = new Condition(Operator.MATCH_ALL, "any"); + public Builder() { + this.matchingValue = Optional.empty(); + } - private final Operator operator; - private final String matchingValue; + public Builder operator(Operator.OperatorName operator) { + this.operator = operator; + return this; + } - Condition(Operator operator, String matchingValue) { - Preconditions.checkNotNull(operator); - Preconditions.checkNotNull(matchingValue); + public Builder matchingValue(String matchingValue) { + this.matchingValue = Optional.of(matchingValue); + return this; + } - this.operator = operator; - this.matchingValue = matchingValue; - } + public Condition build() { + Preconditions.checkState(operator != null, "You need to specify an operator"); - boolean matches(String line) { - return operator.actual(line) - .expected(matchingValue) - .matches(); + return operator.getConditionFactory().apply(matchingValue); + } } - @Override - public final boolean equals(Object o) { - if (o instanceof Condition) { - Condition condition = (Condition) o; + class MatchAllCondition implements Condition { + public Operator.OperatorName getOperator() { + return Operator.OperatorName.MATCH_ALL; + } - return Objects.equals(this.operator, condition.operator) - && Objects.equals(this.matchingValue, condition.matchingValue); + @Override + public boolean matches(String line) { + return true; + } + + @Override + public final boolean equals(Object o) { + return o instanceof MatchAllCondition; + } + + @Override + public final int hashCode() { + return Objects.hash(MatchAllCondition.class); } - return false; } - @Override - public final int hashCode() { - return Objects.hash(operator, matchingValue); + class OperatorCondition implements Condition { + private final Operator operator; + private final String matchingValue; + + OperatorCondition(Operator operator, String matchingValue) { + Preconditions.checkNotNull(operator); + Preconditions.checkNotNull(matchingValue); + + this.operator = operator; + this.matchingValue = matchingValue; + } + + public Operator.OperatorName getOperator() { + return operator.getOperatorName(); + } + + public String getMatchingValue() { + return matchingValue; + } + + @Override + public boolean matches(String line) { + return operator.actual(line) + .expected(matchingValue) + .matches(); + } + + @Override + public final boolean equals(Object o) { + if (o instanceof OperatorCondition) { + OperatorCondition condition = (OperatorCondition) o; + + return Objects.equals(this.operator, condition.operator) + && Objects.equals(this.matchingValue, condition.matchingValue); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(operator, matchingValue); + } } + + Condition MATCH_ALL = new MatchAllCondition(); + + boolean matches(String line); } diff --git a/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/Operator.java b/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/Operator.java index 26947c0..d56e04c 100644 --- a/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/Operator.java +++ b/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/Operator.java @@ -19,7 +19,52 @@ package org.apache.james.mock.smtp.server; +import java.util.Arrays; +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; + public interface Operator { + enum OperatorName { + CONTAINS("contains", maybeMatchingValue -> { + Preconditions.checkState(maybeMatchingValue.isPresent(), "You need to specify a matchingValue with the contains operator"); + + return new Condition.OperatorCondition(Operator.CONTAINS, maybeMatchingValue.get()); + }), + MATCH_ALL("matchAll", maybeMatchingValue -> { + Preconditions.checkState(!maybeMatchingValue.isPresent(), "You should not specify a matchingValue with the matchAll operator"); + + return new Condition.MatchAllCondition(); + }); + + private final String name; + private final Function<Optional<String>, Condition> conditionFactory; + + @JsonCreator + public static OperatorName from(String name) { + return Arrays.stream(values()) + .filter(value -> value.name.equals(name)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unsuported " + name + " operator")); + } + + OperatorName(String name, Function<Optional<String>, Condition> conditionFactory) { + this.name = name; + this.conditionFactory = conditionFactory; + } + + @JsonValue + public String getName() { + return name; + } + + public Function<Optional<String>, Condition> getConditionFactory() { + return conditionFactory; + } + } @FunctionalInterface interface Expected { @@ -31,8 +76,19 @@ public interface Operator { boolean matches(); } - Operator CONTAINS = actual -> expected -> () -> actual.contains(expected); - Operator MATCH_ALL = actual -> expected -> () -> true; + Operator CONTAINS = new Operator() { + @Override + public Expected actual(String actual) { + return expected -> () -> actual.contains(expected); + } + + @Override + public OperatorName getOperatorName() { + return OperatorName.CONTAINS; + } + }; Expected actual(String actual); + + OperatorName getOperatorName(); } diff --git a/server/mailet/mock-smtp-server/src/test/java/org/apache/james/mock/smtp/server/ConditionTest.java b/server/mailet/mock-smtp-server/src/test/java/org/apache/james/mock/smtp/server/ConditionTest.java index e5fe70a..eefbe1c 100644 --- a/server/mailet/mock-smtp-server/src/test/java/org/apache/james/mock/smtp/server/ConditionTest.java +++ b/server/mailet/mock-smtp-server/src/test/java/org/apache/james/mock/smtp/server/ConditionTest.java @@ -19,35 +19,54 @@ package org.apache.james.mock.smtp.server; +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; + import nl.jqno.equalsverifier.EqualsVerifier; class ConditionTest { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + @Test + void operatorConditionShouldMatchBeanContract() { + EqualsVerifier.forClass(Condition.OperatorCondition.class) + .verify(); + } + @Test - void shouldMatchBeanContract() { - EqualsVerifier.forClass(Condition.class) + void matchAllShouldMatchBeanContract() { + EqualsVerifier.forClass(Condition.MatchAllCondition.class) .verify(); } @Test + void differentConditionTypesShouldNotBeEqual() { + assertThat(Condition.MATCH_ALL) + .isNotEqualTo(new Condition.OperatorCondition(Operator.CONTAINS, "any")); + } + + @Test void constructorShouldThrowWhenNullOperator() { - assertThatThrownBy(() -> new Condition(null, "matchingValue")) + assertThatThrownBy(() -> new Condition.OperatorCondition(null, "matchingValue")) .isInstanceOf(NullPointerException.class); } @Test void constructorShouldThrowWhenNullMatchingValue() { - assertThatThrownBy(() -> new Condition(Operator.CONTAINS, null)) + assertThatThrownBy(() -> new Condition.OperatorCondition(Operator.CONTAINS, null)) .isInstanceOf(NullPointerException.class); } @Test void matchesShouldReturnTrueWhenOperatorMatches() { - Condition condition = new Condition(Operator.CONTAINS, "match me"); + Condition condition = new Condition.OperatorCondition(Operator.CONTAINS, "match me"); assertThat(condition.matches("this contains match me string")) .isTrue(); @@ -55,7 +74,7 @@ class ConditionTest { @Test void matchesShouldReturnFalseWhenOperatorDoesNotMatch() { - Condition condition = new Condition(Operator.CONTAINS, "match me"); + Condition condition = new Condition.OperatorCondition(Operator.CONTAINS, "match me"); assertThat(condition.matches("this contains another string")) .isFalse(); @@ -63,7 +82,7 @@ class ConditionTest { @Test void matchesShouldThrowWhenNullLine() { - Condition condition = new Condition(Operator.CONTAINS, "match me"); + Condition condition = new Condition.OperatorCondition(Operator.CONTAINS, "match me"); assertThatThrownBy(() -> condition.matches(null)) .isInstanceOf(NullPointerException.class); @@ -71,22 +90,72 @@ class ConditionTest { @Test void matchAllShouldReturnTrue() { - assertThat(Condition.MATCH_ALL - .matches("this contains another string")) + assertThat(Condition.MATCH_ALL.matches("this contains another string")) .isTrue(); } @Test void matchAllShouldReturnTrueEvenWhenLineIsNull() { - assertThat(Condition.MATCH_ALL - .matches(null)) + assertThat(Condition.MATCH_ALL.matches(null)) .isTrue(); } @Test void matchAllShouldReturnTrueEvenWhenLineIsEmpty() { - assertThat(Condition.MATCH_ALL - .matches("")) + assertThat(Condition.MATCH_ALL.matches("")) .isTrue(); } + + @Nested + class JSONTest { + @Test + void jacksonShouldDeserializeCondition() throws Exception { + Condition condition = OBJECT_MAPPER.readValue( + "{\"operator\":\"contains\", \"matchingValue\":\"matchme\"}", + Condition.class); + + assertThat(condition).isEqualTo(new Condition.OperatorCondition(Operator.CONTAINS, "matchme")); + } + + @Test + void jacksonShouldDeserializeMatchAllCondition() throws Exception { + Condition condition = OBJECT_MAPPER.readValue( + "{\"operator\":\"matchAll\"}", + Condition.class); + + assertThat(condition).isEqualTo(Condition.MATCH_ALL); + } + + @Test + void jacksonShouldSerializeCondition() throws Exception { + String json = OBJECT_MAPPER.writeValueAsString(new Condition.OperatorCondition(Operator.CONTAINS, "matchme")); + + assertThatJson(json).isEqualTo("{\"operator\":\"contains\", \"matchingValue\":\"matchme\"}"); + } + + @Test + void jacksonShouldSerializeMatchAllCondition() throws Exception { + String json = OBJECT_MAPPER.writeValueAsString(Condition.MATCH_ALL); + + assertThatJson(json).isEqualTo("{\"operator\":\"matchAll\"}"); + } + + @Test + void jacksonShouldThrowWhenDeserializeMatchAllConditionWithMatchingValue(){ + String json = "{\"operator\":\"matchAll\", \"matchingValue\":\"matchme\"}"; + + assertThatThrownBy(() -> OBJECT_MAPPER.readValue(json, Condition.class)) + .isInstanceOf(InvalidDefinitionException.class) + .hasMessageContaining("You should not specify a matchingValue with the matchAll operator"); + } + + @Test + void jacksonShouldThrowWhenDeserializeContainsConditionWithoutMatchingValue(){ + String json = "{\"operator\":\"contains\"}"; + + assertThatThrownBy(() -> OBJECT_MAPPER.readValue(json, Condition.class)) + .isInstanceOf(InvalidDefinitionException.class) + .hasMessageContaining("You need to specify a matchingValue with the contains operator"); + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org