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