package org.codefx.libfx.collection.tree.stream;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.NoSuchElementException;
import java.util.Optional;
import org.codefx.libfx.collection.tree.stream.TreeIterationStrategy;
import org.codefx.libfx.collection.tree.stream.TreeIterator;
import org.junit.Before;
import org.junit.Test;
/**
* Tests {@link TreeIterator}.
*/
public class TreeIteratorTest {
private TreeIterationStrategy<String> strategy;
private TreeIterator<String> treeIterator;
@Before
@SuppressWarnings({ "unchecked", "javadoc" })
public void setUp() {
strategy = mock(TreeIterationStrategy.class);
treeIterator = new TreeIterator<>(strategy);
}
// create
@Test(expected = NullPointerException.class)
@SuppressWarnings("javadoc")
public void create_nullStrategy_throwsNullPointerExeption() throws Exception {
@SuppressWarnings("unused")
TreeIterator<?> treeIterator = new TreeIterator<>(null);
}
// has next
@Test
@SuppressWarnings("javadoc")
public void hasNext_strategyReturnsEmptyOptional_returnsFalse() throws Exception {
when(strategy.goToNextNode()).thenReturn(Optional.empty());
boolean hasNext = treeIterator.hasNext();
assertFalse(hasNext);
}
@Test
@SuppressWarnings("javadoc")
public void hasNext_strategyReturnsNonEmptyOptional_returnsTrue() throws Exception {
when(strategy.goToNextNode()).thenReturn(Optional.of("A"));
boolean hasNext = treeIterator.hasNext();
assertTrue(hasNext);
}
// next
@Test(expected = NoSuchElementException.class)
@SuppressWarnings("javadoc")
public void next_strategyReturnsEmptyOptional_throwsNoSuchElementException() throws Exception {
when(strategy.goToNextNode()).thenReturn(Optional.empty());
treeIterator.next();
}
@Test
@SuppressWarnings("javadoc")
public void next_strategyReturnsNonEmptyOptional_returnsThatElement() throws Exception {
String element = "element";
when(strategy.goToNextNode()).thenReturn(Optional.of(element));
String nextElement = treeIterator.next();
assertSame(element, nextElement);
}
// calls to strategy
@Test
@SuppressWarnings("javadoc")
public void create_noCallsToGoToNext() throws Exception {
verifyZeroInteractions(strategy);
}
@Test
@SuppressWarnings("javadoc")
public void hasNext_manyCallsToExhaustedStrategy_callsGoToNextOnlyOnce() throws Exception {
// strategy is "exhausted" so it always returns 'empty'
when(strategy.goToNextNode()).thenReturn(Optional.empty());
treeIterator.hasNext();
treeIterator.hasNext();
treeIterator.hasNext();
verify(strategy, times(1)).goToNextNode();
}
@Test
@SuppressWarnings("javadoc")
public void hasNext_manyCallsToNonExhaustedStrategy_callsGoToNextOnlyOnce() throws Exception {
// strategy is not "exhausted" so it returns non-empty Optionals
when(strategy.goToNextNode()).thenReturn(Optional.of("A"));
treeIterator.hasNext();
treeIterator.hasNext();
treeIterator.hasNext();
verify(strategy, times(1)).goToNextNode();
}
@Test
@SuppressWarnings("javadoc")
public void hasNextThenNext_callsGoToNextOnlyOnce() throws Exception {
when(strategy.goToNextNode()).thenReturn(Optional.of("A"));
treeIterator.hasNext();
treeIterator.hasNext();
treeIterator.next();
verify(strategy).goToNextNode();
}
@Test
@SuppressWarnings("javadoc")
public void next_manyCalls_callsGoToNextExactlyAsOften() throws Exception {
when(strategy.goToNextNode()).thenReturn(Optional.of("A"));
treeIterator.next();
treeIterator.next();
treeIterator.next();
verify(strategy, times(3)).goToNextNode();
}
@Test
@SuppressWarnings("javadoc")
public void hasNextThenNext_manyCalls_callsGoToNextCorrectly() throws Exception {
when(strategy.goToNextNode()).thenReturn(Optional.of("A"));
verify(strategy, times(0)).goToNextNode();
treeIterator.next(); // must move forward so calls 'goToNext'
verify(strategy, times(1)).goToNextNode();
treeIterator.hasNext(); // must move forward so calls 'goToNext'
verify(strategy, times(2)).goToNextNode();
treeIterator.hasNext(); // no additional information required so no more calls
treeIterator.hasNext();
treeIterator.hasNext();
verify(strategy, times(2)).goToNextNode();
treeIterator.next(); // no additional information required so no more calls
verify(strategy, times(2)).goToNextNode();
}
}