package com.googlecode.totallylazy;
import com.googlecode.totallylazy.functions.Curried2;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.matchers.NumberMatcher;
import com.googlecode.totallylazy.predicates.Predicates;
import org.junit.Test;
import java.util.NoSuchElementException;
import static com.googlecode.totallylazy.functions.Callables.callThrows;
import static com.googlecode.totallylazy.functions.Callables.ignoreAndReturn;
import static com.googlecode.totallylazy.functions.Callables.returns;
import static com.googlecode.totallylazy.functions.Callables.toString;
import static com.googlecode.totallylazy.functions.Functions.constant;
import static com.googlecode.totallylazy.Objects.equalTo;
import static com.googlecode.totallylazy.Option.applicate;
import static com.googlecode.totallylazy.Option.none;
import static com.googlecode.totallylazy.Option.option;
import static com.googlecode.totallylazy.Option.some;
import static com.googlecode.totallylazy.OptionTest.Person.person;
import static com.googlecode.totallylazy.Sequences.sequence;
import static com.googlecode.totallylazy.Sequences.size;
import static com.googlecode.totallylazy.matchers.IterableMatcher.hasExactly;
import static com.googlecode.totallylazy.numbers.Numbers.add;
import static com.googlecode.totallylazy.numbers.Numbers.divide;
import static com.googlecode.totallylazy.numbers.Numbers.number;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
public class OptionTest {
@Test
public void supportsContains() throws Exception {
assertThat(option(1).contains(1), is(true));
assertThat(option(1).contains(2), is(false));
}
@Test
public void supportsIsAlias() throws Exception {
assertThat(option(1).is(Predicates.is(1)), is(true));
assertThat(option(1).is(Predicates.is(2)), is(false));
}
@Test
public void supportsExists() throws Exception {
assertThat(option(1).exists(Predicates.is(1)), is(true));
assertThat(option(1).exists(Predicates.is(2)), is(false));
}
@Test
public void supportsApplicativeEquality() throws Exception {
final Option<Curried2<Object, Object, Boolean>> some = some(equalTo());
final Option<Integer> some1 = some(3);
final Option<Function1<Object, Boolean>> applicate = applicate(some, some1);
assertThat(applicate(applicate, some(5)), is(some(false)));
assertThat(applicate(applicate(some(equalTo()), some(3)), some(3)), is(some(true)));
assertThat(applicate(applicate(some(equalTo()), none(Integer.class)), some(3)), is(none(Boolean.class)));
assertThat(applicate(applicate(some(equalTo()), some(3)), none(Integer.class)), is(none(Boolean.class)));
}
@Test
public void supportsApplicativeUsage() throws Exception {
assertThat(none(Number.class).applicate(some(add(3))), is(none(Number.class)));
assertThat(some(9).applicate(Option.<Function1<Number, Number>>none()), is(none(Number.class)));
assertThat(some(9).applicate(some(add(3))), is(Option.<Number>some(12)));
assertThat(some(5).applicate(some(3).applicate(some(add()))), is(Option.<Number>some(8)));
assertThat(none(Number.class).applicate(some(3).applicate(some(add()))), is(none(Number.class)));
assertThat(some(5).applicate(none(Number.class).applicate(some(add()))), is(none(Number.class)));
assertThat(applicate(applicate(some(add()), some(3)), some(5)), is(Option.<Number>some(8)));
assertThat(applicate(applicate(some(add()), none(Number.class)), some(5)), is(none(Number.class)));
assertThat(applicate(applicate(some(add()), some(3)), none(Number.class)), is(none(Number.class)));
}
@Test
public void supportsApplicativeUsageToConstruct() throws Exception {
assertThat(some("Dan").applicate(some(35).applicate(some(person().flip()))), is(some(person("Dan", 35))));
assertThat(some("Ray").applicate(none(Integer.class).applicate(some(person().flip()))), is(none(Person.class)));
assertThat(none(String.class).applicate(some(100).applicate(some(person().flip()))), is(none(Person.class)));
assertThat(applicate(applicate(some(person()), some("Dan")), some(35)), is(some(person("Dan", 35))));
assertThat(applicate(applicate(some(person()), some("Ray")), none(Integer.class)), is(none(Person.class)));
assertThat(applicate(applicate(some(person()), none(String.class)), some(100)), is(none(Person.class)));
}
@Test
public void supportsJoin() {
assertThat(some(1).join(sequence(2, 3)), hasExactly(1, 2, 3));
assertThat(none(Integer.class).join(sequence(1, 2, 3)), hasExactly(1, 2, 3));
}
static class Person {
private final String name;
private final int age;
private Person(String name, int age) {
this.name = name;
this.age = age;
}
static Curried2<String, Integer, Person> person() {
return Person::person;
}
static Person person(String name, int age) {
return new Person(name, age);
}
private Sequence<Object> values() {
return Sequences.<Object>sequence(name, age);
}
@Override
public boolean equals(Object o) {
return o instanceof Person && ((Person) o).values().equals(values());
}
@Override
public int hashCode() {
return values().hashCode();
}
}
@Test
public void canFold() throws Exception {
assertThat(option(1).fold(1, add()), NumberMatcher.is(2));
assertThat(some(1).fold(1, add()), NumberMatcher.is(2));
assertThat(Option.<Number>none().fold(1, add()), NumberMatcher.is(1));
}
@Test
public void canMap() throws Exception {
assertThat(option(1).map(toString), is(option("1")));
assertThat(some(2).map(toString), is(some("2")));
assertThat(none().map(toString), is(none(String.class)));
assertThat(some(2).map(ignoreAndReturn(null)), is(none()));
}
@Test
public void canFlatMap() {
assertThat(some(number(4)).flatMap(divide(2).optional()), is(some((Number) 2)));
assertThat(some(number(4)).flatMap(divide(0).optional()), is(none(Number.class)));
assertThat(none(Number.class).flatMap(constant(none(Number.class))), is(none(Number.class)));
assertThat(none(Number.class).flatMap(constant(some(number(4)))), is(none(Number.class)));
}
@Test
public void canFlatten() {
assertThat(Option.flatten(some(some(1))), is(some(1)));
assertThat(Option.flatten(some(none())), is(none()));
}
@Test
public void areIterable() throws Exception {
assertThat(size(some(1)), NumberMatcher.is(1));
assertThat(size(none()), NumberMatcher.is(0));
}
@Test
public void canGetValueOfSome() throws Exception {
assertThat(some(1).get(), is(1));
}
@Test(expected = NoSuchElementException.class)
public void cannotGetValueOfNone() throws Exception {
none().get();
}
@Test
public void canGetOrElseValue() throws Exception {
assertThat(some(1).getOrElse(2), is(1));
assertThat(Option.<Integer>none().getOrElse(2), is(2));
assertThat(option(1).getOrElse(2), is(1));
assertThat(Option.<Integer>option(null).getOrElse(2), is(2));
}
@Test
public void canGetOrElseWithCallable() throws Exception {
assertThat(some(1).getOrElse(returns(2)), is(1));
assertThat(Option.<Integer>none().getOrElse(returns(2)), is(2));
assertThat(option(1).getOrElse(returns(2)), is(1));
assertThat(Option.<Integer>option(null).getOrElse(returns(2)), is(2));
try {
assertThat(Option.<Integer>option(null).getOrElse(callThrows(new RuntimeException(), Integer.class)), is(2));
fail();
} catch (RuntimeException e) {
}
}
@Test
public void canGetOrNullValue() throws Exception {
assertThat(some(1).getOrNull(), is(1));
assertThat(Option.<Integer>none().getOrNull(), is(nullValue(Integer.class)));
assertThat(option(1).getOrNull(), is(1));
assertThat(Option.<Integer>option(null).getOrNull(), is(nullValue(Integer.class)));
}
@Test
public void canSeeIfEmpty() throws Exception {
assertThat(some(1).isEmpty(), is(false));
assertThat(none().isEmpty(), is(true));
}
@Test(expected = RuntimeException.class)
public void canThrowIfNone() throws Exception{
assertThat(some("bob").getOrThrow(new RuntimeException()), is("bob"));
none().getOrThrow(new RuntimeException());
}
@Test
public void canConvertSomeToEitherAsRight() {
assertThat(some("all good").<String>toEither("borked"), is(Either.<String, String>right("all good")));
}
@Test
public void canConvertNoneToEitherAsLeft() {
assertThat(none().toEither("borked"), is(Either.<String, Object>left("borked")));
}
}