11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2008 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.collect.testing;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static junit.framework.Assert.assertEquals;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static junit.framework.Assert.fail;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport junit.framework.AssertionFailedError;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.ArrayList;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Arrays;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collection;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collections;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.HashSet;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Iterator;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.List;
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.ListIterator;
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.NoSuchElementException;
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Set;
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Stack;
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Most of the logic for {@link IteratorTester} and {@link ListIteratorTester}.
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This class is GWT compatible.
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param <E> the type of element returned by the iterator
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param <I> the type of the iterator ({@link Iterator} or
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *     {@link ListIterator})
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Kevin Bourrillion
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Chris Povirk
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertabstract class AbstractIteratorTester<E, I extends Iterator<E>> {
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private boolean whenNextThrowsExceptionStopTestingCallsToRemove;
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private boolean whenAddThrowsExceptionStopTesting;
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Don't verify iterator behavior on remove() after a call to next()
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * throws an exception.
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>JDK 6 currently has a bug where some iterators get into a undefined
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * state when next() throws a NoSuchElementException. The correct
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * behavior is for remove() to remove the last element returned by
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * next, even if a subsequent next() call threw an exception; however
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * JDK 6's HashMap and related classes throw an IllegalStateException
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * in this case.
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>Calling this method causes the iterator tester to skip testing
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * any remove() in a stimulus sequence after the reference iterator
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * throws an exception in next().
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>TODO: remove this once we're on 6u5, which has the fix.
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6529795">
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *     Sun Java Bug 6529795</a>
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void ignoreSunJavaBug6529795() {
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    whenNextThrowsExceptionStopTestingCallsToRemove = true;
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Don't verify iterator behavior after a call to add() throws an exception.
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>AbstractList's ListIterator implementation gets into a undefined state
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * when add() throws an UnsupportedOperationException. Instead of leaving the
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * iterator's position unmodified, it increments it, skipping an element or
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * even moving past the end of the list.
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>Calling this method causes the iterator tester to skip testing in a
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * stimulus sequence after the iterator under test throws an exception in
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * add().
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>TODO: remove this once the behavior is fixed.
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6533203">
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *     Sun Java Bug 6533203</a>
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void stopTestingWhenAddThrowsException() {
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    whenAddThrowsExceptionStopTesting = true;
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private Stimulus<E, ? super I>[] stimuli;
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final Iterator<E> elementsToInsert;
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final Set<IteratorFeature> features;
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final List<E> expectedElements;
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final int startIndex;
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final KnownOrder knownOrder;
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Meta-exception thrown by
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@link AbstractIteratorTester.MultiExceptionListIterator} instead of
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * throwing any particular exception type.
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // This class is accessible but not supported in GWT.
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class PermittedMetaException extends RuntimeException {
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Set<? extends Class<? extends RuntimeException>> exceptionClasses;
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    PermittedMetaException(
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Set<? extends Class<? extends RuntimeException>> exceptionClasses) {
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super("one of " + exceptionClasses);
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.exceptionClasses = exceptionClasses;
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    PermittedMetaException(Class<? extends RuntimeException> exceptionClass) {
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this(Collections.singleton(exceptionClass));
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // It's not supported In GWT, it always returns true.
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    boolean isPermitted(RuntimeException exception) {
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (Class<? extends RuntimeException> clazz : exceptionClasses) {
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (Platform.checkIsInstance(clazz, exception)) {
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return true;
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return false;
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // It's not supported in GWT, it always passes.
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    void assertPermitted(RuntimeException exception) {
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (!isPermitted(exception)) {
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // TODO: use simple class names
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        String message = "Exception " + exception.getClass()
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            + " was thrown; expected " + this;
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Helpers.fail(exception, message);
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public String toString() {
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return getMessage();
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static final long serialVersionUID = 0;
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class UnknownElementException extends RuntimeException {
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private UnknownElementException(Collection<?> expected, Object actual) {
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super("Returned value '"
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          + actual + "' not found. Remaining elements: " + expected);
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static final long serialVersionUID = 0;
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Quasi-implementation of {@link ListIterator} that works from a list of
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * elements and a set of features to support (from the enclosing
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@link AbstractIteratorTester} instance). Instead of throwing exceptions
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * like {@link NoSuchElementException} at the appropriate times, it throws
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@link PermittedMetaException} instances, which wrap a set of all
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * exceptions that the iterator could throw during the invocation of that
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * method. This is necessary because, e.g., a call to
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@code iterator().remove()} of an unmodifiable list could throw either
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@link IllegalStateException} or {@link UnsupportedOperationException}.
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Note that iterator implementations should always throw one of the
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * exceptions in a {@code PermittedExceptions} instance, since
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@code PermittedExceptions} is thrown only when a method call is invalid.
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>This class is accessible but not supported in GWT as it references
1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@link PermittedMetaException}.
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected final class MultiExceptionListIterator implements ListIterator<E> {
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO: track seen elements when order isn't guaranteed
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO: verify contents afterward
1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO: something shiny and new instead of Stack
1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO: test whether null is supported (create a Feature)
1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * The elements to be returned by future calls to {@code next()}, with the
1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * first at the top of the stack.
1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Stack<E> nextElements = new Stack<E>();
1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * The elements to be returned by future calls to {@code previous()}, with
1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * the first at the top of the stack.
1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Stack<E> previousElements = new Stack<E>();
1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * {@link #nextElements} if {@code next()} was called more recently then
1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * {@code previous}, {@link #previousElements} if the reverse is true, or --
1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * overriding both of these -- {@code null} if {@code remove()} or
1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * {@code add()} has been called more recently than either. We use this to
1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * determine which stack to pop from on a call to {@code remove()} (or to
1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * pop from and push to on a call to {@code set()}.
1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Stack<E> stackWithLastReturnedElementAtTop = null;
2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    MultiExceptionListIterator(List<E> expectedElements) {
2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Helpers.addAll(nextElements, Helpers.reverse(expectedElements));
2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 0; i < startIndex; i++) {
2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        previousElements.push(nextElements.pop());
2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void add(E e) {
2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (!features.contains(IteratorFeature.SUPPORTS_ADD)) {
2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new PermittedMetaException(UnsupportedOperationException.class);
2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      previousElements.push(e);
2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      stackWithLastReturnedElementAtTop = null;
2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean hasNext() {
2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return !nextElements.isEmpty();
2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean hasPrevious() {
2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return !previousElements.isEmpty();
2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public E next() {
2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return transferElement(nextElements, previousElements);
2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int nextIndex() {
2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return previousElements.size();
2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public E previous() {
2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return transferElement(previousElements, nextElements);
2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int previousIndex() {
2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return nextIndex() - 1;
2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void remove() {
2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throwIfInvalid(IteratorFeature.SUPPORTS_REMOVE);
2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      stackWithLastReturnedElementAtTop.pop();
2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      stackWithLastReturnedElementAtTop = null;
2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void set(E e) {
2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throwIfInvalid(IteratorFeature.SUPPORTS_SET);
2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      stackWithLastReturnedElementAtTop.pop();
2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      stackWithLastReturnedElementAtTop.push(e);
2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Moves the given element from its current position in
2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * {@link #nextElements} to the top of the stack so that it is returned by
2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * the next call to {@link Iterator#next()}. If the element is not in
2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * {@link #nextElements}, this method throws an
2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * {@link UnknownElementException}.
2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     *
2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * <p>This method is used when testing iterators without a known ordering.
2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * We poll the target iterator's next element and pass it to the reference
2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * iterator through this method so it can return the same element. This
2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * enables the assertion to pass and the reference iterator to properly
2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * update its state.
2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    void promoteToNext(E e) {
2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (nextElements.remove(e)) {
2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        nextElements.push(e);
2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } else {
2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new UnknownElementException(nextElements, e);
2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private E transferElement(Stack<E> source, Stack<E> destination) {
2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (source.isEmpty()) {
2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new PermittedMetaException(NoSuchElementException.class);
2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      destination.push(source.pop());
2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      stackWithLastReturnedElementAtTop = destination;
2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return destination.peek();
2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private void throwIfInvalid(IteratorFeature methodFeature) {
2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Set<Class<? extends RuntimeException>> exceptions
2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          = new HashSet<Class<? extends RuntimeException>>();
2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (!features.contains(methodFeature)) {
3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        exceptions.add(UnsupportedOperationException.class);
3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (stackWithLastReturnedElementAtTop == null) {
3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        exceptions.add(IllegalStateException.class);
3051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (!exceptions.isEmpty()) {
3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new PermittedMetaException(exceptions);
3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private List<E> getElements() {
3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<E> elements = new ArrayList<E>();
3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Helpers.addAll(elements, previousElements);
3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Helpers.addAll(elements, Helpers.reverse(nextElements));
3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return elements;
3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public enum KnownOrder { KNOWN_ORDER, UNKNOWN_ORDER }
3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("unchecked") // creating array of generic class Stimulus
3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  AbstractIteratorTester(int steps, Iterable<E> elementsToInsertIterable,
3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Iterable<? extends IteratorFeature> features,
3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Iterable<E> expectedElements, KnownOrder knownOrder, int startIndex) {
3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // periodically we should manually try (steps * 3 / 2) here; all tests but
3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // one should still pass (testVerifyGetsCalled()).
3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    stimuli = new Stimulus[steps];
3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (!elementsToInsertIterable.iterator().hasNext()) {
3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new IllegalArgumentException();
3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    elementsToInsert = Helpers.cycle(elementsToInsertIterable);
3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.features = Helpers.copyToSet(features);
3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.expectedElements = Helpers.copyToList(expectedElements);
3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.knownOrder = knownOrder;
3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.startIndex = startIndex;
3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * I'd like to make this a parameter to the constructor, but I can't because
3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * the stimulus instances refer to {@code this}.
3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected abstract Iterable<? extends Stimulus<E, ? super I>>
3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      getStimulusValues();
3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a new target iterator each time it's called. This is the iterator
3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * you are trying to test. This must return an Iterator that returns the
3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * expected elements passed to the constructor in the given order. Warning: it
3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * is not enough to simply pull multiple iterators from the same source
3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Iterable, unless that Iterator is unmodifiable.
3521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
3531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected abstract I newTargetIterator();
3541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
3561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Override this to verify anything after running a list of Stimuli.
3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>For example, verify that calls to remove() actually removed
3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * the correct elements.
3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @param elements the expected elements passed to the constructor, as mutated
3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *     by {@code remove()}, {@code set()}, and {@code add()} calls
3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected void verify(List<E> elements) {}
3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Executes the test.
3681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final void test() {
3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      recurse(0);
3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (RuntimeException e) {
3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new RuntimeException(Arrays.toString(stimuli), e);
3741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private void recurse(int level) {
3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // We're going to reuse the stimuli array 3^steps times by overwriting it
3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // in a recursive loop.  Sneaky.
3801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (level == stimuli.length) {
3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // We've filled the array.
3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      compareResultsForThisListOfStimuli();
3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } else {
3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // Keep recursing to fill the array.
3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (Stimulus<E, ? super I> stimulus : getStimulusValues()) {
3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        stimuli[level] = stimulus;
3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        recurse(level + 1);
3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private void compareResultsForThisListOfStimuli() {
3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    MultiExceptionListIterator reference =
3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new MultiExceptionListIterator(expectedElements);
3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    I target = newTargetIterator();
3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    boolean shouldStopTestingCallsToRemove = false;
3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < stimuli.length; i++) {
3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Stimulus<E, ? super I> stimulus = stimuli[i];
3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (stimulus.equals(remove) && shouldStopTestingCallsToRemove) {
4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        break;
4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        boolean threwException = stimulus.executeAndCompare(reference, target);
4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (threwException
4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            && stimulus.equals(next)
4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            && whenNextThrowsExceptionStopTestingCallsToRemove) {
4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          shouldStopTestingCallsToRemove = true;
4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (threwException
4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            && stimulus.equals(add)
4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            && whenAddThrowsExceptionStopTesting) {
4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          break;
4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        List<E> elements = reference.getElements();
4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        verify(elements);
4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (AssertionFailedError cause) {
4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Helpers.fail(cause,
4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            "failed with stimuli " + subListCopy(stimuli, i + 1));
4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static List<Object> subListCopy(Object[] source, int size) {
4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Object[] copy = new Object[size];
4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Platform.unsafeArrayCopy(source, 0, copy, 0, size);
4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return Arrays.asList(copy);
4271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private interface IteratorOperation {
4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object execute(Iterator<?> iterator);
4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
4341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Apply this method to both iterators and return normally only if both
4351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * produce the same response.
4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
4371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @return {@code true} if an exception was thrown by the iterators.
4381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @see Stimulus#executeAndCompare(ListIterator, Iterator)
4401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
4411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private <T extends Iterator<E>> boolean internalExecuteAndCompare(
4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      T reference, T target, IteratorOperation method)
4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throws AssertionFailedError {
4441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object referenceReturnValue = null;
4461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    PermittedMetaException referenceException = null;
4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object targetReturnValue = null;
4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    RuntimeException targetException = null;
4491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
4511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      targetReturnValue = method.execute(target);
4521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (RuntimeException e) {
4531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      targetException = e;
4541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
4571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (method == NEXT_METHOD && targetException == null
4581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          && knownOrder == KnownOrder.UNKNOWN_ORDER) {
4591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        /*
4601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * We already know the iterator is an Iterator<E>, and now we know that
4611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * we called next(), so the returned element must be of type E.
4621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         */
4631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @SuppressWarnings("unchecked")
4641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        E targetReturnValueFromNext = (E) targetReturnValue;
4651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        /*
4661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * We have an Iterator<E> and want to cast it to
4671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * MultiExceptionListIterator. Because we're inside an
4681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * AbstractIteratorTester<E>, that's implicitly a cast to
4691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * AbstractIteratorTester<E>.MultiExceptionListIterator. The runtime
4701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * won't be able to verify the AbstractIteratorTester<E> part, so it's
4711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * an unchecked cast. We know, however, that the only possible value for
4721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * the type parameter is <E>, since otherwise the
4731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * MultiExceptionListIterator wouldn't be an Iterator<E>. The cast is
4741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * safe, even though javac can't tell.
4751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         *
4761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * Sun bug 6665356 is an additional complication. Until OpenJDK 7, javac
4771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * doesn't recognize this kind of cast as unchecked cast. Neither does
4781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         * Eclipse 3.4. Right now, this suppression is mostly unecessary.
4791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert         */
4801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        MultiExceptionListIterator multiExceptionListIterator =
4811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            (MultiExceptionListIterator) reference;
4821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        multiExceptionListIterator.promoteToNext(targetReturnValueFromNext);
4831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      referenceReturnValue = method.execute(reference);
4861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (PermittedMetaException e) {
4871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      referenceException = e;
4881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (UnknownElementException e) {
4891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Helpers.fail(e, e.getMessage());
4901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (referenceException == null) {
4931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (targetException != null) {
4941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Helpers.fail(targetException,
4951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            "Target threw exception when reference did not");
4961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      /*
4991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert       * Reference iterator returned a value, so we should expect the
5001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert       * same value from the target
5011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert       */
5021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(referenceReturnValue, targetReturnValue);
5031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return false;
5051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
5061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (targetException == null) {
5081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail("Target failed to throw " + referenceException);
5091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
5101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /*
5121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Reference iterator threw an exception, so we should expect an acceptable
5131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * exception from the target.
5141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
5151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    referenceException.assertPermitted(targetException);
5161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return true;
5181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
5191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final IteratorOperation REMOVE_METHOD =
5211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      new IteratorOperation() {
5221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
5231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public Object execute(Iterator<?> iterator) {
5241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          iterator.remove();
5251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return null;
5261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
5271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
5281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final IteratorOperation NEXT_METHOD =
5301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      new IteratorOperation() {
5311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
5321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public Object execute(Iterator<?> iterator) {
5331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return iterator.next();
5341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
5351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
5361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final IteratorOperation PREVIOUS_METHOD =
5381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      new IteratorOperation() {
5391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
5401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public Object execute(Iterator<?> iterator) {
5411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return ((ListIterator<?>) iterator).previous();
5421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
5431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
5441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final IteratorOperation newAddMethod() {
5461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Object toInsert = elementsToInsert.next();
5471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new IteratorOperation() {
5481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
5491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public Object execute(Iterator<?> iterator) {
5501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @SuppressWarnings("unchecked")
5511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ListIterator<Object> rawIterator = (ListIterator<Object>) iterator;
5521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        rawIterator.add(toInsert);
5531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return null;
5541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
5551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
5561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
5571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final IteratorOperation newSetMethod() {
5591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final E toInsert = elementsToInsert.next();
5601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new IteratorOperation() {
5611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
5621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public Object execute(Iterator<?> iterator) {
5631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @SuppressWarnings("unchecked")
5641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ListIterator<E> li = (ListIterator<E>) iterator;
5651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        li.set(toInsert);
5661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return null;
5671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
5681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
5691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
5701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  abstract static class Stimulus<E, T extends Iterator<E>> {
5721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final String toString;
5731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    protected Stimulus(String toString) {
5751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.toString = toString;
5761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
5771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
5791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Send this stimulus to both iterators and return normally only if both
5801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * produce the same response.
5811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     *
5821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * @return {@code true} if an exception was thrown by the iterators.
5831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
5841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    abstract boolean executeAndCompare(ListIterator<E> reference, T target);
5851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public String toString() {
5871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return toString;
5881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
5891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
5901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, Iterator<E>> hasNext = new Stimulus<E, Iterator<E>>("hasNext") {
5921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override boolean
5931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        executeAndCompare(ListIterator<E> reference, Iterator<E> target) {
5941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // return only if both are true or both are false
5951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(reference.hasNext(), target.hasNext());
5961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return false;
5971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
5981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  };
5991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, Iterator<E>> next = new Stimulus<E, Iterator<E>>("next") {
6001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override boolean
6011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        executeAndCompare(ListIterator<E> reference, Iterator<E> target) {
6021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return internalExecuteAndCompare(reference, target, NEXT_METHOD);
6031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
6041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  };
6051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, Iterator<E>> remove = new Stimulus<E, Iterator<E>>("remove") {
6061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override boolean
6071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        executeAndCompare(ListIterator<E> reference, Iterator<E> target) {
6081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return internalExecuteAndCompare(reference, target, REMOVE_METHOD);
6091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
6101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  };
6111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("unchecked")
6131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  List<Stimulus<E, Iterator<E>>> iteratorStimuli() {
6141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return Arrays.asList(hasNext, next, remove);
6151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
6161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, ListIterator<E>> hasPrevious =
6181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      new Stimulus<E, ListIterator<E>>("hasPrevious") {
6191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override boolean executeAndCompare(
6201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            ListIterator<E> reference, ListIterator<E> target) {
6211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // return only if both are true or both are false
6221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertEquals(reference.hasPrevious(), target.hasPrevious());
6231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return false;
6241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
6251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
6261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, ListIterator<E>> nextIndex =
6271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      new Stimulus<E, ListIterator<E>>("nextIndex") {
6281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override boolean executeAndCompare(
6291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            ListIterator<E> reference, ListIterator<E> target) {
6301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertEquals(reference.nextIndex(), target.nextIndex());
6311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return false;
6321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
6331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
6341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, ListIterator<E>> previousIndex =
6351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      new Stimulus<E, ListIterator<E>>("previousIndex") {
6361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override boolean executeAndCompare(
6371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            ListIterator<E> reference, ListIterator<E> target) {
6381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertEquals(reference.previousIndex(), target.previousIndex());
6391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return false;
6401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
6411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
6421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, ListIterator<E>> previous =
6431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      new Stimulus<E, ListIterator<E>>("previous") {
6441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override boolean executeAndCompare(
6451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            ListIterator<E> reference, ListIterator<E> target) {
6461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return internalExecuteAndCompare(reference, target, PREVIOUS_METHOD);
6471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
6481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
6491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, ListIterator<E>> add = new Stimulus<E, ListIterator<E>>("add") {
6501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override boolean executeAndCompare(
6511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ListIterator<E> reference, ListIterator<E> target) {
6521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return internalExecuteAndCompare(reference, target, newAddMethod());
6531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
6541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  };
6551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Stimulus<E, ListIterator<E>> set = new Stimulus<E, ListIterator<E>>("set") {
6561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override boolean executeAndCompare(
6571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ListIterator<E> reference, ListIterator<E> target) {
6581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return internalExecuteAndCompare(reference, target, newSetMethod());
6591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
6601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  };
6611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("unchecked")
6631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  List<Stimulus<E, ListIterator<E>>> listIteratorStimuli() {
6641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return Arrays.asList(
6651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        hasPrevious, nextIndex, previousIndex, previous, add, set);
6661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
6671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
668