/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.control;
import io.vavr.*;
import io.vavr.collection.Seq;
import io.vavr.AbstractValueTest;
import io.vavr.Function1;
import io.vavr.PartialFunction;
import io.vavr.Serializables;
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Supplier;
public class OptionTest extends AbstractValueTest {
// -- AbstractValueTest
@Override
protected <T> Option<T> empty() {
return Option.none();
}
@Override
protected <T> Option<T> of(T element) {
return Option.some(element);
}
@SafeVarargs
@Override
protected final <T> Option<T> of(T... elements) {
return of(elements[0]);
}
@Override
protected boolean useIsEqualToInsteadOfIsSameAs() {
return true;
}
@Override
protected int getPeekNonNilPerformingAnAction() {
return 1;
}
// -- Option
// -- narrow
@Test
public void shouldNarrowOption() {
final Option<Integer> option = Option.of(42);
final Option<Number> narrow = Option.narrow(option);
assertThat(narrow.get()).isEqualTo(42);
}
// -- construction
@Test
public void shouldMapNullToNone() {
assertThat(Option.of(null)).isEqualTo(Option.none());
}
@Test
public void shouldMapNonNullToSome() {
final Option<?> option = Option.of(new Object());
assertThat(option.isDefined()).isTrue();
}
@Test
public void shouldWrapNullInSome() {
final Option<?> some = Option.some(null);
assertThat(some.get()).isEqualTo(null);
}
@Test
public void shouldWrapIfTrue() {
assertThat(Option.when(true, () -> null)).isEqualTo(Option.some(null));
assertThat(Option.when(true, (Object) null)).isEqualTo(Option.some(null));
}
@Test
public void shouldNotWrapIfFalse() {
assertThat(Option.when(false, () -> null)).isEqualTo(Option.none());
assertThat(Option.when(false, (Object) null)).isEqualTo(Option.none());
}
@Test
public void shouldNotExecuteIfFalse() {
assertThat(Option.when(false, () -> {
throw new RuntimeException();
})).isEqualTo(Option.none());
}
@Test(expected = NullPointerException.class)
public void shouldThrowExceptionOnWhenWithProvider() {
assertThat(Option.when(false, (Supplier<?>) null)).isEqualTo(Option.none());
}
@Test
public void shouldWrapEmptyOptional() {
assertThat(Option.ofOptional(Optional.empty())).isEqualTo(Option.none());
}
@Test
public void shouldWrapSomeOptional() {
assertThat(Option.ofOptional(Optional.of(1))).isEqualTo(Option.of(1));
}
@Test(expected = NullPointerException.class)
public void shouldThrowExceptionOnNullOptional() {
assertThat(Option.ofOptional(null)).isEqualTo(Option.none());
}
// -- sequence
@Test
public void shouldConvertListOfNonEmptyOptionsToOptionOfList() {
final List<Option<String>> options = Arrays.asList(Option.of("a"), Option.of("b"), Option.of("c"));
final Option<Seq<String>> reducedOption = Option.sequence(options);
assertThat(reducedOption instanceof Option.Some).isTrue();
assertThat(reducedOption.get().size()).isEqualTo(3);
assertThat(reducedOption.get().mkString()).isEqualTo("abc");
}
@Test
public void shouldConvertListOfEmptyOptionsToOptionOfList() {
final List<Option<String>> options = Arrays.asList(Option.none(), Option.none(), Option.none());
final Option<Seq<String>> option = Option.sequence(options);
assertThat(option instanceof Option.None).isTrue();
}
@Test
public void shouldConvertListOfMixedOptionsToOptionOfList() {
final List<Option<String>> options = Arrays.asList(Option.of("a"), Option.none(), Option.of("c"));
final Option<Seq<String>> option = Option.sequence(options);
assertThat(option instanceof Option.None).isTrue();
}
// -- get
@Test
public void shouldSucceedOnGetWhenValueIsPresent() {
assertThat(Option.of(1).get()).isEqualTo(1);
}
@Test(expected = NoSuchElementException.class)
public void shouldThrowOnGetWhenValueIsNotDefined() {
Option.none().get();
}
// -- orElse
@Test
public void shouldReturnSelfOnOrElseIfValueIsPresent() {
final Option<Integer> opt = Option.of(42);
assertThat(opt.orElse(Option.of(0))).isSameAs(opt);
}
@Test
public void shouldReturnSelfOnOrElseSupplierIfValueIsPresent() {
final Option<Integer> opt = Option.of(42);
assertThat(opt.orElse(() -> Option.of(0))).isSameAs(opt);
}
@Test
public void shouldReturnAlternativeOnOrElseIfValueIsNotDefined() {
final Option<Integer> opt = Option.of(42);
assertThat(Option.none().orElse(opt)).isSameAs(opt);
}
@Test
public void shouldReturnAlternativeOnOrElseSupplierIfValueIsNotDefined() {
final Option<Integer> opt = Option.of(42);
assertThat(Option.none().orElse(() -> opt)).isSameAs(opt);
}
// -- getOrElse
@Test
public void shouldGetValueOnGetOrElseWhenValueIsPresent() {
assertThat(Option.of(1).getOrElse(2)).isEqualTo(1);
}
@Test
public void shouldGetAlternativeOnGetOrElseWhenValueIsNotDefined() {
assertThat(Option.none().getOrElse(2)).isEqualTo(2);
}
// -- getOrElse
@Test
public void shouldGetValueOnGetOrElseGetWhenValueIsPresent() {
assertThat(Option.of(1).getOrElse(() -> 2)).isEqualTo(1);
}
@Test
public void shouldGetAlternativeOnGetOrElseGetWhenValueIsNotDefined() {
assertThat(Option.none().getOrElse(() -> 2)).isEqualTo(2);
}
// -- getOrElseThrow
@Test
public void shouldGetValueOnGetOrElseThrowWhenValueIsPresent() {
assertThat(Option.of(1).getOrElseThrow(() -> new RuntimeException("none"))).isEqualTo(1);
}
@Test(expected = RuntimeException.class)
public void shouldThrowOnGetOrElseThrowWhenValueIsNotDefined() {
Option.none().getOrElseThrow(() -> new RuntimeException("none"));
}
// -- toJavaOptional
@Test
public void shouldConvertNoneToJavaOptional() {
final Option<Object> none = Option.none();
assertThat(none.toJavaOptional()).isEqualTo(Optional.empty());
}
@Test
public void shouldConvertSomeToJavaOptional() {
final Option<Integer> some = Option.some(1);
assertThat(some.toJavaOptional()).isEqualTo(Optional.of(1));
}
// -- isDefined
@Test
public void shouldBePresentOnIsDefinedWhenValueIsDefined() {
assertThat(Option.of(1).isDefined()).isTrue();
}
@Test
public void shouldNotBePresentOnIsDefinedWhenValueIsNotDefined() {
assertThat(Option.none().isDefined()).isFalse();
}
// -- isEmpty
@Test
public void shouldBeEmptyOnIsEmptyWhenValueIsEmpty() {
assertThat(Option.none().isEmpty()).isTrue();
}
@Test
public void shouldBePresentOnIsEmptyWhenValue() {
assertThat(Option.of(1).isEmpty()).isFalse();
}
// -- onEmpty
@Test
public void shouldThrowNullPointerExceptionWhenNullOnEmptyActionPassed() {
try {
final Option<String> none = Option.none();
none.onEmpty(null);
Assert.fail("No exception was thrown");
} catch (NullPointerException exc) {
assertThat(exc.getMessage()).isEqualTo("action is null");
}
}
@Test
public void shouldExecuteRunnableWhenOptionIsEmpty() {
final AtomicBoolean state = new AtomicBoolean();
final Option<?> option = Option.none().onEmpty(() -> state.set(false));
assertThat(state.get()).isFalse();
assertThat(option).isSameAs(Option.none());
}
@Test
public void shouldNotThrowExceptionIfOnEmptySetAndOptionIsSome() {
try {
final Option<String> none = Option.some("value");
none.onEmpty(() -> {
throw new RuntimeException("Exception from empty option!");
});
} catch (RuntimeException exc) {
Assert.fail("No exception should be thrown!");
}
}
// -- filter
@Test
public void shouldReturnSomeOnFilterWhenValueIsDefinedAndPredicateMatches() {
assertThat(Option.of(1).filter(i -> i == 1)).isEqualTo(Option.of(1));
}
@Test
public void shouldReturnNoneOnFilterWhenValueIsDefinedAndPredicateNotMatches() {
assertThat(Option.of(1).filter(i -> i == 2)).isEqualTo(Option.none());
}
@Test
public void shouldReturnNoneOnFilterWhenValueIsNotDefinedAndPredicateNotMatches() {
assertThat(Option.<Integer> none().filter(i -> i == 1)).isEqualTo(Option.none());
}
// -- map
@Test
public void shouldMapSome() {
assertThat(Option.of(1).map(String::valueOf)).isEqualTo(Option.of("1"));
}
@Test
public void shouldMapNone() {
assertThat(Option.<Integer> none().map(String::valueOf)).isEqualTo(Option.none());
}
// -- flatMap
@Test
public void shouldFlatMapSome() {
assertThat(Option.of(1).flatMap(i -> Option.of(String.valueOf(i)))).isEqualTo(Option.of("1"));
}
@Test
public void shouldFlatMapNone() {
assertThat(Option.<Integer> none().flatMap(i -> Option.of(String.valueOf(i)))).isEqualTo(Option.none());
}
@Test
public void shouldFlatMapNonEmptyIterable() {
final Option<Integer> option = Option.some(2);
assertThat(Option.of(1).flatMap(i -> option)).isEqualTo(Option.of(2));
}
@Test
public void shouldFlatMapEmptyIterable() {
final Option<Integer> option = Option.none();
assertThat(Option.of(1).flatMap(i -> option)).isEqualTo(Option.none());
}
// -- exists
@Test
public void shouldBeAwareOfPropertyThatHoldsExistsOfSome() {
assertThat(Option.some(1).exists(i -> i == 1)).isTrue();
}
@Test
public void shouldBeAwareOfPropertyThatNotHoldsExistsOfSome() {
assertThat(Option.some(1).exists(i -> i == 2)).isFalse();
}
@Test
public void shouldNotHoldPropertyExistsOfNone() {
assertThat(Option.none().exists(e -> true)).isFalse();
}
// -- forall
@Test
public void shouldBeAwareOfPropertyThatHoldsForAllOfSome() {
assertThat(Option.some(1).forAll(i -> i == 1)).isTrue();
}
@Test
public void shouldBeAwareOfPropertyThatNotHoldsForAllOfSome() {
assertThat(Option.some(1).forAll(i -> i == 2)).isFalse();
}
@Test // a property holds for all elements of no elements
public void shouldNotHoldPropertyForAllOfNone() {
assertThat(Option.none().forAll(e -> true)).isTrue();
}
// -- forEach
@Test
public void shouldConsumePresentValueOnForEachWhenValueIsDefined() {
final int[] actual = new int[] { -1 };
Option.of(1).forEach(i -> actual[0] = i);
assertThat(actual[0]).isEqualTo(1);
}
@Test
public void shouldNotConsumeAnythingOnForEachWhenValueIsNotDefined() {
final int[] actual = new int[] { -1 };
Option.<Integer> none().forEach(i -> actual[0] = i);
assertThat(actual[0]).isEqualTo(-1);
}
// -- toEither
@Test
public void shouldMakeRightOnSomeToEither() {
assertThat(API.Some(5).toEither("bad")).isEqualTo(API.Right(5));
}
@Test
public void shouldMakeLeftOnNoneToEither() {
assertThat(API.None().toEither("bad")).isEqualTo(API.Left("bad"));
}
@Test
public void shouldMakeLeftOnNoneToEitherSupplier() {
assertThat(API.None().toEither(() -> "bad")).isEqualTo(API.Left("bad"));
}
// -- toValidation
@Test
public void shouldMakeValidOnSomeToValidation() {
assertThat(API.Some(5).toValidation("bad")).isEqualTo(API.Valid(5));
}
@Test
public void shouldMakeLeftOnNoneToValidation() {
assertThat(API.None().toValidation("bad")).isEqualTo(API.Invalid("bad"));
}
@Test
public void shouldMakeLeftOnNoneToValidationSupplier() {
assertThat(API.None().toValidation(() -> "bad")).isEqualTo(API.Invalid("bad"));
}
// -- peek
@Test
public void shouldConsumePresentValueOnPeekWhenValueIsDefined() {
final int[] actual = new int[] { -1 };
final Option<Integer> testee = Option.of(1).peek(i -> actual[0] = i);
assertThat(actual[0]).isEqualTo(1);
assertThat(testee).isEqualTo(Option.of(1));
}
@Test
public void shouldNotConsumeAnythingOnPeekWhenValueIsNotDefined() {
final int[] actual = new int[] { -1 };
final Option<Integer> testee = Option.<Integer> none().peek(i -> actual[0] = i);
assertThat(actual[0]).isEqualTo(-1);
assertThat(testee).isEqualTo(Option.none());
}
// -- transform
@Test(expected = NullPointerException.class)
public void shouldThrowExceptionOnNullTransformFunction() {
Option.some(1).transform(null);
}
@Test
public void shouldApplyTransformFunctionToSome() {
final Option<Integer> option = Option.some(1);
final Function<Option<Integer>, String> f = o -> o.get().toString().concat("-transformed");
assertThat(option.transform(f)).isEqualTo("1-transformed");
}
@Test
public void shouldHandleTransformOnNone() {
assertThat(Option.none().<String> transform(self -> self.isEmpty() ? "ok" : "failed")).isEqualTo("ok");
}
// -- collect
@Test
public void shouldCollectDefinedValueUsingPartialFunction() {
final PartialFunction<Integer, String> pf = Function1.<Integer, String> of(String::valueOf).partial(i -> i % 2 == 1);
assertThat(Option.of(3).collect(pf)).isEqualTo(Option.of("3"));
}
@Test
public void shouldFilterNotDefinedValueUsingPartialFunction() {
final PartialFunction<Integer, String> pf = Function1.<Integer, String> of(String::valueOf).partial(i -> i % 2 == 1);
assertThat(Option.of(2).collect(pf)).isEqualTo(Option.none());
}
@Test
public void shouldCollectEmptyOptionalUsingPartialFunction() {
final PartialFunction<Integer, String> pf = Function1.<Integer, String> of(String::valueOf).partial(i -> i % 2 == 1);
assertThat(Option.<Integer>none().collect(pf)).isEqualTo(Option.none());
}
@Test(expected = NullPointerException.class)
public void shouldThrowExceptionOnNullCollectPartialFunction() {
final PartialFunction<Integer, String> pf = null;
Option.some(1).collect(pf);
}
// -- iterator
@Test
public void shouldReturnIteratorOfSome() {
assertThat((Iterator<Integer>) Option.some(1).iterator()).isNotNull();
}
@Test
public void shouldReturnIteratorOfNone() {
assertThat((Iterator<Object>) Option.none().iterator()).isNotNull();
}
// -- equals
@Test
public void shouldEqualNoneIfObjectIsSame() {
final Option<?> none = Option.none();
assertThat(none).isEqualTo(none);
}
@Test
public void shouldEqualSomeIfObjectIsSame() {
final Option<?> some = Option.some(1);
assertThat(some).isEqualTo(some);
}
@Test
public void shouldNotEqualNoneIfObjectIsNull() {
assertThat(Option.none()).isNotNull();
}
@Test
public void shouldNotEqualSomeIfObjectIsNull() {
assertThat(Option.some(1)).isNotNull();
}
@Test
public void shouldNotEqualNoneIfObjectIsOfDifferentType() {
final Object none = Option.none();
assertThat(none.equals(new Object())).isFalse();
}
@Test
public void shouldNotEqualSomeIfObjectIsOfDifferentType() {
final Object some = Option.some(1);
assertThat(some.equals(new Object())).isFalse();
}
@Test
public void shouldEqualSomeIfObjectsAreEquivalent() {
assertThat(Option.some(1)).isEqualTo(Option.some(1));
}
@Test
public void shouldNotEqualSomeIfObjectIsOfDifferentValue() {
assertThat(Option.some(1)).isNotEqualTo(Option.some(2));
}
// -- hashCode
@Test
public void shouldHashNone() {
assertThat(Option.none().hashCode()).isEqualTo(Objects.hash());
}
@Test
public void shouldHashSome() {
assertThat(Option.some(1).hashCode()).isEqualTo(Objects.hashCode(1));
}
// -- toString
@Test
public void shouldConvertSomeToString() {
assertThat(Option.some(1).toString()).isEqualTo("Some(1)");
}
@Test
public void shouldConvertNoneToString() {
assertThat(Option.none().toString()).isEqualTo("None");
}
// -- serialization
@Test
public void shouldPreserveSingletonWhenDeserializingNone() {
final Object none = Serializables.deserialize(Serializables.serialize(Option.none()));
assertThat(none == Option.none()).isTrue();
}
// -- toCompletableFuture
@Test
public void shouldConvertSomeToCompletableFuture() {
final String some = "some";
final CompletableFuture<String> future = API.Option(some).toCompletableFuture();
assertThat(future.isDone());
assertThat(Try.of(future::get).get()).isEqualTo(some);
}
@Test
public void shouldConvertNoneToFailedCompletableFuture() {
final CompletableFuture<Object> future = API.None().toCompletableFuture();
assertThat(future.isDone());
assertThat(future.isCompletedExceptionally());
}
// -- spliterator
@Test
public void shouldHaveSizedSpliterator() {
assertThat(of(1).spliterator().hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)).isTrue();
}
@Test
public void shouldHaveOrderedSpliterator() {
assertThat(of(1).spliterator().hasCharacteristics(Spliterator.ORDERED)).isTrue();
}
@Test
public void shouldReturnSizeWhenSpliterator() {
assertThat(of(1).spliterator().getExactSizeIfKnown()).isEqualTo(1);
}
}