1/*
2 * Copyright (C) 2008 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.collect.testing.testers;
18
19import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
20import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
21import static com.google.common.collect.testing.features.CollectionFeature.KNOWN_ORDER;
22import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
23
24import com.google.common.collect.testing.AbstractCollectionTester;
25import com.google.common.collect.testing.Helpers;
26import com.google.common.collect.testing.IteratorFeature;
27import com.google.common.collect.testing.IteratorTester;
28import com.google.common.collect.testing.features.CollectionFeature;
29
30import java.lang.reflect.Method;
31import java.util.ArrayList;
32import java.util.Arrays;
33import java.util.Iterator;
34import java.util.List;
35import java.util.NoSuchElementException;
36import java.util.Set;
37import java.util.concurrent.CopyOnWriteArrayList;
38import java.util.concurrent.CopyOnWriteArraySet;
39
40/**
41 * A generic JUnit test which tests {@code iterator} operations on a collection.
42 * Can't be invoked directly; please see
43 * {@link com.google.common.collect.testing.CollectionTestSuiteBuilder}.
44 *
45 * <p>This class is GWT compatible.
46 *
47 * @author Chris Povirk
48 */
49public class CollectionIteratorTester<E> extends AbstractCollectionTester<E> {
50  public void testIterator() {
51    List<E> iteratorElements = new ArrayList<E>();
52    for (E element : collection) { // uses iterator()
53      iteratorElements.add(element);
54    }
55    Helpers.assertEqualIgnoringOrder(
56        Arrays.asList(createSamplesArray()), iteratorElements);
57  }
58
59  @CollectionFeature.Require(KNOWN_ORDER)
60  public void testIterationOrdering() {
61    List<E> iteratorElements = new ArrayList<E>();
62    for (E element : collection) { // uses iterator()
63      iteratorElements.add(element);
64    }
65    List<E> expected = Helpers.copyToList(getOrderedElements());
66    assertEquals("Different ordered iteration", expected, iteratorElements);
67  }
68
69  // TODO: switch to DerivedIteratorTestSuiteBuilder
70
71  @CollectionFeature.Require({KNOWN_ORDER, SUPPORTS_REMOVE})
72  public void testIterator_knownOrderRemoveSupported() {
73    runIteratorTest(MODIFIABLE, IteratorTester.KnownOrder.KNOWN_ORDER,
74        getOrderedElements());
75  }
76
77  @CollectionFeature.Require(value = KNOWN_ORDER, absent = SUPPORTS_REMOVE)
78  public void testIterator_knownOrderRemoveUnsupported() {
79    runIteratorTest(UNMODIFIABLE, IteratorTester.KnownOrder.KNOWN_ORDER,
80        getOrderedElements());
81  }
82
83  @CollectionFeature.Require(absent = KNOWN_ORDER, value = SUPPORTS_REMOVE)
84  public void testIterator_unknownOrderRemoveSupported() {
85    runIteratorTest(MODIFIABLE, IteratorTester.KnownOrder.UNKNOWN_ORDER,
86        getSampleElements());
87  }
88
89  @CollectionFeature.Require(absent = {KNOWN_ORDER, SUPPORTS_REMOVE})
90  public void testIterator_unknownOrderRemoveUnsupported() {
91    runIteratorTest(UNMODIFIABLE, IteratorTester.KnownOrder.UNKNOWN_ORDER,
92        getSampleElements());
93  }
94
95  private void runIteratorTest(Set<IteratorFeature> features,
96      IteratorTester.KnownOrder knownOrder, Iterable<E> elements) {
97    new IteratorTester<E>(Platform.collectionIteratorTesterNumIterations(), features, elements,
98        knownOrder) {
99      {
100        // TODO: don't set this universally
101        ignoreSunJavaBug6529795();
102      }
103
104      @Override protected Iterator<E> newTargetIterator() {
105        resetCollection();
106        return collection.iterator();
107      }
108
109      @Override protected void verify(List<E> elements) {
110        expectContents(elements);
111      }
112    }.test();
113  }
114
115  /**
116   * Returns the {@link Method} instance for
117   * {@link #testIterator_knownOrderRemoveSupported()} so that tests of
118   * {@link CopyOnWriteArraySet} and {@link CopyOnWriteArrayList} can suppress
119   * it with {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
120   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570575">Sun bug
121   * 6570575</a> is fixed.
122   */
123  public static Method getIteratorKnownOrderRemoveSupportedMethod() {
124    return Platform.getMethod(
125          CollectionIteratorTester.class, "testIterator_knownOrderRemoveSupported");
126  }
127
128  /**
129   * Returns the {@link Method} instance for
130   * {@link #testIterator_unknownOrderRemoveSupported()} so that tests of
131   * classes with unmodifiable iterators can suppress it.
132   */
133  public static Method getIteratorUnknownOrderRemoveSupportedMethod() {
134    return Platform.getMethod(
135        CollectionIteratorTester.class, "testIterator_unknownOrderRemoveSupported");
136  }
137
138  public void testIteratorNoSuchElementException() {
139    Iterator<E> iterator = collection.iterator();
140    while (iterator.hasNext()) {
141      iterator.next();
142    }
143
144    try {
145      iterator.next();
146      fail("iterator.next() should throw NoSuchElementException");
147    } catch (NoSuchElementException expected) {}
148  }
149
150  /**
151   * Returns the {@link Method} instance for
152   * {@link #testIterator_knownOrderRemoveUnsupported()} so that tests of
153   * {@code ArrayStack} can suppress it with
154   * {@code FeatureSpecificTestSuiteBuilder.suppressing()}. {@code ArrayStack}
155   * supports {@code remove()} on only the first element, and the iterator
156   * tester can't handle that.
157   */
158  public static Method getIteratorKnownOrderRemoveUnsupportedMethod() {
159    return Platform.getMethod(
160        CollectionIteratorTester.class, "testIterator_knownOrderRemoveUnsupported");
161  }
162}
163