Compare commits
10 commits
612fd7138a
...
58796c8f73
Author | SHA1 | Date | |
---|---|---|---|
58796c8f73 | |||
5b09c1b525 | |||
|
33869a7c26 | ||
b23337f25c | |||
892e3ec9f5 | |||
d1f4c61f00 | |||
|
03b288da4c | ||
|
7890359f21 | ||
913df97a1d | |||
786569a995 |
16 changed files with 405 additions and 275 deletions
2
.github/workflows/build-maven.yml
vendored
2
.github/workflows/build-maven.yml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: setup-jdk-${{ matrix.java }}
|
||||
uses: actions/setup-java@v2.1.0
|
||||
uses: actions/setup-java@v2.2.0
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: ${{ matrix.java }}
|
||||
|
|
2
.github/workflows/deploy-sonatype.yml
vendored
2
.github/workflows/deploy-sonatype.yml
vendored
|
@ -12,7 +12,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v2.1.0
|
||||
uses: actions/setup-java@v2.2.0
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: 11
|
||||
|
|
|
@ -14,6 +14,8 @@ https://oss.sonatype.org/content/repositories/releases/net/kemitix/mon/)
|
|||
https://img.shields.io/maven-central/v/net.kemitix/mon.svg?style=for-the-badge)](
|
||||
https://search.maven.org/artifact/net.kemitix/mon)
|
||||
|
||||
The documentation below is being slowly migrated to [Javadoc](https://kemitix.github.io/mon/).
|
||||
|
||||
- [Maven Usage](#Maven-Usage)
|
||||
- [Wrapper](#Wrapper) - light-weight type-alias-like
|
||||
- [TypeAlias](#TypeAlias) - type-alias-like monadic wrapper
|
||||
|
|
7
pom.xml
7
pom.xml
|
@ -11,7 +11,7 @@
|
|||
</parent>
|
||||
|
||||
<artifactId>mon</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.3.0</version>
|
||||
|
||||
<name>Mon</name>
|
||||
<description>Wrapper, TypeAlias, Maybe, Result, Tree, Lazy, Either and Combinators for Java.
|
||||
|
@ -41,9 +41,9 @@
|
|||
<kemitix-maven-tiles.version>3.0.1</kemitix-maven-tiles.version>
|
||||
<digraph-dependency.basePackage>net.kemitix.mon</digraph-dependency.basePackage>
|
||||
<kemitix-checkstyle.version>5.5.0</kemitix-checkstyle.version>
|
||||
<pitest-maven-plugin.version>1.6.8</pitest-maven-plugin.version>
|
||||
<pitest-maven-plugin.version>1.6.9</pitest-maven-plugin.version>
|
||||
<pitest-junit5-plugin.version>0.14</pitest-junit5-plugin.version>
|
||||
<spotbugs.version>4.3.0</spotbugs.version>
|
||||
<spotbugs.version>4.4.0</spotbugs.version>
|
||||
<apiguardian-api.version>1.1.2</apiguardian-api.version>
|
||||
</properties>
|
||||
|
||||
|
@ -60,7 +60,6 @@
|
|||
<artifactId>apiguardian-api</artifactId>
|
||||
<version>${apiguardian-api.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
|
|
64
src/main/java/net/kemitix/mon/reader/Reader.java
Normal file
64
src/main/java/net/kemitix/mon/reader/Reader.java
Normal file
|
@ -0,0 +1,64 @@
|
|||
package net.kemitix.mon.reader;
|
||||
|
||||
import org.apiguardian.api.API;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Returns a program ready to run upon the supply of a suitable environment.
|
||||
*
|
||||
* @param <E> The type of the environment required by the program.
|
||||
* @param <R> The type of the result returned by the program.
|
||||
*/
|
||||
@API(status = API.Status.EXPERIMENTAL, since = "3.0.1")
|
||||
@FunctionalInterface
|
||||
public interface Reader<E, R> {
|
||||
|
||||
/**
|
||||
* Executes the program.
|
||||
*
|
||||
* @param env the required environment
|
||||
* @return the result of the program
|
||||
*/
|
||||
R run(E env);
|
||||
|
||||
/**
|
||||
* Applies the function provided to the reader when it is run.
|
||||
*
|
||||
* @param f the function, which takes an {@link E} as its only parameter
|
||||
* @param <V> the type of the functions output
|
||||
* @return a new Reader to provide the result of the supplied function
|
||||
*/
|
||||
@API(status = API.Status.EXPERIMENTAL)
|
||||
default <V> Reader<E, V> map(Function<R, V> f) {
|
||||
return e -> f.apply(run(e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the function provided to the reader when it is run.
|
||||
*
|
||||
* @param f the function, which takes an {@link E} and the previously
|
||||
* generated value as its two parameters
|
||||
* @param <V> the type of the functions output
|
||||
* @return a new Reader to provided the result of the supplied function
|
||||
*/
|
||||
@API(status = API.Status.EXPERIMENTAL)
|
||||
default <V> Reader<E, V> flatMap(BiFunction<E, R, V> f) {
|
||||
return env -> f.apply(env, run(env));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the function provided to the reader when run, and executes that
|
||||
* resulting reader.
|
||||
*
|
||||
* @param f the function which takes the previously generated value and
|
||||
* produces another Reader
|
||||
* @param <V> the type of the value the new Reader returns
|
||||
* @return a new Reader
|
||||
*/
|
||||
@API(status = API.Status.EXPERIMENTAL)
|
||||
default <V> Reader<E, V> flatMap(Function<R, Reader<E, V>> f) {
|
||||
return env -> f.apply(run(env)).run(env);
|
||||
}
|
||||
}
|
1
src/main/java/net/kemitix/mon/reader/package-info.java
Normal file
1
src/main/java/net/kemitix/mon/reader/package-info.java
Normal file
|
@ -0,0 +1 @@
|
|||
package net.kemitix.mon.reader;
|
|
@ -24,7 +24,6 @@ package net.kemitix.mon.result;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
@ -67,8 +66,9 @@ class Err<T> implements Result<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void match(final Consumer<T> onSuccess, final Consumer<Throwable> onError) {
|
||||
public Result<T> match(final Consumer<T> onSuccess, final Consumer<Throwable> onError) {
|
||||
onError.accept(error);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,8 +101,8 @@ class Err<T> implements Result<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final Consumer<T> successConsumer) {
|
||||
// do nothing
|
||||
public Result<T> onSuccess(final Consumer<T> successConsumer) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -122,11 +122,6 @@ class Err<T> implements Result<T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> Result<R> andThen(final Function<T, Callable<R>> f) {
|
||||
return (Result<R>) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<T> thenWith(final Function<T, WithResultContinuation<T>> f) {
|
||||
return this;
|
||||
|
|
|
@ -26,11 +26,12 @@ public class ErrVoid implements ResultVoid {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void match(
|
||||
public ResultVoid match(
|
||||
final Runnable onSuccess,
|
||||
final Consumer<Throwable> onError
|
||||
) {
|
||||
onError.accept(error);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,8 +40,8 @@ public class ErrVoid implements ResultVoid {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final Runnable runnable) {
|
||||
// do nothing
|
||||
public ResultVoid onSuccess(final Runnable runnable) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -446,23 +446,6 @@ public interface Result<T> extends BaseResult, ThrowableFunctor<T, ThrowableFunc
|
|||
return maybeResult.flatMap(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the inner {@code Result} of a {@link Maybe}, so that a {@code Result} contains a {@code Maybe}.
|
||||
*
|
||||
* @param maybeResult the Maybe the contains a Result
|
||||
* @param <T> the type of the value that may be in the Result
|
||||
* @return a Result containing a Maybe, the value in the Maybe was the value in a successful Result within the
|
||||
* original Maybe. If the original Maybe is Nothing, the Result will contain Nothing. If the original Result was an
|
||||
* error, then the Result will also be an error.
|
||||
* @deprecated
|
||||
*/
|
||||
@API(status = DEPRECATED)
|
||||
@Deprecated
|
||||
static <T> Result<Maybe<T>> swap(final Maybe<Result<T>> maybeResult) {
|
||||
return maybeResult.orElseGet(() -> Result.ok(null))
|
||||
.flatMap(value -> Result.ok(Maybe.maybe(value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Maybe} from the {@code Result}.
|
||||
*
|
||||
|
@ -657,9 +640,10 @@ public interface Result<T> extends BaseResult, ThrowableFunctor<T, ThrowableFunc
|
|||
*
|
||||
* @param onSuccess the Consumer to pass the value of a successful Result to
|
||||
* @param onError the Consumer to pass the error from an error Result to
|
||||
* @return the original Result
|
||||
*/
|
||||
@API(status = STABLE)
|
||||
void match(Consumer<T> onSuccess, Consumer<Throwable> onError);
|
||||
Result<T> match(Consumer<T> onSuccess, Consumer<Throwable> onError);
|
||||
|
||||
/**
|
||||
* Provide the value within the Result, if it is a success, to the Consumer, and returns this Result.
|
||||
|
@ -707,9 +691,10 @@ public interface Result<T> extends BaseResult, ThrowableFunctor<T, ThrowableFunc
|
|||
* success value. When this is an error, then nothing happens.</p>
|
||||
*
|
||||
* @param successConsumer the consumer to handle the success
|
||||
* @return the original Result
|
||||
*/
|
||||
@API(status = STABLE)
|
||||
void onSuccess(Consumer<T> successConsumer);
|
||||
Result<T> onSuccess(Consumer<T> successConsumer);
|
||||
|
||||
/**
|
||||
* A handler for error state, when the error matches the errorClass.
|
||||
|
@ -738,29 +723,6 @@ public interface Result<T> extends BaseResult, ThrowableFunctor<T, ThrowableFunc
|
|||
Consumer<E> consumer
|
||||
);
|
||||
|
||||
/**
|
||||
* Maps a Success Result to another Result using a Callable that is able to throw a checked exception.
|
||||
*
|
||||
* <p>Combination of {@link #flatMap(Function)} and {@link #of(Callable)}.</p>
|
||||
*
|
||||
* <pre><code>
|
||||
* Integer doSomething() {...}
|
||||
* String doSomethingElse(final Integer value) {...}
|
||||
* Result<String> r = Result.of(() -> doSomething())
|
||||
* .andThen(value -> () -> doSomethingElse(value));
|
||||
* </code></pre>
|
||||
*
|
||||
* <p>When the Result is an Err, then the original error is carried over and the Callable is never called.</p>
|
||||
*
|
||||
* @param f the function to map the Success value into the Callable
|
||||
* @param <R> the type of the final Result
|
||||
* @return a new Result
|
||||
* @deprecated Use {@link #map(ThrowableFunction)}
|
||||
*/
|
||||
@API(status = DEPRECATED)
|
||||
@Deprecated
|
||||
<R> Result<R> andThen(Function<T, Callable<R>> f);
|
||||
|
||||
/**
|
||||
* Perform the continuation with the value within the success {@code Result}
|
||||
* and return itself.
|
||||
|
|
|
@ -27,9 +27,10 @@ public interface ResultVoid extends BaseResult {
|
|||
*
|
||||
* @param onSuccess the Consumer to pass the value of a successful Result to
|
||||
* @param onError the Consumer to pass the error from an error Result to
|
||||
* @return the original ResultVoid
|
||||
*/
|
||||
@API(status = STABLE)
|
||||
void match(Runnable onSuccess, Consumer<Throwable> onError);
|
||||
ResultVoid match(Runnable onSuccess, Consumer<Throwable> onError);
|
||||
|
||||
/**
|
||||
* Attempts to restore an error {@code ResultVoid} to a success.
|
||||
|
@ -66,9 +67,10 @@ public interface ResultVoid extends BaseResult {
|
|||
* success value. When this is an error, then nothing happens.</p>
|
||||
*
|
||||
* @param runnable the call if the Result is a success
|
||||
* @return the original ResultVoid
|
||||
*/
|
||||
@API(status = STABLE)
|
||||
void onSuccess(Runnable runnable);
|
||||
ResultVoid onSuccess(Runnable runnable);
|
||||
|
||||
/**
|
||||
* A handler for error state, when the error matches the errorClass.
|
||||
|
|
|
@ -24,7 +24,6 @@ package net.kemitix.mon.result;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
@ -62,8 +61,9 @@ class Success<T> implements Result<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void match(final Consumer<T> onSuccess, final Consumer<Throwable> onError) {
|
||||
public Result<T> match(final Consumer<T> onSuccess, final Consumer<Throwable> onError) {
|
||||
onSuccess.accept(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,8 +93,9 @@ class Success<T> implements Result<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final Consumer<T> successConsumer) {
|
||||
public Result<T> onSuccess(final Consumer<T> successConsumer) {
|
||||
successConsumer.accept(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,11 +111,6 @@ class Success<T> implements Result<T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> Result<R> andThen(final Function<T, Callable<R>> f) {
|
||||
return result(f.apply(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<T> thenWith(final Function<T, WithResultContinuation<T>> f) {
|
||||
return f.apply(value).call(this);
|
||||
|
|
|
@ -37,8 +37,9 @@ public class SuccessVoid implements ResultVoid {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void match(final Runnable onSuccess, final Consumer<Throwable> onError) {
|
||||
public ResultVoid match(final Runnable onSuccess, final Consumer<Throwable> onError) {
|
||||
onSuccess.run();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,8 +48,9 @@ public class SuccessVoid implements ResultVoid {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final Runnable runnable) {
|
||||
public ResultVoid onSuccess(final Runnable runnable) {
|
||||
runnable.run();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -209,7 +209,7 @@ class EitherTest implements WithAssertions {
|
|||
}
|
||||
@Nested @DisplayName("getLeft") public class GetLeft {
|
||||
@Test
|
||||
@DisplayName("")
|
||||
@DisplayName("when is a Left then get the value")
|
||||
public void whenLeft_thenGetValue() {
|
||||
//given
|
||||
Either<String, Integer> either = Either.left("value");
|
||||
|
@ -220,7 +220,7 @@ class EitherTest implements WithAssertions {
|
|||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("")
|
||||
@DisplayName("when is a Right then is empty")
|
||||
public void whenRight_thenGetEmpty() {
|
||||
//given
|
||||
Either<Integer, String> either = Either.right("value");
|
||||
|
@ -232,7 +232,7 @@ class EitherTest implements WithAssertions {
|
|||
}
|
||||
@Nested @DisplayName("getRight") public class GetRight {
|
||||
@Test
|
||||
@DisplayName("")
|
||||
@DisplayName("when is a Left then is empty")
|
||||
public void whenLeft_thenGetEmpty() {
|
||||
//given
|
||||
Either<String, Integer> either = Either.left("value");
|
||||
|
@ -243,7 +243,7 @@ class EitherTest implements WithAssertions {
|
|||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("")
|
||||
@DisplayName("when is a Right then get the value")
|
||||
public void whenRight_thenGetValue() {
|
||||
//given
|
||||
Either<Integer, String> either = Either.right("value");
|
||||
|
|
110
src/test/java/net/kemitix/mon/ReaderTest.java
Normal file
110
src/test/java/net/kemitix/mon/ReaderTest.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
package net.kemitix.mon;
|
||||
|
||||
import net.kemitix.mon.reader.Reader;
|
||||
import org.assertj.core.api.WithAssertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ReaderTest
|
||||
implements WithAssertions {
|
||||
|
||||
@Test
|
||||
@DisplayName("read a value and return it")
|
||||
void readAndReturn() {
|
||||
//given
|
||||
Integer value = 123;
|
||||
Environment env = new Environment() {
|
||||
@Override
|
||||
public Integer intValue() {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
Reader<Environment, Integer> program = (Environment e) -> {
|
||||
return e.intValue();
|
||||
};
|
||||
|
||||
//when
|
||||
Integer result = program.run(env);
|
||||
|
||||
//then
|
||||
assertThat(result).isEqualTo(value);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("map")
|
||||
void map() {
|
||||
//given
|
||||
AtomicInteger value = new AtomicInteger(123);
|
||||
Environment env = new Environment() {
|
||||
@Override
|
||||
public Integer intValue() {
|
||||
return value.incrementAndGet();
|
||||
}
|
||||
};
|
||||
Reader<Environment, String> program =
|
||||
((Reader<Environment, Integer>) e -> e.intValue())
|
||||
.map(i -> i * 2)
|
||||
.map(i -> Integer.toString(i));
|
||||
//when
|
||||
String result = program.run(env);
|
||||
//then
|
||||
assertThat(result).isEqualTo("248");// (123 + 1) * 2
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("andThen")
|
||||
void andThen() {
|
||||
//given
|
||||
AtomicInteger value = new AtomicInteger(123);
|
||||
Environment env = new Environment() {
|
||||
@Override
|
||||
public Integer intValue() {
|
||||
return value.incrementAndGet();
|
||||
}
|
||||
};
|
||||
Reader<Environment, String> program =
|
||||
((Reader<Environment, Integer>) e -> e.intValue())
|
||||
.flatMap((e, i) -> e.intValue() + (i * 2))
|
||||
.flatMap((e, i) -> String.format("%.2f",
|
||||
i.floatValue() / e.intValue()));
|
||||
//when
|
||||
String result = program.run(env);
|
||||
//then
|
||||
assertThat(result).isEqualTo("2.96");// ((123 * 2) + (123 + 1)) / (123 + 2)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("flatMap")
|
||||
void flatMap() {
|
||||
//given
|
||||
AtomicInteger value = new AtomicInteger(123);
|
||||
Environment env = new Environment() {
|
||||
@Override
|
||||
public Integer intValue() {
|
||||
return value.incrementAndGet();
|
||||
}
|
||||
};
|
||||
Function<Integer, Reader<Environment, Integer>> addNextValue =
|
||||
integer -> (Reader<Environment, Integer>) e -> e.intValue() + integer;
|
||||
Function<Integer, Reader<Environment, Float>> divideByNextValue =
|
||||
integer -> (Reader<Environment, Float>) e -> integer.floatValue() / e.intValue();
|
||||
Reader<Environment, String> program =
|
||||
((Reader<Environment, Integer>) e -> e.intValue())
|
||||
.flatMap(addNextValue)
|
||||
.flatMap(divideByNextValue)
|
||||
.map(f -> String.format("%.3f", f));
|
||||
//when
|
||||
String result = program.run(env);
|
||||
//then
|
||||
assertThat(result).isEqualTo("1.976");// (123 + 124) / 125
|
||||
}
|
||||
|
||||
private interface Environment {
|
||||
|
||||
Integer intValue();
|
||||
|
||||
}
|
||||
}
|
|
@ -106,17 +106,6 @@ class ResultTest implements WithAssertions {
|
|||
assertThat(result.isError()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenOkayVoid_match_isNull() {
|
||||
//when
|
||||
var result = Result.ok();
|
||||
//then
|
||||
result.match(
|
||||
() -> assertThat(true).isTrue(),
|
||||
error -> fail("not an error")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenOk_isOkay() {
|
||||
//when
|
||||
|
@ -133,17 +122,6 @@ class ResultTest implements WithAssertions {
|
|||
assertThat(result.isError()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenOkay_matchSuccess() {
|
||||
//given
|
||||
final Result<String> result = Result.ok("good");
|
||||
//then
|
||||
result.match(
|
||||
success -> assertThat(success).isEqualTo("good"),
|
||||
error -> fail("not an error")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenError_isError() {
|
||||
//when
|
||||
|
@ -160,17 +138,6 @@ class ResultTest implements WithAssertions {
|
|||
assertThat(result.isError()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenError_matchError() {
|
||||
//given
|
||||
final Result<Integer> result = anError(new Exception("bad"));
|
||||
//then
|
||||
result.match(
|
||||
success -> fail("not a success"),
|
||||
error -> assertThat(error.getMessage()).isEqualTo("bad")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void okay_toString() {
|
||||
//given
|
||||
|
@ -245,6 +212,95 @@ class ResultTest implements WithAssertions {
|
|||
.flatMap(s -> Result.of(() -> {throw e;}));
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("match")
|
||||
class MatchTests {
|
||||
|
||||
@Test
|
||||
void whenOkay_matchSuccess() {
|
||||
//given
|
||||
Result<String> ok = Result.ok("good");
|
||||
//then
|
||||
ok.match(
|
||||
success -> assertThat(success).isEqualTo("good"),
|
||||
error -> fail("not an error")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenError_matchError() {
|
||||
//given
|
||||
Result<Integer> error = anError(new Exception("bad"));
|
||||
//then
|
||||
error.match(
|
||||
success -> fail("not a success"),
|
||||
e -> assertThat(e.getMessage()).isEqualTo("bad")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenOkayVoid_matchOkay() {
|
||||
//when
|
||||
var ok = Result.ok();
|
||||
//then
|
||||
ok.match(
|
||||
() -> assertThat(true).isTrue(),
|
||||
error -> fail("not an error")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenErrorVoid_matchError() {
|
||||
//when
|
||||
var error = Result.error(new RuntimeException());
|
||||
//then
|
||||
error.match(
|
||||
() -> fail("not a success"),
|
||||
e -> assertThat(true).isTrue()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenOkay_match_returnsSelf() {
|
||||
//given
|
||||
final Result<String> ok = Result.ok("good");
|
||||
//when
|
||||
Result<String> result = ok.match(s -> {}, e -> {});
|
||||
//then
|
||||
assertThat(result).isSameAs(ok);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenError_match_returnsSelf() {
|
||||
//given
|
||||
final Result<Integer> error = anError(new Exception("bad"));
|
||||
//then
|
||||
Result<Integer> result = error.match(s -> {}, e -> {});
|
||||
//then
|
||||
assertThat(result).isSameAs(error);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenOkayVoid_match_returnsSelf() {
|
||||
//given
|
||||
ResultVoid ok = Result.ok();
|
||||
//when
|
||||
ResultVoid result = ok.match(() -> {}, e -> {});
|
||||
//then
|
||||
assertThat(result).isSameAs(ok);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenErrorVoid_match_returnsSelf() {
|
||||
//given
|
||||
ResultVoid error = Result.error(new RuntimeException());
|
||||
//when
|
||||
ResultVoid result = error.match(() -> {}, e -> {});
|
||||
//then
|
||||
assertThat(result).isSameAs(error);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("flatMap")
|
||||
class FlatMapTests {
|
||||
|
@ -527,50 +583,6 @@ class ResultTest implements WithAssertions {
|
|||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("invert")
|
||||
class InvertTests {
|
||||
@Test
|
||||
void justOkay_whenInvert_thenOkayJust() {
|
||||
//given
|
||||
final Maybe<Result<Integer>> justSuccess = Maybe.just(Result.ok(1));
|
||||
//when
|
||||
final Result<Maybe<Integer>> result = Result.swap(justSuccess);
|
||||
//then
|
||||
result.match(
|
||||
success -> assertThat(success.toOptional()).contains(1),
|
||||
error -> fail("Not an error")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void JustError_whenInvert_isError() {
|
||||
//given
|
||||
final RuntimeException exception = new RuntimeException();
|
||||
final Maybe<Result<Integer>> justError = Maybe.just(anError(exception));
|
||||
//when
|
||||
final Result<Maybe<Integer>> result = Result.swap(justError);
|
||||
//then
|
||||
result.match(
|
||||
success -> fail("Not a success"),
|
||||
error -> assertThat(error).isSameAs(exception)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nothing_whenInvert_thenOkayNothing() {
|
||||
//given
|
||||
final Maybe<Result<Integer>> nothing = Maybe.nothing();
|
||||
//when
|
||||
final Result<Maybe<Integer>> result = Result.swap(nothing);
|
||||
//then
|
||||
result.match(
|
||||
success -> assertThat(success.toOptional()).isEmpty(),
|
||||
error -> fail("Not an error")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("use cases")
|
||||
class UseCaseTests {
|
||||
|
@ -832,6 +844,52 @@ class ResultTest implements WithAssertions {
|
|||
//then
|
||||
assertThat(capture).hasValue(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void error_whenOnSuccess_returnsSelf() {
|
||||
//given
|
||||
final Result<Integer> error = anError(new RuntimeException());
|
||||
|
||||
//when
|
||||
final Result<Integer> result = error.onSuccess(x -> {});
|
||||
|
||||
//then
|
||||
assertThat(result).isSameAs(error);
|
||||
}
|
||||
|
||||
@Test
|
||||
void success_whenOnSuccess_returnsSelf() {
|
||||
//given
|
||||
final Result<Integer> ok = Result.ok(1);
|
||||
|
||||
//when
|
||||
final Result<Integer> result = ok.onSuccess(x -> {});
|
||||
|
||||
//then
|
||||
assertThat(result).isSameAs(ok);
|
||||
}
|
||||
|
||||
@Test void errorVoid_whenOnSuccess_returnsSelf() {
|
||||
//given
|
||||
final ResultVoid error = Result.error(new RuntimeException());
|
||||
|
||||
//when
|
||||
final ResultVoid result = error.onSuccess(() -> {});
|
||||
|
||||
//then
|
||||
assertThat(result).isSameAs(error);
|
||||
}
|
||||
|
||||
@Test void successVoid_whenOnSuccess_returnsSelf() {
|
||||
//given
|
||||
final ResultVoid ok = Result.ok();
|
||||
|
||||
//when
|
||||
final ResultVoid result = ok.onSuccess(() -> {});
|
||||
|
||||
//then
|
||||
assertThat(result).isSameAs(ok);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
@ -957,122 +1015,6 @@ class ResultTest implements WithAssertions {
|
|||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("andThen")
|
||||
class AndThenTests {
|
||||
@Test
|
||||
void okay_whenAndThen_whereSuccess_isUpdatedSuccess() {
|
||||
//given
|
||||
final Result<Integer> ok = Result.ok(1);
|
||||
//when
|
||||
final Result<String> result = ok.andThen(v -> () -> "success");
|
||||
//then
|
||||
result.match(
|
||||
v -> assertThat(v).isEqualTo("success"),
|
||||
e -> fail("not an error"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void okay_whenAndThen_whereError_isError() {
|
||||
//given
|
||||
final Result<Integer> ok = Result.ok(1);
|
||||
final RuntimeException exception = new RuntimeException();
|
||||
//when
|
||||
final Result<Object> result = ok.andThen(v -> () -> {
|
||||
throw exception;
|
||||
});
|
||||
//then
|
||||
result.match(
|
||||
x -> fail("not a success"),
|
||||
e -> assertThat(e).isSameAs(exception));
|
||||
}
|
||||
|
||||
@Test
|
||||
void error_whereAndThen_whereSuccess_isError() {
|
||||
//given
|
||||
final RuntimeException exception = new RuntimeException();
|
||||
final Result<Integer> error = anError(exception);
|
||||
//when
|
||||
final Result<Object> result = error.andThen(v -> () -> "success");
|
||||
//then
|
||||
result.match(
|
||||
x -> fail("not a success"),
|
||||
e -> assertThat(e).isSameAs(exception));
|
||||
}
|
||||
|
||||
@Test
|
||||
void error_whenAndThen_whereError_isOriginalError() {
|
||||
//given
|
||||
final RuntimeException exception1 = new RuntimeException();
|
||||
final Result<Integer> error = anError(exception1);
|
||||
//when
|
||||
final Result<Object> result = error.andThen(v -> () -> {
|
||||
throw new RuntimeException();
|
||||
});
|
||||
//then
|
||||
result.match(
|
||||
x -> fail("not a success"),
|
||||
e -> assertThat(e).isSameAs(exception1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void okayVoid_whenAndThen_whereSuccess_isUpdatedSuccess() {
|
||||
//given
|
||||
final ResultVoid ok = Result.ok();
|
||||
//when
|
||||
final ResultVoid result = ok.andThen(() -> {
|
||||
// do nothing
|
||||
});
|
||||
//then
|
||||
assertThat(result.isOkay()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void okayVoid_whenAndThen_whereError_isError() {
|
||||
//given
|
||||
final ResultVoid ok = Result.ok();
|
||||
final RuntimeException exception = new RuntimeException();
|
||||
//when
|
||||
final ResultVoid result = ok.andThen(() -> {
|
||||
throw exception;
|
||||
});
|
||||
//then
|
||||
result.match(
|
||||
() -> fail("not a success"),
|
||||
e -> assertThat(e).isSameAs(exception));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorVoid_whereAndThen_whereSuccess_isError() {
|
||||
//given
|
||||
final RuntimeException exception = new RuntimeException();
|
||||
final ResultVoid error = Result.error(exception);
|
||||
//when
|
||||
final ResultVoid result = error.andThen(() -> {
|
||||
// do nothing
|
||||
});
|
||||
//then
|
||||
result.match(
|
||||
() -> fail("not a success"),
|
||||
e -> assertThat(e).isSameAs(exception));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorVoid_whenAndThen_whereError_isOriginalError() {
|
||||
//given
|
||||
final RuntimeException exception1 = new RuntimeException();
|
||||
final ResultVoid error = Result.error(exception1);
|
||||
//when
|
||||
final ResultVoid result = error.andThen(() -> {
|
||||
throw new RuntimeException();
|
||||
});
|
||||
//then
|
||||
result.match(
|
||||
() -> fail("not a success"),
|
||||
e -> assertThat(e).isSameAs(exception1));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("thenWith")
|
||||
class ThenWithTests {
|
||||
|
@ -1668,6 +1610,64 @@ class ResultTest implements WithAssertions {
|
|||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("andThen")
|
||||
class AndThenTests {
|
||||
|
||||
@Test
|
||||
void successVoid_andThen_returnSelf() {
|
||||
//given
|
||||
ResultVoid ok = Result.ok();
|
||||
//when
|
||||
ResultVoid result = ok.andThen(() -> {});
|
||||
//then
|
||||
assertThat(result).isSameAs(ok);
|
||||
}
|
||||
|
||||
@Test
|
||||
void successVoid_andThen_isCalled() {
|
||||
//given
|
||||
ResultVoid ok = Result.ok();
|
||||
AtomicBoolean called = new AtomicBoolean(false);
|
||||
//when
|
||||
ok.andThen(() -> called.set(true));
|
||||
//then
|
||||
assertThat(called).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void successVoid_andThen_exception_errorVoid() {
|
||||
//given
|
||||
ResultVoid ok = Result.ok();
|
||||
//when
|
||||
ResultVoid result = ok.andThen(() -> {throw new RuntimeException();});
|
||||
//then
|
||||
assertThat(result.isError()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorVoid_andThen_returnsSelf() {
|
||||
//given
|
||||
ResultVoid error = Result.error(new RuntimeException());
|
||||
//when
|
||||
ResultVoid result = error.andThen(() -> {});
|
||||
//then
|
||||
assertThat(result).isSameAs(error);
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorVoid_andThen_notCalled() {
|
||||
//given
|
||||
ResultVoid error = Result.error(new RuntimeException());
|
||||
final AtomicBoolean called = new AtomicBoolean(false);
|
||||
//when
|
||||
error.andThen(() -> called.set(true));
|
||||
//then
|
||||
assertThat(called).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* These include snippets from the Javadocs and are meant to prove that the examples are valid.
|
||||
*/
|
||||
|
@ -2293,7 +2293,7 @@ class ResultTest implements WithAssertions {
|
|||
|
||||
Result<Double> businessOperation(final String fileName1, final String fileName2) {
|
||||
return readIntFromFile(fileName1)
|
||||
.andThen(intFromFile1 -> () -> adjustValue(intFromFile1))
|
||||
.map(this::adjustValue)
|
||||
.flatMap(adjustedIntFromFile1 -> readIntFromFile(fileName2)
|
||||
.flatMap(intFromFile2 -> adjustedIntFromFile1
|
||||
.flatMap(aif1 -> calculateAverage(aif1, intFromFile2))));
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package net.kemitix.mon;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -18,8 +15,6 @@ class WrapperTest {
|
|||
|
||||
interface WrappedIterableString extends Wrapper<Iterable<String>> { }
|
||||
|
||||
interface WrappedListInteger extends Wrapper<List<Integer>> {}
|
||||
|
||||
interface AWrapper extends Wrapper<String> {}
|
||||
|
||||
@Test
|
||||
|
@ -65,6 +60,7 @@ class WrapperTest {
|
|||
final WrappedString wrappedString = () -> "1";
|
||||
final WrappedInteger wrappedInteger = () -> 1;
|
||||
//then
|
||||
//noinspection AssertBetweenInconvertibleTypes
|
||||
assertThat(wrappedString).isNotEqualTo(wrappedInteger);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue