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.assertFalse;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  import static org.junit.jupiter.api.Assertions.fail;
24  
25  import java.util.Iterator;
26  import java.util.NoSuchElementException;
27  
28  import org.apache.commons.collections4.AbstractObjectTest;
29  import org.junit.jupiter.api.Test;
30  
31  /**
32   * Abstract class for testing the Iterator interface.
33   * <p>
34   * This class provides a framework for testing an implementation of Iterator.
35   * Concrete subclasses must provide the iterator to be tested.
36   * They must also specify certain details of how the iterator operates by
37   * overriding the supportsXxx() methods if necessary.
38   */
39  public abstract class AbstractIteratorTest<E> extends AbstractObjectTest {
40  
41      /**
42       * JUnit constructor.
43       *
44       * @param testName  the test class name
45       */
46      public AbstractIteratorTest(final String testName) {
47          super(testName);
48      }
49  
50      /**
51       * Implement this method to return an iterator over an empty collection.
52       *
53       * @return an empty iterator
54       */
55      public abstract Iterator<E> makeEmptyIterator();
56  
57      /**
58       * Implements the abstract superclass method to return the full iterator.
59       *
60       * @return a full iterator
61       */
62      @Override
63      public abstract Iterator<E> makeObject();
64  
65      /**
66       * Whether or not we are testing an iterator that can be empty.
67       * Default is true.
68       *
69       * @return true if Iterator can be empty
70       */
71      public boolean supportsEmptyIterator() {
72          return true;
73      }
74  
75      /**
76       * Whether or not we are testing an iterator that can contain elements.
77       * Default is true.
78       *
79       * @return true if Iterator can be full
80       */
81      public boolean supportsFullIterator() {
82          return true;
83      }
84  
85      /**
86       * Whether or not we are testing an iterator that supports remove().
87       * Default is true.
88       *
89       * @return true if Iterator supports remove
90       */
91      public boolean supportsRemove() {
92          return true;
93      }
94  
95      /**
96       * Test the empty iterator.
97       */
98      @Test
99      public void testEmptyIterator() {
100         if (!supportsEmptyIterator()) {
101             return;
102         }
103 
104         final Iterator<E> it = makeEmptyIterator();
105 
106         // hasNext() should return false
107         assertFalse(it.hasNext(), "hasNext() should return false for empty iterators");
108 
109         // next() should throw a NoSuchElementException
110         assertThrows(NoSuchElementException.class, () -> it.next(),
111                 "NoSuchElementException must be thrown when Iterator is exhausted");
112         verify();
113 
114         assertNotNull(it.toString());
115     }
116 
117     /**
118      * Test normal iteration behavior.
119      */
120     @Test
121     public void testFullIterator() {
122         if (!supportsFullIterator()) {
123             return;
124         }
125 
126         final Iterator<E> it = makeObject();
127 
128         // hasNext() must be true (ensure makeFullIterator is correct!)
129         assertTrue(it.hasNext(), "hasNext() should return true for at least one element");
130 
131         // next() must not throw exception (ensure makeFullIterator is correct!)
132         try {
133             it.next();
134         } catch (final NoSuchElementException e) {
135             fail("Full iterators must have at least one element");
136         }
137 
138         // iterate through
139         while (it.hasNext()) {
140             it.next();
141             verify();
142         }
143 
144         // next() must throw NoSuchElementException now
145         assertThrows(NoSuchElementException.class, () -> it.next(),
146                 "NoSuchElementException must be thrown when Iterator is exhausted");
147 
148         assertNotNull(it.toString());
149     }
150 
151     /**
152      * Test remove behavior.
153      */
154     @Test
155     public void testRemove() {
156         final Iterator<E> it = makeObject();
157 
158         if (!supportsRemove()) {
159             // check for UnsupportedOperationException if not supported
160             try {
161                 it.remove();
162             } catch (final UnsupportedOperationException ex) {}
163             return;
164         }
165 
166         // should throw IllegalStateException before next() called
167         assertThrows(IllegalStateException.class, () -> it.remove());
168         verify();
169 
170         // remove after next should be fine
171         it.next();
172         it.remove();
173 
174         // should throw IllegalStateException for second remove()
175         assertThrows(IllegalStateException.class, () -> it.remove());
176     }
177 
178     /**
179      * Allows subclasses to add complex cross verification
180      */
181     public void verify() {
182         // do nothing
183     }
184 
185 }