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