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.assertNull;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collections;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.NoSuchElementException;
31  
32  import org.junit.jupiter.api.BeforeEach;
33  import org.junit.jupiter.api.Test;
34  
35  /**
36   * A unit test to test the basic functions of {@link BoundedIterator}.
37   *
38   * @param <E> the type of elements tested by this iterator.
39   */
40  public class BoundedIteratorTest<E> extends AbstractIteratorTest<E> {
41  
42      /** Test array of size 7 */
43      private final String[] testArray = {
44          "a", "b", "c", "d", "e", "f", "g"
45      };
46  
47      private List<E> testList;
48  
49      @Override
50      public Iterator<E> makeEmptyIterator() {
51          return new BoundedIterator<>(Collections.<E>emptyList().iterator(), 0, 10);
52      }
53  
54      @Override
55      public Iterator<E> makeObject() {
56          return new BoundedIterator<>(new ArrayList<>(testList).iterator(), 1, testList.size() - 1);
57      }
58  
59      @SuppressWarnings("unchecked")
60      @BeforeEach
61      public void setUp()
62          throws Exception {
63          testList = Arrays.asList((E[]) testArray);
64      }
65  
66      /**
67       * Test a decorated iterator bounded such that the first element returned is
68       * at an index greater its first element, and the last element returned is
69       * at an index less than its last element.
70       */
71      @Test
72      public void testBounded() {
73          final Iterator<E> iter = new BoundedIterator<>(testList.iterator(), 2, 4);
74  
75          assertTrue(iter.hasNext());
76          assertEquals("c", iter.next());
77          assertTrue(iter.hasNext());
78          assertEquals("d", iter.next());
79          assertTrue(iter.hasNext());
80          assertEquals("e", iter.next());
81          assertTrue(iter.hasNext());
82          assertEquals("f", iter.next());
83  
84          assertFalse(iter.hasNext());
85  
86          assertThrows(NoSuchElementException.class, () -> iter.next(),
87                  "Expected NoSuchElementException.");
88      }
89  
90      /**
91       * Test a decorated iterator bounded to a {@code max} of 0. The
92       * BoundedIterator should behave as if there are no more elements to return,
93       * since it is technically an empty iterator.
94       */
95      @Test
96      public void testEmptyBounded() {
97          final Iterator<E> iter = new BoundedIterator<>(testList.iterator(), 3, 0);
98          assertFalse(iter.hasNext());
99  
100         assertThrows(NoSuchElementException.class, () -> iter.next());
101     }
102 
103     /**
104      * Test the case if the {@code max} passed to the constructor is
105      * greater than the size of the decorated iterator. The last element
106      * returned should be the same as the last element of the decorated
107      * iterator.
108      */
109     @Test
110     public void testMaxGreaterThanSize() {
111         final Iterator<E> iter = new BoundedIterator<>(testList.iterator(), 1, 10);
112 
113         assertTrue(iter.hasNext());
114         assertEquals("b", iter.next());
115         assertTrue(iter.hasNext());
116         assertEquals("c", iter.next());
117         assertTrue(iter.hasNext());
118         assertEquals("d", iter.next());
119         assertTrue(iter.hasNext());
120         assertEquals("e", iter.next());
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     }
130 
131     /**
132      * Test the case if a negative {@code max} is passed to the
133      * constructor. {@link IllegalArgumentException} is expected.
134      */
135     @Test
136     public void testNegativeMax() {
137         final IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> new BoundedIterator<>(testList.iterator(), 3, -1));
138         assertEquals("Max parameter must not be negative.", thrown.getMessage());
139     }
140 
141     /**
142      * Test the case if a negative {@code offset} is passed to the
143      * constructor. {@link IllegalArgumentException} is expected.
144      */
145     @Test
146     public void testNegativeOffset() {
147         final IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> new BoundedIterator<>(testList.iterator(), -1, 4));
148         assertEquals("Offset parameter must not be negative.", thrown.getMessage());
149     }
150 
151     /**
152      * Test the case if the {@code offset} passed to the constructor is
153      * greater than the decorated iterator's size. The BoundedIterator should
154      * behave as if there are no more elements to return.
155      */
156     @Test
157     public void testOffsetGreaterThanSize() {
158         final Iterator<E> iter = new BoundedIterator<>(testList.iterator(), 10, 4);
159         assertFalse(iter.hasNext());
160 
161         assertThrows(NoSuchElementException.class, () -> iter.next());
162     }
163 
164     /**
165      * Test the {@code remove()} method being called twice without calling
166      * {@code next()} in between.
167      */
168     @Test
169     public void testRemoveCalledTwice() {
170         final List<E> testListCopy = new ArrayList<>(testList);
171         final Iterator<E> iter = new BoundedIterator<>(testListCopy.iterator(), 1, 5);
172 
173         assertTrue(iter.hasNext());
174         assertEquals("b", iter.next());
175         iter.remove();
176 
177         assertThrows(IllegalStateException.class, () -> iter.remove());
178     }
179 
180     /**
181      * Test removing the first element. Verify that the element is removed from
182      * the underlying collection.
183      */
184     @Test
185     public void testRemoveFirst() {
186         final List<E> testListCopy = new ArrayList<>(testList);
187         final Iterator<E> iter = new BoundedIterator<>(testListCopy.iterator(), 1, 5);
188 
189         assertTrue(iter.hasNext());
190         assertEquals("b", iter.next());
191 
192         iter.remove();
193         assertFalse(testListCopy.contains("b"));
194 
195         assertTrue(iter.hasNext());
196         assertEquals("c", iter.next());
197         assertTrue(iter.hasNext());
198         assertEquals("d", iter.next());
199         assertTrue(iter.hasNext());
200         assertEquals("e", iter.next());
201         assertTrue(iter.hasNext());
202         assertEquals("f", iter.next());
203 
204         assertFalse(iter.hasNext());
205 
206         assertThrows(NoSuchElementException.class, () -> iter.next());
207     }
208 
209     /**
210      * Test removing the last element. Verify that the element is removed from
211      * the underlying collection.
212      */
213     @Test
214     public void testRemoveLast() {
215         final List<E> testListCopy = new ArrayList<>(testList);
216         final Iterator<E> iter = new BoundedIterator<>(testListCopy.iterator(), 1, 5);
217 
218         assertTrue(iter.hasNext());
219         assertEquals("b", iter.next());
220         assertTrue(iter.hasNext());
221         assertEquals("c", iter.next());
222         assertTrue(iter.hasNext());
223         assertEquals("d", iter.next());
224         assertTrue(iter.hasNext());
225         assertEquals("e", iter.next());
226         assertTrue(iter.hasNext());
227         assertEquals("f", iter.next());
228 
229         assertFalse(iter.hasNext());
230 
231         final NoSuchElementException thrown = assertThrows(NoSuchElementException.class, () -> iter.next());
232         assertNull(thrown.getMessage());
233 
234         iter.remove();
235         assertFalse(testListCopy.contains("f"));
236 
237         assertFalse(iter.hasNext());
238 
239         final NoSuchElementException thrown1 = assertThrows(NoSuchElementException.class, () -> iter.next());
240         assertNull(thrown1.getMessage());
241     }
242 
243     /**
244      * Test removing an element in the middle of the iterator. Verify that the
245      * element is removed from the underlying collection.
246      */
247     @Test
248     public void testRemoveMiddle() {
249         final List<E> testListCopy = new ArrayList<>(testList);
250         final Iterator<E> iter = new BoundedIterator<>(testListCopy.iterator(), 1, 5);
251 
252         assertTrue(iter.hasNext());
253         assertEquals("b", iter.next());
254         assertTrue(iter.hasNext());
255         assertEquals("c", iter.next());
256         assertTrue(iter.hasNext());
257         assertEquals("d", iter.next());
258 
259         iter.remove();
260         assertFalse(testListCopy.contains("d"));
261 
262         assertTrue(iter.hasNext());
263         assertEquals("e", iter.next());
264         assertTrue(iter.hasNext());
265         assertEquals("f", iter.next());
266 
267         assertFalse(iter.hasNext());
268 
269         assertThrows(NoSuchElementException.class, () -> iter.next());
270     }
271 
272     /**
273      * Test the case if the decorated iterator does not support the
274      * {@code remove()} method and throws an {@link UnsupportedOperationException}.
275      */
276     @Test
277     public void testRemoveUnsupported() {
278         final Iterator<E> mockIterator = new AbstractIteratorDecorator<E>(testList.iterator()) {
279             @Override
280             public void remove() {
281                 throw new UnsupportedOperationException();
282             }
283         };
284 
285         final Iterator<E> iter = new BoundedIterator<>(mockIterator, 1, 5);
286         assertTrue(iter.hasNext());
287         assertEquals("b", iter.next());
288 
289         final UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class, () -> iter.remove());
290         assertNull(thrown.getMessage());
291 
292     }
293 
294     /**
295      * Test the {@code remove()} method being called without
296      * {@code next()} being called first.
297      */
298     @Test
299     public void testRemoveWithoutCallingNext() {
300         final List<E> testListCopy = new ArrayList<>(testList);
301         final Iterator<E> iter = new BoundedIterator<>(testListCopy.iterator(), 1, 5);
302 
303         final IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> iter.remove());
304         assertEquals("remove() cannot be called before calling next()", thrown.getMessage());
305     }
306 
307     /**
308      * Test a decorated iterator bounded such that the {@code offset} is
309      * zero and the {@code max} is its size, in that the BoundedIterator
310      * should return all the same elements as its decorated iterator.
311      */
312     @Test
313     public void testSameAsDecorated() {
314         final Iterator<E> iter = new BoundedIterator<>(testList.iterator(), 0,
315                                                   testList.size());
316 
317         assertTrue(iter.hasNext());
318         assertEquals("a", iter.next());
319         assertTrue(iter.hasNext());
320         assertEquals("b", iter.next());
321         assertTrue(iter.hasNext());
322         assertEquals("c", iter.next());
323         assertTrue(iter.hasNext());
324         assertEquals("d", iter.next());
325         assertTrue(iter.hasNext());
326         assertEquals("e", iter.next());
327         assertTrue(iter.hasNext());
328         assertEquals("f", iter.next());
329         assertTrue(iter.hasNext());
330         assertEquals("g", iter.next());
331 
332         assertFalse(iter.hasNext());
333 
334         assertThrows(NoSuchElementException.class, () -> iter.next());
335     }
336 
337 }