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 21 import junit.framework.TestCase; 22 23 import java.util.Iterator; 24 import java.util.NoSuchElementException; 25 26 /** 27 * Unit test for {@code AbstractIterator}. 28 * 29 * @author Kevin Bourrillion 30 */ 31 @SuppressWarnings("serial") // No serialization is used in this test 32 @GwtCompatible 33 // TODO(cpovirk): why is this slow (>1m/test) under GWT when fully optimized? 34 public class AbstractIteratorTest extends TestCase { 35 36 public void testDefaultBehaviorOfNextAndHasNext() { 37 38 // This sample AbstractIterator returns 0 on the first call, 1 on the 39 // second, then signals that it's reached the end of the data 40 Iterator<Integer> iter = new AbstractIterator<Integer>() { 41 private int rep; 42 @Override public Integer computeNext() { 43 switch (rep++) { 44 case 0: 45 return 0; 46 case 1: 47 return 1; 48 case 2: 49 return endOfData(); 50 default: 51 fail("Should not have been invoked again"); 52 return null; 53 } 54 } 55 }; 56 57 assertTrue(iter.hasNext()); 58 assertEquals(0, (int) iter.next()); 59 60 // verify idempotence of hasNext() 61 assertTrue(iter.hasNext()); 62 assertTrue(iter.hasNext()); 63 assertTrue(iter.hasNext()); 64 assertEquals(1, (int) iter.next()); 65 66 assertFalse(iter.hasNext()); 67 68 // Make sure computeNext() doesn't get invoked again 69 assertFalse(iter.hasNext()); 70 71 try { 72 iter.next(); 73 fail("no exception thrown"); 74 } catch (NoSuchElementException expected) { 75 } 76 } 77 78 public void testSneakyThrow() throws Exception { 79 Iterator<Integer> iter = new AbstractIterator<Integer>() { 80 boolean haveBeenCalled; 81 @Override public Integer computeNext() { 82 if (haveBeenCalled) { 83 fail("Should not have been called again"); 84 } else { 85 haveBeenCalled = true; 86 sneakyThrow(new SomeCheckedException()); 87 } 88 return null; // never reached 89 } 90 }; 91 92 // The first time, the sneakily-thrown exception comes out 93 try { 94 iter.hasNext(); 95 fail("No exception thrown"); 96 } catch (Exception e) { 97 if (!(e instanceof SomeCheckedException)) { 98 throw e; 99 } 100 } 101 102 // But the second time, AbstractIterator itself throws an ISE 103 try { 104 iter.hasNext(); 105 fail("No exception thrown"); 106 } catch (IllegalStateException expected) { 107 } 108 } 109 110 public void testException() { 111 final SomeUncheckedException exception = new SomeUncheckedException(); 112 Iterator<Integer> iter = new AbstractIterator<Integer>() { 113 @Override public Integer computeNext() { 114 throw exception; 115 } 116 }; 117 118 // It should pass through untouched 119 try { 120 iter.hasNext(); 121 fail("No exception thrown"); 122 } catch (SomeUncheckedException e) { 123 assertSame(exception, e); 124 } 125 } 126 127 public void testExceptionAfterEndOfData() { 128 Iterator<Integer> iter = new AbstractIterator<Integer>() { 129 @Override public Integer computeNext() { 130 endOfData(); 131 throw new SomeUncheckedException(); 132 } 133 }; 134 try { 135 iter.hasNext(); 136 fail("No exception thrown"); 137 } catch (SomeUncheckedException expected) { 138 } 139 } 140 141 public void testCantRemove() { 142 Iterator<Integer> iter = new AbstractIterator<Integer>() { 143 boolean haveBeenCalled; 144 @Override public Integer computeNext() { 145 if (haveBeenCalled) { 146 endOfData(); 147 } 148 haveBeenCalled = true; 149 return 0; 150 } 151 }; 152 153 assertEquals(0, (int) iter.next()); 154 155 try { 156 iter.remove(); 157 fail("No exception thrown"); 158 } catch (UnsupportedOperationException expected) { 159 } 160 } 161 162 public void testReentrantHasNext() { 163 Iterator<Integer> iter = new AbstractIterator<Integer>() { 164 @Override protected Integer computeNext() { 165 hasNext(); 166 return null; 167 } 168 }; 169 try { 170 iter.hasNext(); 171 fail(); 172 } catch (IllegalStateException expected) { 173 } 174 } 175 176 // Technically we should test other reentrant scenarios (4 combinations of 177 // hasNext/next), but we'll cop out for now, knowing that 178 // next() both start by invoking hasNext() anyway. 179 180 /** 181 * Throws a undeclared checked exception. 182 */ 183 private static void sneakyThrow(Throwable t) { 184 class SneakyThrower<T extends Throwable> { 185 @SuppressWarnings("unchecked") // not really safe, but that's the point 186 void throwIt(Throwable t) throws T { 187 throw (T) t; 188 } 189 } 190 new SneakyThrower<Error>().throwIt(t); 191 } 192 193 private static class SomeCheckedException extends Exception { 194 } 195 196 private static class SomeUncheckedException extends RuntimeException { 197 } 198 } 199