View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.iterators;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Collections;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.NoSuchElementException;
30  
31  import org.junit.jupiter.api.BeforeEach;
32  import org.junit.jupiter.api.Test;
33  
34  /**
35   * A unit test to test the basic functions of {@link SkippingIterator}.
36   *
37   * @param <E> the type of elements tested by this iterator.
38   */
39  public class SkippingIteratorTest<E> extends AbstractIteratorTest<E> {
40  
41      /** Test array of size 7 */
42      private final String[] testArray = {
43          "a", "b", "c", "d", "e", "f", "g"
44      };
45  
46      private List<E> testList;
47  
48      @Override
49      public Iterator<E> makeEmptyIterator() {
50          return new SkippingIterator<>(Collections.<E>emptyList().iterator(), 0);
51      }
52  
53      @Override
54      public Iterator<E> makeObject() {
55          return new SkippingIterator<>(new ArrayList<>(testList).iterator(), 1);
56      }
57  
58      @SuppressWarnings("unchecked")
59      @BeforeEach
60      public void setUp()
61          throws Exception {
62          testList = Arrays.asList((E[]) testArray);
63      }
64  
65      /**
66       * Test the case if a negative {@code offset} is passed to the
67       * constructor. {@link IllegalArgumentException} is expected.
68       */
69      @Test
70      public void testNegativeOffset() {
71          assertThrows(IllegalArgumentException.class, () -> new SkippingIterator<>(testList.iterator(), -1),
72                  "Expected IllegalArgumentException.");
73      }
74  
75      /**
76       * Test the case if the {@code offset} passed to the constructor is
77       * greater than the decorated iterator's size. The SkippingIterator should
78       * behave as if there are no more elements to return.
79       */
80      @Test
81      public void testOffsetGreaterThanSize() {
82          final Iterator<E> iter = new SkippingIterator<>(testList.iterator(), 10);
83          assertFalse(iter.hasNext());
84  
85          assertThrows(NoSuchElementException.class, () -> iter.next(),
86                  "Expected NoSuchElementException.");
87      }
88  
89      /**
90       * Test the {@code remove()} method being called twice without calling
91       * {@code next()} in between.
92       */
93      @Test
94      public void testRemoveCalledTwice() {
95          final List<E> testListCopy = new ArrayList<>(testList);
96          final Iterator<E> iter = new SkippingIterator<>(testListCopy.iterator(), 1);
97  
98          assertTrue(iter.hasNext());
99          assertEquals("b", iter.next());
100         iter.remove();
101 
102         assertThrows(IllegalStateException.class, () -> iter.remove(),
103                 "Expected IllegalStateException.");
104     }
105 
106     /**
107      * Test removing the first element. Verify that the element is removed from
108      * the underlying collection.
109      */
110     @Test
111     public void testRemoveFirst() {
112         final List<E> testListCopy = new ArrayList<>(testList);
113         final Iterator<E> iter = new SkippingIterator<>(testListCopy.iterator(), 4);
114 
115         assertTrue(iter.hasNext());
116         assertEquals("e", iter.next());
117 
118         iter.remove();
119         assertFalse(testListCopy.contains("e"));
120 
121         assertTrue(iter.hasNext());
122         assertEquals("f", iter.next());
123         assertTrue(iter.hasNext());
124         assertEquals("g", iter.next());
125 
126         assertFalse(iter.hasNext());
127 
128         assertThrows(NoSuchElementException.class, () -> iter.next(),
129                 "Expected NoSuchElementException.");
130     }
131 
132     /**
133      * Test removing the last element. Verify that the element is removed from
134      * the underlying collection.
135      */
136     @Test
137     public void testRemoveLast() {
138         final List<E> testListCopy = new ArrayList<>(testList);
139         final Iterator<E> iter = new SkippingIterator<>(testListCopy.iterator(), 5);
140 
141         assertTrue(iter.hasNext());
142         assertEquals("f", iter.next());
143         assertTrue(iter.hasNext());
144         assertEquals("g", iter.next());
145 
146         assertFalse(iter.hasNext());
147 
148         assertThrows(NoSuchElementException.class, () -> iter.next(),
149                 "Expected NoSuchElementException.");
150 
151         iter.remove();
152         assertFalse(testListCopy.contains("g"));
153 
154         assertFalse(iter.hasNext());
155 
156         assertThrows(NoSuchElementException.class, () -> iter.next(),
157                 "Expected NoSuchElementException.");
158     }
159 
160     /**
161      * Test removing an element in the middle of the iterator. Verify that the
162      * element is removed from the underlying collection.
163      */
164     @Test
165     public void testRemoveMiddle() {
166         final List<E> testListCopy = new ArrayList<>(testList);
167         final Iterator<E> iter = new SkippingIterator<>(testListCopy.iterator(), 3);
168 
169         assertTrue(iter.hasNext());
170         assertEquals("d", iter.next());
171 
172         iter.remove();
173         assertFalse(testListCopy.contains("d"));
174 
175         assertTrue(iter.hasNext());
176         assertEquals("e", iter.next());
177         assertTrue(iter.hasNext());
178         assertEquals("f", iter.next());
179         assertTrue(iter.hasNext());
180         assertEquals("g", iter.next());
181 
182         assertFalse(iter.hasNext());
183 
184         assertThrows(NoSuchElementException.class, () -> iter.next(),
185                 "Expected NoSuchElementException.");
186     }
187 
188     /**
189      * Test the case if the decorated iterator does not support the
190      * {@code remove()} method and throws an {@link UnsupportedOperationException}.
191      */
192     @Test
193     public void testRemoveUnsupported() {
194         final Iterator<E> mockIterator = new AbstractIteratorDecorator<E>(testList.iterator()) {
195             @Override
196             public void remove() {
197                 throw new UnsupportedOperationException();
198             }
199         };
200 
201         final Iterator<E> iter = new SkippingIterator<>(mockIterator, 1);
202         assertTrue(iter.hasNext());
203         assertEquals("b", iter.next());
204 
205         assertThrows(UnsupportedOperationException.class, () -> iter.remove(),
206                 "Expected UnsupportedOperationException.");
207     }
208 
209     /**
210      * Test the {@code remove()} method being called without
211      * {@code next()} being called first.
212      */
213     @Test
214     public void testRemoveWithoutCallingNext() {
215         final List<E> testListCopy = new ArrayList<>(testList);
216         final Iterator<E> iter = new SkippingIterator<>(testListCopy.iterator(), 1);
217 
218         assertThrows(IllegalStateException.class, () -> iter.remove(),
219                 "Expected IllegalStateException.");
220     }
221 
222     /**
223      * Test a decorated iterator bounded such that the {@code offset} is
224      * zero, in that the SkippingIterator should return all the same elements
225      * as its decorated iterator.
226      */
227     @Test
228     public void testSameAsDecorated() {
229         final Iterator<E> iter = new SkippingIterator<>(testList.iterator(), 0);
230 
231         assertTrue(iter.hasNext());
232         assertEquals("a", iter.next());
233         assertTrue(iter.hasNext());
234         assertEquals("b", iter.next());
235         assertTrue(iter.hasNext());
236         assertEquals("c", iter.next());
237         assertTrue(iter.hasNext());
238         assertEquals("d", iter.next());
239         assertTrue(iter.hasNext());
240         assertEquals("e", iter.next());
241         assertTrue(iter.hasNext());
242         assertEquals("f", iter.next());
243         assertTrue(iter.hasNext());
244         assertEquals("g", iter.next());
245 
246         assertFalse(iter.hasNext());
247 
248         assertThrows(NoSuchElementException.class, () -> iter.next(),
249                 "Expected NoSuchElementException.");
250     }
251 
252     /**
253      * Test a decorated iterator bounded such that the first element returned is
254      * at an index greater its first element, and the last element returned is
255      * at an index less than its last element.
256      */
257     @Test
258     public void testSkipping() {
259         final Iterator<E> iter = new SkippingIterator<>(testList.iterator(), 2);
260 
261         assertTrue(iter.hasNext());
262         assertEquals("c", iter.next());
263         assertTrue(iter.hasNext());
264         assertEquals("d", iter.next());
265         assertTrue(iter.hasNext());
266         assertEquals("e", iter.next());
267         assertTrue(iter.hasNext());
268         assertEquals("f", iter.next());
269         assertTrue(iter.hasNext());
270         assertEquals("g", iter.next());
271 
272         assertFalse(iter.hasNext());
273 
274         assertThrows(NoSuchElementException.class, () -> iter.next(),
275                 "Expected NoSuchElementException.");
276     }
277 
278 }