• 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 
23 import junit.framework.TestCase;
24 
25 import java.lang.ref.WeakReference;
26 import java.util.Iterator;
27 import java.util.NoSuchElementException;
28 
29 /**
30  * Unit test for {@code AbstractIterator}.
31  *
32  * @author Kevin Bourrillion
33  */
34 @GwtCompatible(emulated = true)
35 // TODO(cpovirk): why is this slow (>1m/test) under GWT when fully optimized?
36 public class AbstractIteratorTest extends TestCase {
37 
testDefaultBehaviorOfNextAndHasNext()38   public void testDefaultBehaviorOfNextAndHasNext() {
39 
40     // This sample AbstractIterator returns 0 on the first call, 1 on the
41     // second, then signals that it's reached the end of the data
42     Iterator<Integer> iter = new AbstractIterator<Integer>() {
43       private int rep;
44       @Override 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 = new AbstractIterator<Integer>() {
82       boolean haveBeenCalled;
83       @Override public Integer computeNext() {
84         if (haveBeenCalled) {
85           fail("Should not have been called again");
86         } else {
87           haveBeenCalled = true;
88           sneakyThrow(new SomeCheckedException());
89         }
90         return null; // never reached
91       }
92     };
93 
94     // The first time, the sneakily-thrown exception comes out
95     try {
96       iter.hasNext();
97       fail("No exception thrown");
98     } catch (Exception e) {
99       if (!(e instanceof SomeCheckedException)) {
100         throw e;
101       }
102     }
103 
104     // But the second time, AbstractIterator itself throws an ISE
105     try {
106       iter.hasNext();
107       fail("No exception thrown");
108     } catch (IllegalStateException expected) {
109     }
110   }
111 
testException()112   public void testException() {
113     final SomeUncheckedException exception = new SomeUncheckedException();
114     Iterator<Integer> iter = new AbstractIterator<Integer>() {
115       @Override public Integer computeNext() {
116         throw exception;
117       }
118     };
119 
120     // It should pass through untouched
121     try {
122       iter.hasNext();
123       fail("No exception thrown");
124     } catch (SomeUncheckedException e) {
125       assertSame(exception, e);
126     }
127   }
128 
testExceptionAfterEndOfData()129   public void testExceptionAfterEndOfData() {
130     Iterator<Integer> iter = new AbstractIterator<Integer>() {
131       @Override public Integer computeNext() {
132         endOfData();
133         throw new SomeUncheckedException();
134       }
135     };
136     try {
137       iter.hasNext();
138       fail("No exception thrown");
139     } catch (SomeUncheckedException expected) {
140     }
141   }
142 
testCantRemove()143   public void testCantRemove() {
144     Iterator<Integer> iter = new AbstractIterator<Integer>() {
145       boolean haveBeenCalled;
146       @Override public Integer computeNext() {
147         if (haveBeenCalled) {
148           endOfData();
149         }
150         haveBeenCalled = true;
151         return 0;
152       }
153     };
154 
155     assertEquals(0, (int) iter.next());
156 
157     try {
158       iter.remove();
159       fail("No exception thrown");
160     } catch (UnsupportedOperationException expected) {
161     }
162   }
163 
164   @GwtIncompatible("weak references")
testFreesNextReference()165   public void testFreesNextReference() {
166     Iterator<Object> itr = new AbstractIterator<Object>() {
167       @Override public Object computeNext() {
168         return new Object();
169       }
170     };
171     WeakReference<Object> ref = new WeakReference<Object>(itr.next());
172     GcFinalization.awaitClear(ref);
173   }
174 
testReentrantHasNext()175   public void testReentrantHasNext() {
176     Iterator<Integer> iter = new AbstractIterator<Integer>() {
177       @Override protected Integer computeNext() {
178         hasNext();
179         return null;
180       }
181     };
182     try {
183       iter.hasNext();
184       fail();
185     } catch (IllegalStateException expected) {
186     }
187   }
188 
189   // Technically we should test other reentrant scenarios (4 combinations of
190   // hasNext/next), but we'll cop out for now, knowing that
191   // next() both start by invoking hasNext() anyway.
192 
193   /**
194    * Throws a undeclared checked exception.
195    */
sneakyThrow(Throwable t)196   private static void sneakyThrow(Throwable t) {
197     class SneakyThrower<T extends Throwable> {
198       @SuppressWarnings("unchecked") // intentionally unsafe for test
199       void throwIt(Throwable t) throws T {
200         throw (T) t;
201       }
202     }
203     new SneakyThrower<Error>().throwIt(t);
204   }
205 
206   private static class SomeCheckedException extends Exception {
207   }
208 
209   private static class SomeUncheckedException extends RuntimeException {
210   }
211 }
212