package net.emaze.dysfunctional.filtering;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import net.emaze.dysfunctional.dispatching.logic.Always;
import net.emaze.dysfunctional.dispatching.logic.Never;
import net.emaze.dysfunctional.iterations.ConstantIterator;
import org.junit.Assert;
import org.junit.Test;

/**
 *
 * @author rferranti
 */
public class FilteringIteratorTest {

    @Test(expected = IllegalArgumentException.class)
    public void creatingFilteringIteratorWithNullIteratorYieldsException() {
        new FilteringIterator<Object>(null, new Always<Object>());
    }

    @Test(expected = IllegalArgumentException.class)
    public void creatingFilteringIteratorWithNullPredicateYieldsException() {
        new FilteringIterator<Object>(new ConstantIterator<Object>("a"), null);
    }

    @Test(expected = NoSuchElementException.class)
    public void callingNextOnEmptyIteratorYieldsException() {
        List<Integer> bucket = Collections.<Integer>emptyList();
        Iterator<Integer> iter = new FilteringIterator<Integer>(bucket.iterator(), new Always<Integer>());
        iter.next();
    }

    @Test(expected = NoSuchElementException.class)
    public void callingNextOnNeverMatchingIteratorYieldsException() {
        List<Integer> bucket = Arrays.asList(1, 2, 3);
        Iterator<Integer> iter = new FilteringIterator<Integer>(bucket.iterator(), new Never<Integer>());
        iter.next();
    }

    @Test
    public void callingHasNextDoesNotConsumeValues() {
        List<Integer> bucket = Arrays.asList(1);
        Iterator<Integer> iter = new FilteringIterator<Integer>(bucket.iterator(), new Always<Integer>());
        iter.hasNext();
        iter.hasNext();
        Assert.assertEquals(Integer.valueOf(1), iter.next());
    }

    @Test
    public void emptyIteratorHasNoNext() {
        List<Integer> bucket = Collections.emptyList();
        Iterator<Integer> iter = new FilteringIterator<Integer>(bucket.iterator(), new Always<Integer>());
        Assert.assertFalse(iter.hasNext());
    }

    @Test
    public void whenPredicateEvaluatesToFalseElementsAreFilteredOut() {
        List<Integer> bucket = Collections.singletonList(1);
        Iterator<Integer> iter = new FilteringIterator<Integer>(bucket.iterator(), new Never<Integer>());
        Assert.assertFalse(iter.hasNext());
    }

    @Test
    public void canCallNextMultipleTimesWithoutCallingHasNext() {
        List<Integer> bucket = Arrays.asList(1, 2);
        Iterator<Integer> iter = new FilteringIterator<Integer>(bucket.iterator(), new Always<Integer>());
        List<Integer> got = new ArrayList<Integer>();
        got.add(iter.next());
        got.add(iter.next());
        Assert.assertEquals(bucket, got);
    }

    @Test
    public void canRemoveFromFilteringIterator() {
        List<Integer> bucket = new ArrayList<Integer>();
        bucket.add(1);
        bucket.add(2);

        Iterator<Integer> iter = new FilteringIterator<Integer>(bucket.iterator(), new Always<Integer>());
        iter.next();
        iter.remove();

        Assert.assertEquals(Arrays.asList(2), bucket);
    }
}

@@ -324,16 +324,76 @@
 .Never;%0A
+import net.emaze.dysfunctional.dispatching.logic.Predicate;%0A
 import n
@@ -3288,11 +3288,621 @@
 );%0A    %7D
+%0A%0A    @Test%0A    public void filterIsAppliedOncePerElement() %7B%0A        List%3CInteger%3E bucket = Arrays.asList(1, 2);%0A        SpyPredicate%3CInteger%3E spy = new SpyPredicate%3CInteger%3E();%0A        Iterator%3CInteger%3E iter = new FilteringIterator%3CInteger%3E(bucket.iterator(), spy);%0A        iter.hasNext();%0A        iter.hasNext();%0A        iter.next();%0A        Assert.assertEquals(1, spy.calls);%0A    %7D%0A%0A    private static class SpyPredicate%3CT%3E implements Predicate%3CT%3E %7B%0A    %0A        private int calls = 0;%0A%0A        @Override%0A        public boolean accept(T elem) %7B%0A            calls++;%0A            return true;%0A        %7D%0A    %7D
 %0A%7D%0A

test coverage