001/*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect.testing.testers;
018
019import static com.google.common.collect.testing.Helpers.assertEqualIgnoringOrder;
020import static com.google.common.collect.testing.Helpers.copyToList;
021import static com.google.common.collect.testing.Helpers.mapEntry;
022import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
023import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
024import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_VALUES;
025import static com.google.common.collect.testing.features.CollectionFeature.KNOWN_ORDER;
026import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_ITERATOR_REMOVE;
027import static com.google.common.collect.testing.features.CollectionSize.ZERO;
028import static com.google.common.collect.testing.testers.ReflectionFreeAssertThrows.assertThrows;
029import static java.util.Arrays.asList;
030
031import com.google.common.annotations.GwtCompatible;
032import com.google.common.collect.testing.AbstractCollectionTester;
033import com.google.common.collect.testing.IteratorFeature;
034import com.google.common.collect.testing.IteratorTester;
035import com.google.common.collect.testing.features.CollectionFeature;
036import com.google.common.collect.testing.features.CollectionSize;
037import java.util.ArrayList;
038import java.util.Iterator;
039import java.util.List;
040import java.util.Map.Entry;
041import java.util.NoSuchElementException;
042import java.util.Set;
043import org.checkerframework.checker.nullness.qual.Nullable;
044import org.junit.Ignore;
045
046/**
047 * A generic JUnit test which tests {@code iterator} operations on a collection. Can't be invoked
048 * directly; please see {@link com.google.common.collect.testing.CollectionTestSuiteBuilder}.
049 *
050 * @author Chris Povirk
051 */
052@GwtCompatible(emulated = true)
053@Ignore("test runners must not instantiate and run this directly, only via suites we build")
054// @Ignore affects the Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
055@SuppressWarnings("JUnit4ClassUsedInJUnit3")
056@ElementTypesAreNonnullByDefault
057public class CollectionIteratorTester<E extends @Nullable Object>
058    extends AbstractCollectionTester<E> {
059  public void testIterator() {
060    List<E> iteratorElements = new ArrayList<>();
061    for (E element : collection) { // uses iterator()
062      iteratorElements.add(element);
063    }
064    assertEqualIgnoringOrder(asList(createSamplesArray()), iteratorElements);
065  }
066
067  @CollectionFeature.Require(KNOWN_ORDER)
068  public void testIterationOrdering() {
069    List<E> iteratorElements = new ArrayList<>();
070    for (E element : collection) { // uses iterator()
071      iteratorElements.add(element);
072    }
073    List<E> expected = copyToList(getOrderedElements());
074    assertEquals("Different ordered iteration", expected, iteratorElements);
075  }
076
077  @CollectionFeature.Require(ALLOWS_NULL_VALUES)
078  @CollectionSize.Require(absent = ZERO)
079  public void testIterator_nullElement() {
080    initCollectionWithNullElement();
081    List<E> iteratorElements = new ArrayList<>();
082    for (E element : collection) { // uses iterator()
083      iteratorElements.add(element);
084    }
085    assertEqualIgnoringOrder(asList(createArrayWithNullElement()), iteratorElements);
086  }
087
088  @CollectionFeature.Require(SUPPORTS_ITERATOR_REMOVE)
089  @CollectionSize.Require(absent = ZERO)
090  public void testIterator_removeAffectsBackingCollection() {
091    int originalSize = collection.size();
092    Iterator<E> iterator = collection.iterator();
093    Object element = iterator.next();
094    // If it's an Entry, it may become invalid once it's removed from the Map. Copy it.
095    if (element instanceof Entry) {
096      Entry<?, ?> entry = (Entry<?, ?>) element;
097      element = mapEntry(entry.getKey(), entry.getValue());
098    }
099    assertTrue(collection.contains(element)); // sanity check
100    iterator.remove();
101    assertFalse(collection.contains(element));
102    assertEquals(originalSize - 1, collection.size());
103  }
104
105  @CollectionFeature.Require({KNOWN_ORDER, SUPPORTS_ITERATOR_REMOVE})
106  public void testIterator_knownOrderRemoveSupported() {
107    runIteratorTest(MODIFIABLE, IteratorTester.KnownOrder.KNOWN_ORDER, getOrderedElements());
108  }
109
110  @CollectionFeature.Require(value = KNOWN_ORDER, absent = SUPPORTS_ITERATOR_REMOVE)
111  public void testIterator_knownOrderRemoveUnsupported() {
112    runIteratorTest(UNMODIFIABLE, IteratorTester.KnownOrder.KNOWN_ORDER, getOrderedElements());
113  }
114
115  @CollectionFeature.Require(absent = KNOWN_ORDER, value = SUPPORTS_ITERATOR_REMOVE)
116  public void testIterator_unknownOrderRemoveSupported() {
117    runIteratorTest(MODIFIABLE, IteratorTester.KnownOrder.UNKNOWN_ORDER, getSampleElements());
118  }
119
120  @CollectionFeature.Require(absent = {KNOWN_ORDER, SUPPORTS_ITERATOR_REMOVE})
121  public void testIterator_unknownOrderRemoveUnsupported() {
122    runIteratorTest(UNMODIFIABLE, IteratorTester.KnownOrder.UNKNOWN_ORDER, getSampleElements());
123  }
124
125  private void runIteratorTest(
126      Set<IteratorFeature> features, IteratorTester.KnownOrder knownOrder, Iterable<E> elements) {
127    new IteratorTester<E>(
128        Platform.collectionIteratorTesterNumIterations(), features, elements, knownOrder) {
129      @Override
130      protected Iterator<E> newTargetIterator() {
131        resetCollection();
132        return collection.iterator();
133      }
134
135      @Override
136      protected void verify(List<E> elements) {
137        expectContents(elements);
138      }
139    }.test();
140  }
141
142  public void testIteratorNoSuchElementException() {
143    Iterator<E> iterator = collection.iterator();
144    while (iterator.hasNext()) {
145      iterator.next();
146    }
147
148    assertThrows(NoSuchElementException.class, () -> iterator.next());
149  }
150}