package com.googlecode.totallylazy;
import com.googlecode.totallylazy.functions.Callables;
import com.googlecode.totallylazy.functions.CountCalls0;
import com.googlecode.totallylazy.comparators.Comparators;
import com.googlecode.totallylazy.concurrent.NamedExecutors;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.functions.Functions;
import com.googlecode.totallylazy.matchers.Matchers;
import com.googlecode.totallylazy.matchers.NumberMatcher;
import com.googlecode.totallylazy.numbers.Numbers;
import com.googlecode.totallylazy.predicates.Predicate;
import com.googlecode.totallylazy.predicates.Predicates;
import com.googlecode.totallylazy.time.Dates;
import org.junit.Ignore;
import org.junit.Test;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import static com.googlecode.totallylazy.Arrays.list;
import static com.googlecode.totallylazy.Strings.isBlank;
import static com.googlecode.totallylazy.functions.Callables.ascending;
import static com.googlecode.totallylazy.functions.Callables.call;
import static com.googlecode.totallylazy.functions.Callables.callThrows;
import static com.googlecode.totallylazy.functions.Callables.descending;
import static com.googlecode.totallylazy.functions.Callables.length;
import static com.googlecode.totallylazy.functions.Callables.returnArgument;
import static com.googlecode.totallylazy.functions.Callables.returns;
import static com.googlecode.totallylazy.functions.Callables.second;
import static com.googlecode.totallylazy.functions.Callables.size;
import static com.googlecode.totallylazy.functions.Callables.toString;
import static com.googlecode.totallylazy.functions.Functions.and;
import static com.googlecode.totallylazy.functions.Functions.andPair;
import static com.googlecode.totallylazy.functions.Functions.or;
import static com.googlecode.totallylazy.functions.Functions.orPair;
import static com.googlecode.totallylazy.functions.Functions.xor;
import static com.googlecode.totallylazy.Lists.indexIn;
import static com.googlecode.totallylazy.Option.identity;
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.Pair.pair;
import static com.googlecode.totallylazy.predicates.Predicates.greaterThan;
import static com.googlecode.totallylazy.predicates.Predicates.lessThan;
import static com.googlecode.totallylazy.predicates.Predicates.notNullValue;
import static com.googlecode.totallylazy.Quadruple.quadruple;
import static com.googlecode.totallylazy.Quintuple.quintuple;
import static com.googlecode.totallylazy.Runnables.printLine;
import static com.googlecode.totallylazy.Sequences.applicate;
import static com.googlecode.totallylazy.Sequences.characters;
import static com.googlecode.totallylazy.Sequences.cons;
import static com.googlecode.totallylazy.Sequences.empty;
import static com.googlecode.totallylazy.Sequences.flatOption;
import static com.googlecode.totallylazy.Sequences.flatten;
import static com.googlecode.totallylazy.Sequences.one;
import static com.googlecode.totallylazy.Sequences.repeat;
import static com.googlecode.totallylazy.Sequences.sequence;
import static com.googlecode.totallylazy.Sequences.sort;
import static com.googlecode.totallylazy.Sequences.splitOn;
import static com.googlecode.totallylazy.Sequences.zip;
import static com.googlecode.totallylazy.Strings.join;
import static com.googlecode.totallylazy.Strings.toCharacters;
import static com.googlecode.totallylazy.Triple.triple;
import static com.googlecode.totallylazy.functions.Count.count;
import static com.googlecode.totallylazy.functions.CountCalls0.counting;
import static com.googlecode.totallylazy.comparators.Comparators.comparators;
import static com.googlecode.totallylazy.matchers.IterableMatcher.hasExactly;
import static com.googlecode.totallylazy.matchers.IterableMatcher.isEmpty;
import static com.googlecode.totallylazy.matchers.IterableMatcher.startsWith;
import static com.googlecode.totallylazy.numbers.Numbers.add;
import static com.googlecode.totallylazy.numbers.Numbers.even;
import static com.googlecode.totallylazy.numbers.Numbers.multiply;
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 com.googlecode.totallylazy.numbers.Numbers.sum;
import static java.lang.Thread.currentThread;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.fail;
public class SequenceTest {
@Test
public void head() throws Exception {
assertThat(sequence(1, 2).head(), is(1));
}
@Test
public void headOption() throws Exception {
assertThat(sequence(1).headOption(), is(some(1)));
assertThat(empty().headOption(), is(none()));
}
@Test
public void last() throws Exception {
assertThat(sequence(1, 2, 3).last(), is(3));
}
@Test
public void lastOption() throws Exception {
assertThat(sequence(1, 2, 3).lastOption(), is(some(3)));
assertThat(empty().lastOption(), is(none()));
}
@Test
public void tail() throws Exception {
assertThat(sequence(1, 2, 3).tail(), hasExactly(2, 3));
assertThat(sequence(1).tail().isEmpty(), is(true));
try {
empty().tail().isEmpty();
fail("Should have thrown NoSuchElementException");
} catch (NoSuchElementException e) {
// all good
}
}
@Test
public void init() throws Exception {
assertThat(sequence(1, 2, 3).init(), hasExactly(1, 2));
assertThat(sequence(1).init().isEmpty(), is(true));
try {
empty().init().isEmpty();
fail("Should have thrown NoSuchElementException");
} catch (NoSuchElementException e) {
// all good
}
}
@Test
public void supportsShuffle() throws Exception {
assertThat(range(1, 100).shuffle(), is(not(range(1, 100))));
}
@Test
public void supportsReduceWithIdentityFunction() throws Exception {
assertThat(sequence("one", "two", "three").reduce(count()), NumberMatcher.is(3));
}
@Test
public void supportsApplicativeUsage() throws Exception {
assertThat(empty(Number.class).applicate(one(add(3))), Matchers.is(empty(Number.class)));
assertThat(numbers(9).applicate(Sequences.<Function1<Number, Number>>empty()), Matchers.is(empty(Number.class)));
assertThat(numbers(9).applicate(one(add(3))), Matchers.is(numbers(12)));
assertThat(numbers(9, 1).applicate(one(add(3))), Matchers.is(numbers(12, 4)));
assertThat(numbers(9, 1).applicate(sequence(add(3), multiply(10))), Matchers.is(numbers(12, 4, 90, 10)));
//http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors (Lists)
assertThat(applicate(applicate(sequence(add(), multiply()), numbers(1, 2)), numbers(3, 4)), Matchers.is(numbers(4, 5, 5, 6, 3, 4, 6, 8)));
}
@Test
public void recursiveCallOnlyEndsWhenThereIsNoRemainder() throws Exception {
assertThat(sequence(1, 3, 0, 0, 2).recursive(splitOn(0)),
is(sequence(sequence(1, 3), empty(Integer.class), sequence(2))));
}
@Test
public void supportsRecursiveSplitOn() throws Exception {
assertThat(sequence(1, 3, -4, 0, 7, -9, 0, 2).recursive(splitOn(0)),
is(sequence(sequence(1, 3, -4), sequence(7, -9), sequence(2))));
}
@Test
public void supportsSplitOn() throws Exception {
assertThat(sequence(1, 3, -4, 0, 7, -9, 0, 2).splitOn(0),
is(pair(sequence(1, 3, -4), sequence(7, -9, 0, 2))));
}
@Test
public void supportsRecursiveSplitWhen() throws Exception {
assertThat(numbers(1, 3, -4, 5, 7, -9, 0, 2).recursive(Sequences.<Number>splitWhen(Numbers.lessThan(0))),
is(sequence(numbers(1, 3), numbers(5, 7), numbers(0, 2))));
}
@Test
public void supportsSplitWhen() throws Exception {
assertThat(numbers(1, 3, -4, 5, 7, -9, 0, 2).splitWhen(Numbers.lessThan(0)),
is(pair(numbers(1, 3), numbers(5, 7, -9, 0, 2))));
}
@Test
public void supportsReduceRight() throws Exception {
assertThat(numbers().reduceRight(sum), NumberMatcher.is(0));
assertThat(numbers(1).reduceRight(sum), NumberMatcher.is(1));
assertThat(numbers(1, 2).reduceRight(sum), NumberMatcher.is(3));
assertThat(numbers(1, 2, 3).reduceRight(sum), NumberMatcher.is(6));
assertThat(Sequences.<String>sequence().reduceRight(join), is(""));
assertThat(sequence("1").reduceRight(join), is("1"));
assertThat(sequence("1", "2").reduceRight(join), is("12"));
assertThat(sequence("1", "2", "3").reduceRight(join), is("123"));
}
@Test
public void supportsFoldRight() throws Exception {
assertThat(numbers().foldRight(4, sum), NumberMatcher.is(4));
assertThat(numbers(1).foldRight(4, sum), NumberMatcher.is(5));
assertThat(numbers(1, 2).foldRight(4, sum), NumberMatcher.is(7));
assertThat(numbers(1, 2, 3).foldRight(4, sum), NumberMatcher.is(10));
assertThat(Sequences.<String>sequence().foldRight("4", join), is("4"));
assertThat(sequence("1").foldRight("4", join), is("14"));
assertThat(sequence("1", "2").foldRight("4", join), is("124"));
assertThat(sequence("1", "2", "3").foldRight("4", join), is("1234"));
}
@Test
public void supportsFoldRightWithInfiniteSequenceIfFunctionTerminatesEarlyAndUsesPairs() throws Exception {
assertThat(repeat(false).foldRight(false, andPair()), is(false));
assertThat(repeat("a").foldRight("z", p -> p.first()), is("a"));
assertThat(Sequences.<String>sequence().foldRight("d", join.pair()), is("d"));
assertThat(sequence("a").foldRight("d", join.pair()), is("ad"));
assertThat(sequence("a", "b").foldRight("d", join.pair()), is("abd"));
assertThat(sequence("a", "b", "c").foldRight("d", join.pair()), is("abcd"));
}
@Test
public void supportsReduceRightWithInfiniteSequenceIfFunctionTerminatesEarlyAndUsesPairs() throws Exception {
assertThat(repeat(true).reduceRight(orPair()), is(true));
assertThat(range(0).reduceRight(p -> p.first()), NumberMatcher.is(0));
assertThat(Sequences.<String>sequence().reduceRight(join.pair()), is(""));
assertThat(sequence("a").reduceRight(join.pair()), is("a"));
assertThat(sequence("a", "b").reduceRight(join.pair()), is("ab"));
assertThat(sequence("a", "b", "c").reduceRight(join.pair()), is("abc"));
}
@Test
public void supportsBreak() throws Exception {
assertThat(sequence(1, 2, 3, 4, 1, 2, 3, 4).breakOn(greaterThan(3)),
is(pair(sequence(1, 2, 3), sequence(4, 1, 2, 3, 4))));
assertThat(sequence(1, 2, 3).breakOn(lessThan(9)),
is(pair(empty(Integer.class), sequence(1, 2, 3))));
assertThat(sequence(1, 2, 3).breakOn(greaterThan(9)),
is(pair(sequence(1, 2, 3), empty(Integer.class))));
}
@Test
public void supportsSpan() throws Exception {
assertThat(sequence(1, 2, 3, 4, 1, 2, 3, 4).span(lessThan(3)), is(pair(sequence(1, 2), sequence(3, 4, 1, 2, 3, 4))));
assertThat(sequence(1, 2, 3).span(lessThan(9)), is(pair(sequence(1, 2, 3), Sequences.<Integer>empty())));
assertThat(sequence(1, 2, 3).span(lessThan(0)), is(pair(Sequences.<Integer>empty(), sequence(1, 2, 3))));
}
@Test
public void supportsSplitAt() throws Exception {
Sequence<String> data = sequence("Cat", "Dog", "Mouse", "Rabbit", "Monkey");
assertThat(data.splitAt(2), is(pair(sequence("Cat", "Dog"), sequence("Mouse", "Rabbit", "Monkey"))));
assertThat(characters("Hello World!").splitAt(6).first().toString(""), is("Hello "));
assertThat(characters("Hello World!").splitAt(6).second().toString(""), is("World!"));
}
@Test
public void supportsRecursiveSplitAt() throws Exception {
Sequence<String> data = sequence("Cat", "Dog", "Mouse", "Rabbit", "Monkey");
assertThat(data.recursive(Sequences.<String>splitAt(2)), is(sequence(sequence("Cat", "Dog"), sequence("Mouse", "Rabbit"), sequence("Monkey"))));
}
@Test
public void supportsEquality() throws Exception {
assertThat(sequence(1, 2, 3).equals(sequence(1, 2, 3)), is(true));
assertThat(sequence(1, 2, 3).equals(sequence(3, 2, 1)), is(false));
assertThat(sequence(1, 2, 3).equals(sequence("1", "2", "3")), is(false));
assertThat(sequence(1, 2).equals(sequence(1, 2, 3)), is(false));
assertThat(sequence(1, 2, 3).equals(sequence(1, 2)), is(false));
assertThat(sequence(1, 2, 3).equals(list(1, 2, 3)), is(true));
assertThat(sequence(Dates.date(2000, 1, 1), 1).equals(sequence(Dates.date(2000, 1, 1), 1)), is(true));
assertThat(sequence(Dates.date(2000, 1, 1), 1).equals(sequence(null, 1)), is(false));
assertThat(sequence(null, 1).equals(sequence(Dates.date(2000, 1, 1), 1)), is(false));
assertThat(sequence(1, null, 3).equals(sequence(1, 2, 3)), is(false));
assertThat(sequence(1, 2, 3).equals(sequence(1, null, 3)), is(false));
assertThat(sequence(1, null, 3).equals(sequence(1, null, 3)), is(true));
}
@Test
public void supportsHashCodes() throws Exception {
assertThat(sequence(1, 2, 3).hashCode() == sequence(1, 2, 3).hashCode(), is(true));
assertThat(sequence(1, 2, 3).hashCode() == sequence(3, 2, 1).hashCode(), is(true)); // could we make this false easily?
assertThat(sequence(1, 2, 3).hashCode() == sequence("1", "2", "3").hashCode(), is(false));
assertThat(sequence(1, 2).hashCode() == sequence(1, 2, 3).hashCode(), is(false));
assertThat(sequence(1, 2, 3).hashCode() == sequence(1, 2).hashCode(), is(false));
assertThat(sequence(1, 2, 3).hashCode() == list(1, 2, 3).hashCode(), is(false));
assertThat(sequence(1, null, 3, objectWithHashCodeOf(0)).hashCode() != 0, is(true));
}
private Object objectWithHashCodeOf(final int value) {
return new Object() {
@Override
public int hashCode() {
return value;
}
};
}
@Test
public void supportsGroupByAndPreservesOrder() throws Exception {
Sequence<Group<Number, Integer>> groups = sequence(1, 2, 3, 4).groupBy(Numbers.mod(2));
assertThat(groups.first().key(), NumberMatcher.is(1));
assertThat(groups.first(), hasExactly(1, 3));
assertThat(groups.second().key(), NumberMatcher.is(0));
assertThat(groups.second(), hasExactly(2, 4));
}
@Test
public void supportsGrouped() throws Exception {
Sequence<Integer> sequence = sequence(1, 2, 3, 4, 5);
assertThat(sequence.grouped(1), is(sequence(sequence(1), sequence(2), sequence(3), sequence(4), sequence(5))));
assertThat(sequence.grouped(3), is(sequence(sequence(1, 2, 3), sequence(4, 5))));
assertThat(sequence.grouped(5), is(Sequences.<Sequence<Integer>>sequence(sequence(1, 2, 3, 4, 5))));
assertThat(sequence.grouped(6), is(Sequences.<Sequence<Integer>>sequence(sequence(1, 2, 3, 4, 5))));
}
@Test
@Ignore("Manual Test")
public void groupedDoesNotBlowStack() throws Exception {
Sequence<Number> elements = range(0).take(100000);
elements.grouped(10000).realise();
}
@Test
public void supportsToMapAndPreservesOrder() throws Exception {
Map<Number, List<Integer>> groups = sequence(1, 4, 2, 3).toMap(Numbers.mod(2));
assertThat(groups.get(0), hasExactly(4, 2));
assertThat(groups.get(1), hasExactly(1, 3));
}
@Test
public void supportsPartition() throws Exception {
Pair<Sequence<Integer>, Sequence<Integer>> result = sequence(1, 2, 3, 4).partition(even());
assertThat(result.first(), hasExactly(2, 4));
assertThat(result.second(), hasExactly(1, 3));
}
@Test
public void supportsPartitionOnForwardOnlySequence() throws Exception {
Pair<Sequence<Integer>, Sequence<Integer>> result = sequence(1, 2, 3, 4).forwardOnly().partition(even());
assertThat(result.first(), hasExactly(2, 4));
assertThat(result.second(), hasExactly(1, 3));
}
@Test
public void supportsReverse() throws Exception {
assertThat(sequence(1, 2, 3).reverse(), hasExactly(3, 2, 1));
}
@Test
public void supportsSize() throws Exception {
assertThat(range(10000000000L, 10000000099L).size(), NumberMatcher.is(100));
}
@Test
public void canRealiseASequence() throws Exception {
CountCalls0<Integer> counting = counting();
Sequence<Integer> lazy = sequence(counting).map(call(Integer.class));
assertThat(counting.count(), is(0));
assertThat(lazy, hasExactly(0)); // this will increment count by 1
Sequence<Integer> realised = lazy.realise(); // this will increment count by 1
assertThat(counting.count(), is(2));
assertThat(realised, hasExactly(1));
assertThat(realised, hasExactly(1));
}
@Test
public void supportsUnsafeCast() throws Exception {
Sequence<? extends Predicate<?>> wild = sequence(wildCard());
Sequence<Predicate<Object>> boring = wild.unsafeCast();
assertThat(boring.head().matches(new Cat()), is(true));
assertThat(boring.head().matches(null), is(false));
}
private Predicate<?> wildCard() {
return Predicates.notNullValue();
}
@Test
public void supportsSafeCast() throws Exception {
Cat freaky = new Cat(), fatty = new Cat();
Dog buster = new Dog();
Sequence<Animal> animals = sequence(freaky, fatty, buster);
Sequence<Cat> cats = animals.safeCast(Cat.class);
Sequence<Dog> dogs = animals.safeCast(Dog.class);
assertThat(cats, hasExactly(freaky, fatty));
assertThat(dogs, hasExactly(buster));
}
public static interface Animal {
}
public static class Cat implements Animal {
}
public static class Dog implements Animal {
}
@Test
public void supportsUniqueAndPreservesOrder() throws Exception {
assertThat(sequence(1, 2, 1, 4, 3, 2).unique(), hasExactly(1, 2, 4, 3));
assertThat(sequence("Matt", "Dan", "Matt", "Bob").unique(), hasExactly("Matt", "Dan", "Bob"));
}
@Test
public void supportsUniqueAndCanBeIteratedMultipleTimes() throws Exception {
Sequence<String> unique = sequence("Matt", "Dan", "Matt", "Bob").unique();
assertThat(unique, hasExactly("Matt", "Dan", "Bob"));
assertThat(unique, hasExactly("Matt", "Dan", "Bob"));
Sequence<String> uniqueWithCallable = sequence("Matt", "Dan", "Dominic", "Mary").unique(Strings.characterAt(0));
assertThat(uniqueWithCallable, hasExactly("Matt", "Dan"));
assertThat(uniqueWithCallable, hasExactly("Matt", "Dan"));
}
@Test
public void supportsUniqueWithCallable() throws Exception {
assertThat(sequence("Matt", "Dan", "Dominic", "Mary").unique(Strings.characterAt(0)), hasExactly("Matt", "Dan"));
}
@Test
public void supportsSort() throws Exception {
assertThat(sort(sequence(5, 6, 1, 3, 4, 2)), hasExactly(1, 2, 3, 4, 5, 6));
assertThat(sort(sequence("Matt", "Dan", "Bob")), hasExactly("Bob", "Dan", "Matt"));
}
@Test
public void supportsSortDescending() throws Exception {
assertThat(sort(sequence(5, 6, 1, 3, 4, 2), Comparators.<Integer>descending()), hasExactly(6, 5, 4, 3, 2, 1));
assertThat(sequence(5, 6, 1, 3, 4, 2).sortBy(Comparators.<Integer>descending()), hasExactly(6, 5, 4, 3, 2, 1));
assertThat(sort(sequence("Bob", "Dan", "Matt"), Comparators.<String>descending()), hasExactly("Matt", "Dan", "Bob"));
assertThat(sequence("Bob", "Dan", "Matt").sortBy(Comparators.<String>descending()), hasExactly("Matt", "Dan", "Bob"));
}
@Test
public void supportsSortBy() throws Exception {
int[] small = {1};
int[] medium = {1, 2, 3};
int[] large = {1, 2, 3, 4, 5, 6};
Sequence<int[]> unsorted = sequence(large, small, medium);
assertThat(unsorted.sortBy(length()), hasExactly(small, medium, large));
assertThat(unsorted.sortBy(ascending(length())), hasExactly(small, medium, large));
assertThat(unsorted.sortBy(descending(length())), hasExactly(large, medium, small));
}
@Test
public void whenSortingWithNullsTheyAlwaysComeLast() throws Exception {
Sequence<Integer> unsorted = sequence(2, null, 1);
assertThat(unsorted.sortBy(returnArgument(Integer.class)), hasExactly(1, 2, null));
assertThat(unsorted.sortBy(ascending(returnArgument(Integer.class))), hasExactly(1, 2, null));
assertThat(unsorted.sortBy(descending(returnArgument(Integer.class))), hasExactly(2, 1, null));
}
@Test
public void supportsSortByWithCompositeComparator() throws Exception {
Sequence<String> unsorted = Sequences.sequence("dan", "tom", "mateusz", "stuart");
final Sequence<String> sorted = unsorted.sortBy(comparators(descending(length()), ascending(Callables.<String>returnArgument())));
assertThat(sorted, hasExactly("mateusz", "stuart", "dan", "tom"));
}
@Test
public void supportsSortBySizeAndLength() throws Exception {
int[] small = {1};
String medium = "123";
List<Integer> large = list(1, 2, 3, 4, 5, 6);
Sequence<Integer> veryLarge = sequence(1, 2, 3, 4, 5, 6, 7, 8, 9);
Sequence<Object> unsorted = sequence(large, small, veryLarge, medium);
assertThat(unsorted.sortBy(size()), hasExactly(small, medium, large, veryLarge));
assertThat(unsorted.sortBy(ascending(size())), hasExactly(small, medium, large, veryLarge));
assertThat(unsorted.sortBy(descending(length())), hasExactly(veryLarge, large, medium, small));
}
@Test
public void supportsCons() throws Exception {
assertThat(sequence(1, 2, 3).cons(4), hasExactly(4, 1, 2, 3));
assertThat(cons(4, sequence(1, 2, 3)), hasExactly(4, 1, 2, 3));
}
@Test
public void supportsJoin() throws Exception {
Sequence<Integer> numbers = sequence(1, 2, 3).join(sequence(4, 5, 6));
assertThat(numbers, hasExactly(1, 2, 3, 4, 5, 6));
}
@Test
public void supportsAdd() throws Exception {
Sequence<Integer> numbers = sequence(1, 2, 3).append(4);
assertThat(numbers, hasExactly(1, 2, 3, 4));
}
@Test
public void supportsTryPick() throws Exception {
Option<String> converted = sequence(1, 2, 3).tryPick(someVeryExpensiveOperation);
assertThat(converted, is((Option<String>) some("converted")));
}
@Test
public void supportsPick() throws Exception {
String converted = sequence(1, 2, 3).pick(someVeryExpensiveOperation);
assertThat(converted, is("converted"));
}
Function1<Integer, Option<String>> someVeryExpensiveOperation = number -> {
if (Numbers.equalTo(number, 1)) {
return none(); // the conversion didn't work
}
if (Numbers.equalTo(number, 2)) {
return some("converted"); // the conversion worked so don't do any more
}
throw new AssertionError("should never get here");
};
@Test
public void supportsFind() throws Exception {
assertThat(sequence(1, 3, 5).find(even()), is((Option<Integer>) none(Integer.class)));
assertThat(sequence(1, 2, 3).find(even()), is((Option<Integer>) some(2)));
}
@Test
public void supportsFindIndexOf() throws Exception {
assertThat(sequence(1, 3, 5).findIndexOf(even()), is((Option<Integer>) none(Integer.class)));
assertThat(sequence(1, 3, 6).findIndexOf(even()), is((Option<Integer>) some(2)));
}
@Test
public void supportsFindingTheFirstSome() throws Exception {
assertThat(sequence(none(Integer.class), some(2), some(3)).flatMap(identity(Integer.class)).headOption(), is((Option<Integer>) some(2)));
}
@Test
public void supportsContains() throws Exception {
assertThat(sequence(1, 3, 5).contains(2), is(false));
assertThat(sequence(1, 2, 3).contains(2), is(true));
}
@Test
public void supportsExists() throws Exception {
assertThat(sequence(1, 3, 5).exists(even()), is(false));
assertThat(sequence(1, 2, 3).exists(even()), is(true));
}
@Test
public void supportsForAll() throws Exception {
assertThat(sequence(1, 3, 5).forAll(odd()), is(true));
assertThat(sequence(1, 2, 3).forAll(odd()), is(false));
}
@Test
public void canFilterNull() throws Exception {
final Sequence<Integer> numbers = sequence(1, null, 3).filter(notNullValue());
assertThat(numbers, hasExactly(1, 3));
}
@Test
public void supportsRemove() throws Exception {
final Sequence<Integer> numbers = sequence(1, 2, 3, 2).delete(2);
assertThat(numbers, hasExactly(1, 3, 2));
}
@Test
public void supportsRemoveAll() throws Exception {
final Sequence<Integer> numbers = sequence(1, 2, 3, 2).deleteAll(sequence(2));
assertThat(numbers, hasExactly(1, 3));
}
@Test
public void canConvertToArray() throws Exception {
final Integer[] array = sequence(1, 2).toArray(Integer.class);
assertThat(array[0], is(1));
assertThat(array[1], is(2));
}
@Test
public void canConvertToList() throws Exception {
final List<Integer> aList = sequence(1, 2).toList();
assertThat(aList, hasExactly(1, 2));
}
@Test
public void canConvertToDeque() throws Exception {
final Deque<Integer> aList = sequence(1, 2).toDeque();
assertThat(aList, hasExactly(1, 2));
}
@Test
public void supportsIsEmpty() throws Exception {
assertThat(sequence().isEmpty(), is(true));
assertThat(sequence(1).isEmpty(), is(false));
}
@Test
public void supportsToString() throws Exception {
assertThat(sequence(1, 2, 3).toString(), is("1,2,3"));
assertThat(sequence(1, 2, 3).toString(":"), is("1:2:3"));
assertThat(sequence(1, 2, 3).toString("(", ", ", ")"), is("(1, 2, 3)"));
}
@Test
public void toStringOnlyShowsFirstHundredElementsSoItWorksWithInfiniteLists() throws Exception {
assertThat(range(1).toString(), is(range(1, 100).toString()));
}
@Test
public void shouldNotIterateMultipleTimesWhenCallingToString() throws Exception {
final AtomicInteger count = new AtomicInteger(0);
sequence("foo").map(string -> {
count.incrementAndGet();
return string;
}).toString();
assertThat(count.get(), is(1));
}
@Test
public void canReduceEmptySequence() {
assertThat(numbers().reduce(sum()), NumberMatcher.is(0));
}
@Test
public void supportsReduceLeft() throws Exception {
assertThat(numbers(1, 2, 3).reduce(sum()), NumberMatcher.is(6));
assertThat(numbers(1, 2, 3).reduceLeft(sum()), NumberMatcher.is(6));
assertThat(sequence("1", "2", "3").reduce(join), is("123"));
assertThat(sequence("1", "2", "3").reduceLeft(join), is("123"));
}
@Test
public void supportsFoldToACount() throws Exception {
assertThat(sequence("Dan", "Matt", "Bob").fold(0, count()), NumberMatcher.is(3));
assertThat(sequence("Dan", "Matt").fold(0, count()), NumberMatcher.is(2));
assertThat(sequence("Dan").fold(0, count()), NumberMatcher.is(1));
assertThat(empty().fold(0, count()), NumberMatcher.is(0));
}
@Test
public void supportsFoldLeft() throws Exception {
assertThat(sequence(1, 2, 3).fold(0, sum()), NumberMatcher.is(6));
assertThat(sequence(1, 2, 3).foldLeft(0, sum()), NumberMatcher.is(6));
assertThat(sequence("1", "2", "3").fold("0", join), is("0123"));
assertThat(sequence("1", "2", "3").foldLeft("0", join), is("0123"));
}
@Test
public void supportsScanLeft() throws Exception {
assertThat(numbers().scanLeft(0, sum()), is(numbers(0)));
assertThat(numbers(1).scanLeft(0, sum()), is(numbers(0, 1)));
assertThat(numbers(1, 2).scanLeft(0, sum()), is(numbers(0, 1, 3)));
assertThat(numbers(1, 2, 3).scanLeft(0, sum()), is(numbers(0, 1, 3, 6)));
}
static class EachSupport {
static void littleVoid(int value) {
}
static Void bigVoid(int value) {
return null;
}
static String ignoreResult(int value){
return null;
}
}
@Test
public void eachWorksWithAllReturnTypes() throws Exception {
sequence(1,2,3).each(printLine(new StringPrintStream(), "%s"));
sequence(1,2,3).each(Functions.<Integer>identity());
sequence(1,2,3).each(EachSupport::littleVoid);
sequence(1,2,3).each(EachSupport::littleVoid);
sequence(1,2,3).each(EachSupport::bigVoid);
sequence(1,2,3).each(EachSupport::ignoreResult);
sequence(1,2,3).each((value) -> EachSupport.littleVoid(value));
sequence(1,2,3).each((value) -> EachSupport.bigVoid(value));
sequence(1,2,3).each((value) -> EachSupport.ignoreResult(value));
sequence(1,2,3).each(i -> {});
sequence(1,2,3).each(i -> null);
sequence(1,2,3).each(i -> "");
}
@Test
public void supportsEach() throws Exception {
final int[] sum = {0};
sequence(1, 2).each(value -> sum[0] += value);
assertThat(sum[0], is(3));
}
@Test
public void supportsEachConcurrently() throws Exception {
final AtomicInteger sum = new AtomicInteger();
sequence(1, 2).eachConcurrently(sum::addAndGet);
assertThat(sum.intValue(), is(3));
}
@Test
public void supportsTap() throws Exception {
final int[] sum = {0};
Sequence<Integer> result = sequence(1, 2).tap(value -> sum[0] += value).realise();
assertThat(result, hasExactly(1, 2));
assertThat(sum[0], is(3));
}
@Test
public void supportsMap() throws Exception {
Sequence<String> strings = sequence(1, 2).map(toString);
assertThat(strings, hasExactly("1", "2"));
}
@Test
public void supportsConcurrentMap() throws Exception {
Iterable<String> strings = sequence(1, 2).mapConcurrently(toString);
assertThat(strings, hasExactly("1", "2"));
}
@Test
public void supportsConcurrentMapWithCustomExecutor() throws Exception {
ExecutorService executorService = NamedExecutors.newCachedThreadPool(getClass());
Iterable<String> strings = sequence(1, 2).mapConcurrently(toString, executorService);
assertThat(strings, hasExactly("1", "2"));
executorService.shutdown();
}
@Test
public void mapIsLazy() throws Exception {
Iterable<Integer> result = sequence(returns(1), callThrows(new Exception(), Integer.class)).
map(call(Integer.class));
assertThat(result, startsWith(1));
}
@Test
public void supportsFilter() throws Exception {
Sequence<Integer> result = sequence(1, 2, 3, 4).filter(even());
assertThat(result, hasExactly(2, 4));
}
@Test
public void supportsReject() throws Exception {
Sequence<Integer> result = sequence(1, 2, 3, 4).reject(even());
assertThat(result, hasExactly(1, 3));
}
@Test
public void filterIsLazy() throws Exception {
Iterable<Integer> result = sequence(returns(1), returns(2), callThrows(new Exception(), Integer.class)).
map(call(Integer.class)).
filter(even());
assertThat(result, startsWith(2));
}
@Test
public void supportsFlatMap() throws Exception {
Sequence<Character> characters = sequence("Hello").flatMap(toCharacters());
assertThat(characters, hasExactly('H', 'e', 'l', 'l', 'o'));
}
@Test
public void supportsCollect() throws Exception {
assertThat(sequence("1", 2, 3.0, 'F').collect(
Predicates.is("1"), one -> 4,
Predicates.is(2), two -> 3,
Predicates.is(3.0), three -> 2,
Predicates.is('F'), f -> 1
), hasExactly(4, 3, 2, 1));
assertThat(sequence("1", 2, 3.0, 'F').collect(
Functions.instanceOf(String.class, Double::parseDouble),
Functions.instanceOf(Integer.class, Object::toString),
Functions.instanceOf(Double.class, Double::intValue),
Functions.option(Predicates.is('F'), f -> 4)
), hasExactly(1.0, "2", 3, 4));
}
@Test
public void supportsConcurrentFlatMap() throws Exception {
Sequence<Character> characters = sequence("Hello").flatMapConcurrently(toCharacters());
assertThat(characters, hasExactly('H', 'e', 'l', 'l', 'o'));
}
@Test
public void supportsConcurrentFlatMapWithCustomExecutor() throws Exception {
ExecutorService executorService = NamedExecutors.newCachedThreadPool(getClass());
Sequence<Character> characters = sequence("Hello").flatMapConcurrently(toCharacters(), executorService);
assertThat(characters, hasExactly('H', 'e', 'l', 'l', 'o'));
executorService.shutdown();
}
@Test
public void supportsFlatten() throws Exception {
assertThat(flatten(sequence("Hello").map(toCharacters())), hasExactly('H', 'e', 'l', 'l', 'o'));
assertThat(flatten(sequence(some(1), none(), some(3))), hasExactly(1, 3));
}
@Test
public void supportsTake() throws Exception {
final Sequence<Integer> sequence = sequence(1, 2, 3).take(2);
assertThat(sequence, hasExactly(1, 2));
assertThat(sequence(1).take(2).size(), NumberMatcher.is(1));
assertThat(sequence().take(2).size(), NumberMatcher.is(0));
}
@Test
public void takeIteratorDoesNotAllowCallingNext() throws Exception {
final Iterator<Integer> sequence = sequence(1, 2, 3).take(1).iterator();
assertThat(sequence.next(), NumberMatcher.is(1));
try{
assertThat(sequence.next(), not(NumberMatcher.is(2)));
fail("Expected exception");
} catch(NoSuchElementException e){
// As expected
}
}
@Test
public void supportsTakeDoesNotConsumeMoreThanItNeeds() throws Exception {
final Sequence<Object> sequence = repeat(() -> {throw new IllegalStateException();}).take(0);
assertThat(sequence.isEmpty(), is(true));
assertThat(sequence.size(), is(0));
}
@Test
public void supportsTakeWhile() throws Exception {
final Sequence<Integer> sequence = sequence(1, 3, 5, 6, 8, 1, 3).takeWhile(odd());
assertThat(sequence, hasExactly(1, 3, 5));
assertThat(sequence(1).takeWhile(odd()).size(), NumberMatcher.is(1));
assertThat(Sequences.<Number>sequence().takeWhile(odd()).size(), NumberMatcher.is(0));
}
@Test
public void supportsDrop() throws Exception {
final Sequence<Integer> sequence = sequence(1, 2, 3).drop(2);
assertThat(sequence, hasExactly(3));
assertThat(sequence(1).drop(2).size(), NumberMatcher.is(0));
assertThat(sequence().drop(1).size(), NumberMatcher.is(0));
}
@Test
public void supportsDropWhile() throws Exception {
final Sequence<Integer> sequence = sequence(1, 3, 5, 6, 8, 1, 3).dropWhile(odd());
assertThat(sequence, hasExactly(6, 8, 1, 3));
assertThat(sequence(1).dropWhile(odd()).size(), NumberMatcher.is(0));
assertThat(Sequences.<Number>sequence().dropWhile(odd()).size(), NumberMatcher.is(0));
}
@Test
public void supportsZip() {
final Sequence<Integer> sequence = sequence(1, 3, 5);
assertThat(sequence.zip(sequence(2, 4, 6, 8)), hasExactly(pair(1, 2), pair(3, 4), pair(5, 6)));
assertThat(sequence.zip(sequence(2, 4, 6)), hasExactly(pair(1, 2), pair(3, 4), pair(5, 6)));
assertThat(sequence.zip(sequence(2, 4)), hasExactly(pair(1, 2), pair(3, 4)));
}
@Test
public void supportsZipToTriple() {
assertThat(zip(sequence(1, 3, 5), sequence(2, 4, 6, 8), sequence("car", "cat")), hasExactly(triple(1, 2, "car"), triple(3, 4, "cat")));
assertThat(sequence(1, 3, 5).zip(sequence(2, 4, 6, 8), sequence("car", "cat")), hasExactly(triple(1, 2, "car"), triple(3, 4, "cat")));
}
@Test
public void supportsZipToQuadruple() {
assertThat(zip(sequence(1, 3, 5), sequence(2, 4, 6, 8), sequence("car", "cat"), sequence('C')), hasExactly(quadruple(1, 2, "car", 'C')));
assertThat(sequence(1, 3, 5).zip(sequence(2, 4, 6, 8), sequence("car", "cat"), sequence('C')), hasExactly(quadruple(1, 2, "car", 'C')));
}
@Test
public void supportsZipToQuintuple() {
assertThat(zip(sequence(1, 3, 5), sequence(2, 4, 6, 8), sequence("car", "cat"), sequence('C'), sequence('D')), hasExactly(quintuple(1, 2, "car", 'C', 'D')));
assertThat(sequence(1, 3, 5).zip(sequence(2, 4, 6, 8), sequence("car", "cat"), sequence('C'), sequence('D')), hasExactly(quintuple(1, 2, "car", 'C', 'D')));
}
@Test
public void supportsZipWithIndex() {
assertThat(sequence("Dan", "Matt", "Bob").zipWithIndex(), hasExactly(pair((Number) 0, "Dan"), pair((Number) 1, "Matt"), pair((Number) 2, "Bob")));
}
@Test
public void supportsForwardOnly() throws Exception {
Sequence<Integer> sequence = sequence(1, 2, 3, 4).forwardOnly();
assertThat(sequence.headOption(), is(option(1)));
assertThat(sequence.headOption(), is(option(2)));
}
@Test
public void supportsInterruption() throws Exception {
final int[] count = new int[]{0};
Sequence<Integer> interruptable = repeat(() -> {
if (++count[0] == 5) {
currentThread().interrupt();
}
return count[0];
}).interruptable();
try {
interruptable.realise();
} catch (LazyException e) {
assertThat(e.getCause(), instanceOf(InterruptedException.class));
assertThat(count[0], is(5));
}
}
@Test
public void supportsSortingByOtherIterableOrder() throws Exception {
assertThat(sequence('D', 'E', 'F').sortBy(indexIn(list('F', 'E', 'D'))), hasExactly('F', 'E', 'D'));
assertThat(sequence(pair("Dan", 'D'), pair("Ray", 'R'), pair("Tom", 'T')).sortBy(second(Character.class).then(indexIn(list('T', 'R', 'D')))),
hasExactly(pair("Tom", 'T'), pair("Ray", 'R'), pair("Dan", 'D')));
}
@Test
public void supportsWindowed() throws Exception {
assertThat(sequence(1, 2, 3, 4, 5).windowed(3), is(sequence(sequence(1, 2, 3), sequence(2, 3, 4), sequence(3, 4, 5))));
}
@Test
public void windowedIsLazyAndDoesNotBlowStack() throws Exception {
assertThat(range(1).windowed(3), startsWith(sequence(numbers(1, 2, 3), numbers(2, 3, 4), numbers(3, 4, 5))));
}
@Test
public void supportsWindowedWithStep() throws Exception {
assertThat(range(1).windowed(2, 3), startsWith(sequence(numbers(1, 2, 3), numbers(3, 4, 5), numbers(5, 6, 7))));
}
@Test
public void supportsWindowedWithStepAndImplicitSkip() throws Exception {
assertThat(range(1).windowed(4, 3), startsWith(sequence(numbers(1, 2, 3), numbers(5, 6, 7), numbers(9, 10, 11))));
}
@Test
public void supportsIntersperse() {
assertThat(sequence("a", "b", "c").intersperse("x"), hasExactly("a", "x", "b", "x", "c"));
assertThat(sequence("a").intersperse("x"), hasExactly("a"));
assertThat(sequence().intersperse("x"), isEmpty());
assertThat(repeat(1).intersperse(0).take(5), hasExactly(1, 0, 1, 0, 1));
assertThat(repeat(1).intersperse(0).take(6), hasExactly(1, 0, 1, 0, 1, 0));
}
@Test
public void supportsFlatteningToOption() {
assertThat(sequence("roger", "ramjet").flatOption(), is(some(sequence("roger", "ramjet"))));
assertThat(flatOption(sequence("roger", "ramjet")), is(some(sequence("roger", "ramjet"))));
assertThat(empty(String.class).flatOption(), is(Option.<Sequence<String>>none()));
assertThat(flatOption(empty(String.class)), is(Option.<Sequence<String>>none()));
}
@Test
public void logicalAndOfEmptyListIsTrue() throws Exception {
assertThat(empty(Boolean.class).reduce(and), is(true));
}
@Test
public void logicalOrOfEmptyListIsFalse() throws Exception {
assertThat(empty(Boolean.class).reduce(or), is(false));
}
@Test
public void logicalXorOfEmptyListIsFalse() throws Exception {
assertThat(empty(Boolean.class).reduce(xor), is(false));
}
@Test
public void supportsIndexAccess() {
assertThat(sequence("a", "b", "c").get(1), is("b"));
assertThat(sequence("a", "b", "c").indexOf("c"), is(2));
}
}