package com.googlecode.totallylazy;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.predicates.Predicates;
import org.hamcrest.Matchers;
import org.junit.Test;
import java.util.Enumeration;
import java.util.Vector;
import static com.googlecode.totallylazy.functions.Callables.returns;
import static com.googlecode.totallylazy.Option.none;
import static com.googlecode.totallylazy.Option.some;
import static com.googlecode.totallylazy.Pair.pair;
import static com.googlecode.totallylazy.Quadruple.quadruple;
import static com.googlecode.totallylazy.Quintuple.quintuple;
import static com.googlecode.totallylazy.Sequences.characters;
import static com.googlecode.totallylazy.Sequences.empty;
import static com.googlecode.totallylazy.Sequences.iterate;
import static com.googlecode.totallylazy.Sequences.join;
import static com.googlecode.totallylazy.Sequences.repeat;
import static com.googlecode.totallylazy.Sequences.sequence;
import static com.googlecode.totallylazy.Sequences.transpose;
import static com.googlecode.totallylazy.Triple.triple;
import static com.googlecode.totallylazy.matchers.IterableMatcher.hasExactly;
import static com.googlecode.totallylazy.matchers.IterableMatcher.startsWith;
import static com.googlecode.totallylazy.numbers.Numbers.decrement;
import static com.googlecode.totallylazy.numbers.Numbers.even;
import static com.googlecode.totallylazy.numbers.Numbers.increment;
import static com.googlecode.totallylazy.numbers.Numbers.numbers;
import static com.googlecode.totallylazy.numbers.Numbers.odd;
import static com.googlecode.totallylazy.numbers.Numbers.range;
import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
public class SequencesTest {
@Test
public void shouldCreateEmptySequenceWhenIterableIsNull() throws Exception {
assertThat(sequence((Iterable<Object>) null), is(empty()));
assertThat(sequence((Object[]) null), is(empty(Object.class)));
}
@Test
@SuppressWarnings("unchecked")
public void supportsTranspose() {
Sequence<Sequence<Integer>> transposed = transpose(sequence(1, 2), sequence(3, 4), sequence(5, 6));
assertThat(transposed, hasExactly(sequence(1, 3, 5), sequence(2, 4, 6)));
assertThat(transpose(transposed), hasExactly(sequence(1, 2), sequence(3, 4), sequence(5, 6)));
assertThat(sequence(1, 2).transpose(sequence(3, 4)), hasExactly(sequence(1, 3), sequence(2, 4)));
}
@Test
public void supportsUnzip() {
Pair<Sequence<Integer>, Sequence<Integer>> pair = Sequences.unzip(sequence(pair(1, 2), pair(3, 4), pair(5, 6)));
assertThat(pair.first(), hasExactly(1, 3, 5));
assertThat(pair.second(), hasExactly(2, 4, 6));
}
@Test
public void supportsUnzippingTriples() {
Triple<Sequence<Integer>, Sequence<Integer>, Sequence<String>> triple = Sequences.unzip3(sequence(triple(1, 2, "car"), triple(3, 4, "cat")));
assertThat(triple.first(), hasExactly(1, 3));
assertThat(triple.second(), hasExactly(2, 4));
assertThat(triple.third(), hasExactly("car", "cat"));
}
@Test
public void supportsUnzippingQuadruples() {
Quadruple<Sequence<Integer>, Sequence<Integer>, Sequence<String>, Sequence<Character>> quadruple = Sequences.unzip4(sequence(quadruple(1, 2, "car", 'C'), quadruple(3, 4, "cat", 'D')));
assertThat(quadruple.first(), hasExactly(1, 3));
assertThat(quadruple.second(), hasExactly(2, 4));
assertThat(quadruple.third(), hasExactly("car", "cat"));
assertThat(quadruple.fourth(), hasExactly('C', 'D'));
}
@Test
public void supportsUnzippingQuintuples() {
Quintuple<Sequence<Integer>, Sequence<Integer>, Sequence<String>, Sequence<Character>, Sequence<Integer>> quintuple =
Sequences.unzip5(sequence(quintuple(1, 2, "car", 'C', 1), quintuple(3, 4, "cat", 'D', 2)));
assertThat(quintuple.first(), hasExactly(1, 3));
assertThat(quintuple.second(), hasExactly(2, 4));
assertThat(quintuple.third(), hasExactly("car", "cat"));
assertThat(quintuple.fourth(), hasExactly('C', 'D'));
assertThat(quintuple.fifth(), hasExactly(1, 2));
}
@Test
public void supportsCycle() throws Exception {
assertThat(range(1, 3).cycle(), startsWith((Number) 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3));
}
@Test
public void supportsAddingToAnEmptyList() throws Exception {
assertThat(sequence().append(1).append(2).append(3), hasExactly((Object) 1, 2, 3));
}
@Test
public void joinWorksEvenWhenFirstIterableIsEmpty() throws Exception {
final Sequence<Integer> empty = Sequences.<Integer>empty();
assertThat(empty.append(1).join(sequence(2, 3)).append(4), hasExactly(1, 2, 3, 4));
assertThat(join(empty, sequence(1, 2, 3), empty, asList(4, 5, 6)), hasExactly(1, 2, 3, 4, 5, 6));
}
@Test
public void supportsJoiningSubTypes() throws Exception {
final Sequence<Number> numbers = numbers(2, 3.0D);
Sequence<Integer> integers = sequence(2, 3);
Sequence<Long> longs = sequence(2L, 3L);
assertThat(numbers.join(integers).join(longs), hasExactly((Number) 2, 3.0D, 2, 3, 2L, 3L));
assertThat(join(sequence(1L, 2.0D, 3), numbers, asList(4, 5, 6), integers), hasExactly((Number) 1L, 2.0D, 3, 2, 3.0D, 4, 5, 6, 2, 3));
}
@Test
public void supportsEnumeration() throws Exception {
Vector<String> vector = new Vector<String>();
vector.add("foo");
Enumeration enumeration = vector.elements();
Sequence<String> forwardOnly = Sequences.forwardOnly(enumeration, String.class);
assertThat(forwardOnly.headOption().isEmpty(), is(false));
assertThat(forwardOnly.headOption().isEmpty(), is(true));
Sequence<String> forwardOnlyWithType = Sequences.forwardOnly(vector.elements());
assertThat(forwardOnlyWithType.headOption().isEmpty(), is(false));
assertThat(forwardOnlyWithType.headOption().isEmpty(), is(true));
}
@Test
public void supportsMemorisingAnEnumeration() throws Exception {
Vector<String> vector = new Vector<String>();
vector.add("foo");
Enumeration enumeration = vector.elements();
Sequence<String> memorise = Sequences.memorise(enumeration, String.class);
assertThat(memorise.headOption().isEmpty(), is(false));
assertThat(memorise.headOption().isEmpty(), is(false));
Sequence<String> memorisedWithType = Sequences.memorise(vector.elements());
assertThat(memorisedWithType.headOption().isEmpty(), is(false));
assertThat(memorisedWithType.headOption().isEmpty(), is(false));
}
@Test
public void supportRepeat() throws Exception {
assertThat(repeat(10), startsWith(10, 10, 10, 10, 10));
assertThat(repeat(returns(10)), startsWith(10, 10, 10, 10, 10));
}
@Test
public void supportsCharacters() throws Exception {
assertThat(characters("text"), hasExactly('t', 'e', 'x', 't'));
assertThat(characters("text".toCharArray()), hasExactly('t', 'e', 'x', 't'));
assertThat(characters("text").drop(2).toString(""), is("xt"));
}
@Test
public void supportsIterate() throws Exception {
assertThat(iterate(increment, 1), startsWith((Number) 1, 2, 3, 4, 5));
}
@Test
public void supportsIteratingEvenWhenCallableReturnNull() throws Exception {
final Sequence<Integer> sequence = iterate(integer -> {
assertThat("Should never see a null value", integer, is(Matchers.notNullValue()));
return null;
}, 1).takeWhile(Predicates.notNullValue());
assertThat(sequence, hasExactly(1));
}
@Test
public void canCombineIterateWithOtherOperations() throws Exception {
final Sequence<Number> numbers = iterate(increment, 1);
assertThat(numbers.filter(even()), startsWith((Number) 2, 4, 6));
assertThat(numbers.filter(odd()), startsWith((Number) 1, 3, 5, 7, 9));
}
@Test
public void supportsUnfoldRight() throws Exception {
Sequence<Number> result = Sequences.unfoldRight(new Function1<Number, Option<Pair<Number, Number>>>() {
@Override
public Option<Pair<Number, Number>> call(Number number) throws Exception {
if (number.equals(0)) return none();
return some(pair(number, decrement(number)));
}
}, 10);
assertThat(result, is(range(10, 1)));
}
}