From b5694b6a1f6b928e289b1fc99922283afee34ee9 Mon Sep 17 00:00:00 2001 From: Jose Luis Leon Date: Sun, 2 May 2021 22:37:10 -0500 Subject: [PATCH] Add ResolveHandler filter (#120) --- .../github/joselion/maybe/ResolveHandler.java | 34 +++++++++- .../joselion/maybe/ResolveHandlerTest.java | 67 ++++++++++++++++++- 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/joselion/maybe/ResolveHandler.java b/src/main/java/com/github/joselion/maybe/ResolveHandler.java index 4a9e0aa..25f0590 100644 --- a/src/main/java/com/github/joselion/maybe/ResolveHandler.java +++ b/src/main/java/com/github/joselion/maybe/ResolveHandler.java @@ -3,6 +3,7 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; import org.eclipse.jdt.annotation.Nullable; @@ -123,8 +124,9 @@ public ResolveHandler catchError(final Class errorType, f * If neither the value nor the error is present, it returns an empty handler. * * @param the type the value will be mapped to - * @param mapper a function to map the current value to another (if present) - * @return a new handler with the mapped value, the previous error, or nothing + * @param mapper a function to map the value to another (if present) + * @return a new handler with either the mapped value, the previous error, or + * nothing */ public ResolveHandler map(final Function mapper) { if (success.isPresent()) { @@ -138,6 +140,34 @@ public ResolveHandler map(final Function mapper) { return withNothing(); } + /** + * If a value is present, and the value matches the given {@code predicate}, + * returns a new handler with the value, otherwise returns an empty handler. + * If the error is present, the {@code predicate} is never applied and, the + * next handler will still contain the error. + *

+ * If neither the value nor the error is present, it returns an empty handler. + * + * @param predicate a predicate to apply to the value (if present) + * @return a new handler with either the value if it matched the predicate, + * the previous error, or nothing + */ + public ResolveHandler filter(final Predicate predicate) { + if (success.isPresent()) { + final T value = success.get(); + + return predicate.test(value) + ? withSuccess(value) + : withNothing(); + } + + if (error.isPresent()) { + return withError(error.get()); + } + + return withNothing(); + } + /** * Returns the value resolved/handled if present. A default value otherwise. * diff --git a/src/test/java/com/github/joselion/maybe/ResolveHandlerTest.java b/src/test/java/com/github/joselion/maybe/ResolveHandlerTest.java index 62fa1d0..5655632 100644 --- a/src/test/java/com/github/joselion/maybe/ResolveHandlerTest.java +++ b/src/test/java/com/github/joselion/maybe/ResolveHandlerTest.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.Function; import com.github.joselion.maybe.helpers.UnitTest; @@ -240,7 +241,7 @@ @Nested class map { @Nested class when_the_value_is_present { @Test void returns_a_new_handler_applying_the_mapper_function() { - final ResolveHandler handler = ResolveHandler.withSuccess("Hello world!") + final ResolveHandler handler = ResolveHandler.withSuccess("Hello world!") .map(String::length); assertThat(handler) @@ -284,6 +285,70 @@ } } + @Nested class filter { + @Nested class when_the_value_is_present { + @Nested class and_the_predicate_matches { + @Test void returns_a_new_handler_with_the_value() { + final ResolveHandler handler = ResolveHandler.withSuccess("Hello world!") + .filter(it -> it.contains("world")); + + assertThat(handler) + .extracting(SUCCESS, optional(String.class)) + .contains("Hello world!"); + + assertThat(handler) + .extracting(ERROR, optional(Exception.class)) + .isEmpty(); + } + } + + @Nested class and_the_predicate_does_NOT_match { + @Test void returns_an_empty_handler() { + final ResolveHandler handler = ResolveHandler.withSuccess("Hello world!") + .filter(it -> it.contains("planet")); + + assertThat(handler) + .extracting(SUCCESS, optional(String.class)) + .isEmpty(); + + assertThat(handler) + .extracting(ERROR, optional(Exception.class)) + .isEmpty(); + } + } + } + + @Nested class when_the_error_is_present { + @Test void returns_a_new_handler_with_the_previous_error() { + final ResolveHandler handler = ResolveHandler.withError(FAIL_EXCEPTION) + .filter(Objects::isNull); + + assertThat(handler) + .extracting(SUCCESS, optional(String.class)) + .isEmpty(); + + assertThat(handler) + .extracting(ERROR, optional(IOException.class)) + .contains(FAIL_EXCEPTION); + } + } + + @Nested class when_neither_the_value_nor_the_error_is_present { + @Test void returns_an_empty_handler() { + final ResolveHandler handler = ResolveHandler.withNothing() + .filter(Objects::isNull); + + assertThat(handler) + .extracting(SUCCESS, optional(String.class)) + .isEmpty(); + + assertThat(handler) + .extracting(ERROR, optional(Exception.class)) + .isEmpty(); + } + } + } + @Nested class orDefault { @Nested class when_the_value_is_present { @Test void returns_the_value() {