package com.googlecode.totallylazy.transducers;
import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.predicates.Predicate;
import org.junit.Test;
import java.util.List;
import java.util.NoSuchElementException;
import static com.googlecode.totallylazy.Assert.assertThat;
import static com.googlecode.totallylazy.Lists.list;
import static com.googlecode.totallylazy.Sequences.repeat;
import static com.googlecode.totallylazy.Sequences.sequence;
import static com.googlecode.totallylazy.Unchecked.cast;
import static com.googlecode.totallylazy.numbers.Numbers.average;
import static com.googlecode.totallylazy.numbers.Numbers.range;
import static com.googlecode.totallylazy.predicates.Predicates.instanceOf;
import static com.googlecode.totallylazy.predicates.Predicates.is;
import static com.googlecode.totallylazy.predicates.Predicates.nullValue;
import static com.googlecode.totallylazy.predicates.Predicates.sameInstance;
import static com.googlecode.totallylazy.transducers.Sender.sender;
import static com.googlecode.totallylazy.transducers.Transducers.filter;
public class SenderTest {
@Test
public void canReceiveItems() throws Exception {
assertReceived(sender(1, 2, 3), 1, 2, 3);
}
@Test
public void supportsFiltering() throws Exception {
assertReceived(sender(1, 2, 3, 4).filter(i -> i % 2 == 0), 2, 4);
}
@Test
public void supportsFind() throws Exception {
assertReceived(sender(1, 2, 3, 4).find(i -> i % 2 == 0), 2);
}
@Test
public void supportsMapping() throws Exception {
assertReceived(sender(1, 2, 3).map(Object::toString), "1", "2", "3");
}
@Test
public void supportsFlatMapping() throws Exception {
assertReceived(sender(1, 2, 3).flatMap((Integer i) -> sender(i, i * 2)), 1, 2, 2, 4, 3, 6);
}
@Test
public void flatMappingTerminatesEarly() throws Exception {
assertReceived(sender(range(1)).flatMap((Number i) -> sender(i, i.intValue() * 2)).take(6), 1, 2, 2, 4, 3, 6);
}
@Test
public void supportsScan() throws Exception {
assertReceived(sender(0, 2, 4).scan(average).map(Number::intValue), 0, 1, 2);
}
@Test
public void supportsFirst() throws Exception {
assertReceived(sender(0, 2, 4).first(), 0);
}
@Test
public void firstThrowsErrorWhenNoElement() throws Exception {
assertErrors(sender().first(), instanceOf(NoSuchElementException.class));
}
@Test
public void supportsFirstOption() throws Exception {
assertReceived(sender(0, 2, 4).firstOption(), Option.some(0));
assertReceived(sender().firstOption(), Option.none());
}
@Test
public void supportsLast() throws Exception {
assertReceived(sender(0, 2, 4).last(), 4);
}
@Test
public void lastThrowsErrorWhenNoElement() throws Exception {
assertErrors(sender().last(), instanceOf(NoSuchElementException.class));
}
@Test
public void supportsLastOption() throws Exception {
assertReceived(sender(0, 2, 4).lastOption(), Option.some(4));
assertReceived(sender().lastOption(), Option.none());
}
@Test
public void supportsReduce() throws Exception {
assertReceived(sender(0, 2, 4).reduce(average).map(Number::intValue),
2);
}
@Test
public void supportsTake() throws Exception {
assertReceived(sender(1, 2, 3, 4, 5, 6).take(0));
assertReceived(sender(1, 2, 3, 4, 5, 6).take(1), 1);
assertReceived(sender(1, 2, 3, 4, 5, 6).take(3), 1, 2, 3);
assertReceived(sender(1, 2, 3, 4, 5, 6).take(6), 1, 2, 3, 4, 5, 6);
}
@Test
public void takeTerminatesEarly() throws Exception {
assertReceived(sender(repeat(() -> {
throw new NoSuchElementException();
})).take(0));
}
@Test
public void supportsTakeWhile() throws Exception {
assertReceived(sender(1, 2, 3, 4, 5, 6).takeWhile(i -> i < 4),
1, 2, 3);
}
@Test
public void supportsDrop() throws Exception {
assertReceived(sender(1, 2, 3, 4, 5, 6).drop(3),
4, 5, 6);
}
@Test
public void supportsDropWhile() throws Exception {
assertReceived(sender(1, 2, 3, 4, 5, 6).dropWhile(i -> i < 4),
4, 5, 6);
}
@Test
public void supportsGroupBy() throws Exception {
Sender<List<Integer>> sender = sender(1, 2, 3, 4, 5, 6, 7, 8, 9).
groupBy(i -> i % 2).
flatMap(Sender::toList);
assertReceived(sender,
list(2, 4, 6, 8), list(1, 3, 5, 7, 9));
}
@Test
public void supportsToList() throws Exception {
assertReceived(sender(1, 2, 3, 4).toList(), list(1, 2, 3, 4));
}
@Test
public void supportsToSequence() throws Exception {
assertReceived(sender(1, 2, 3, 4).toSequence(), sequence(1, 2, 3, 4));
}
@Test
public void supportsTransducers() throws Exception {
assertReceived(sender(1, 2, 3, 4).transduce(filter((Integer x) -> x % 2 == 0).map(x -> x * 2)), 4, 8);
}
@SafeVarargs
private final <T> void assertReceived(Sender<T> sender, T... values) {
CapturingReceiver<T> receiver = new CapturingReceiver<>();
sender.send(receiver);
assertThat(receiver.items(), is(sequence(values)));
assertThat(receiver.error(), nullValue());
assertThat(receiver.started(), is(true));
assertThat(receiver.finished(), is(true));
}
private final <T> void assertErrors(Sender<T> sender, Predicate<? super Throwable> throwable) {
CapturingReceiver<T> receiver = new CapturingReceiver<>();
sender.send(receiver);
assertThat(receiver.items().isEmpty(), is(true));
assertThat(receiver.error(), throwable);
assertThat(receiver.started(), is(true));
assertThat(receiver.finished(), is(true));
}
@Test
public void canDecomposeTransducers() throws Exception {
Sender<Integer> original = sender(1, 2, 3, 4, 5, 6, 7, 8, 9);
Sender<List<Integer>> composed = original.
groupBy(i -> i % 2).
flatMap(Sender::toList).
last();
CompositeSender<Integer,List<Integer>> compositeSender = cast(composed);
assertThat(compositeSender.sender(), sameInstance(original));
List<Transducer<?, ?>> transducers = compositeSender.transducers();
assertThat(transducers.size(), is(4));
assertThat(transducers.get(0), instanceOf(GroupByTransducer.class));
assertThat(transducers.get(1), instanceOf(FlatMapTransducer.class));
assertThat(transducers.get(2), instanceOf(LastOptionTransducer.class));
assertThat(transducers.get(3), instanceOf(MapTransducer.class));
}
}