• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.base;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.annotations.GwtIncompatible;
21 import com.google.common.testing.GcFinalization;
22 import java.lang.ref.WeakReference;
23 import java.util.Iterator;
24 import java.util.NoSuchElementException;
25 import junit.framework.TestCase;
26 
27 /**
28  * Unit test for {@code AbstractIterator}.
29  *
30  * @author Kevin Bourrillion
31  */
32 @GwtCompatible(emulated = true)
33 public class AbstractIteratorTest extends TestCase {
34 
testDefaultBehaviorOfNextAndHasNext()35   public void testDefaultBehaviorOfNextAndHasNext() {
36 
37     // This sample AbstractIterator returns 0 on the first call, 1 on the
38     // second, then signals that it's reached the end of the data
39     Iterator<Integer> iter =
40         new AbstractIterator<Integer>() {
41           private int rep;
42 
43           @Override
44           public Integer computeNext() {
45             switch (rep++) {
46               case 0:
47                 return 0;
48               case 1:
49                 return 1;
50               case 2:
51                 return endOfData();
52               default:
53                 fail("Should not have been invoked again");
54                 return null;
55             }
56           }
57         };
58 
59     assertTrue(iter.hasNext());
60     assertEquals(0, (int) iter.next());
61 
62     // verify idempotence of hasNext()
63     assertTrue(iter.hasNext());
64     assertTrue(iter.hasNext());
65     assertTrue(iter.hasNext());
66     assertEquals(1, (int) iter.next());
67 
68     assertFalse(iter.hasNext());
69 
70     // Make sure computeNext() doesn't get invoked again
71     assertFalse(iter.hasNext());
72 
73     try {
74       iter.next();
75       fail("no exception thrown");
76     } catch (NoSuchElementException expected) {
77     }
78   }
79 
testSneakyThrow()80   public void testSneakyThrow() throws Exception {
81     Iterator<Integer> iter =
82         new AbstractIterator<Integer>() {
83           boolean haveBeenCalled;
84 
85           @Override
86           public Integer computeNext() {
87             if (haveBeenCalled) {
88               fail("Should not have been called again");
89             } else {
90               haveBeenCalled = true;
91               sneakyThrow(new SomeCheckedException());
92             }
93             return null; // never reached
94           }
95         };
96 
97     // The first time, the sneakily-thrown exception comes out
98     try {
99       iter.hasNext();
100       fail("No exception thrown");
101     } catch (Exception e) {
102       if (!(e instanceof SomeCheckedException)) {
103         throw e;
104       }
105     }
106 
107     // But the second time, AbstractIterator itself throws an ISE
108     try {
109       iter.hasNext();
110       fail("No exception thrown");
111     } catch (IllegalStateException expected) {
112     }
113   }
114 
testException()115   public void testException() {
116     final SomeUncheckedException exception = new SomeUncheckedException();
117     Iterator<Integer> iter =
118         new AbstractIterator<Integer>() {
119           @Override
120           public Integer computeNext() {
121             throw exception;
122           }
123         };
124 
125     // It should pass through untouched
126     try {
127       iter.hasNext();
128       fail("No exception thrown");
129     } catch (SomeUncheckedException e) {
130       assertSame(exception, e);
131     }
132   }
133 
testExceptionAfterEndOfData()134   public void testExceptionAfterEndOfData() {
135     Iterator<Integer> iter =
136         new AbstractIterator<Integer>() {
137           @Override
138           public Integer computeNext() {
139             endOfData();
140             throw new SomeUncheckedException();
141           }
142         };
143     try {
144       iter.hasNext();
145       fail("No exception thrown");
146     } catch (SomeUncheckedException expected) {
147     }
148   }
149 
testCantRemove()150   public void testCantRemove() {
151     Iterator<Integer> iter =
152         new AbstractIterator<Integer>() {
153           boolean haveBeenCalled;
154 
155           @Override
156           public Integer computeNext() {
157             if (haveBeenCalled) {
158               endOfData();
159             }
160             haveBeenCalled = true;
161             return 0;
162           }
163         };
164 
165     assertEquals(0, (int) iter.next());
166 
167     try {
168       iter.remove();
169       fail("No exception thrown");
170     } catch (UnsupportedOperationException expected) {
171     }
172   }
173 
174   @GwtIncompatible // weak references
testFreesNextReference()175   public void testFreesNextReference() {
176     Iterator<Object> itr =
177         new AbstractIterator<Object>() {
178           @Override
179           public Object computeNext() {
180             return new Object();
181           }
182         };
183     WeakReference<Object> ref = new WeakReference<>(itr.next());
184     GcFinalization.awaitClear(ref);
185   }
186 
testReentrantHasNext()187   public void testReentrantHasNext() {
188     Iterator<Integer> iter =
189         new AbstractIterator<Integer>() {
190           @Override
191           protected Integer computeNext() {
192             boolean unused = hasNext();
193             return null;
194           }
195         };
196     try {
197       iter.hasNext();
198       fail();
199     } catch (IllegalStateException expected) {
200     }
201   }
202 
203   // Technically we should test other reentrant scenarios (4 combinations of
204   // hasNext/next), but we'll cop out for now, knowing that
205   // next() both start by invoking hasNext() anyway.
206 
207   /** Throws a undeclared checked exception. */
sneakyThrow(Throwable t)208   private static void sneakyThrow(Throwable t) {
209     class SneakyThrower<T extends Throwable> {
210       @SuppressWarnings("unchecked") // intentionally unsafe for test
211       void throwIt(Throwable t) throws T {
212         throw (T) t;
213       }
214     }
215     new SneakyThrower<Error>().throwIt(t);
216   }
217 
218   private static class SomeCheckedException extends Exception {}
219 
220   private static class SomeUncheckedException extends RuntimeException {}
221 }
222