Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (C) 2008 The Guava Authors
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package com.google.common.collect.testing;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.fail;
 
 
 
 import java.util.List;
 import java.util.Set;
Most of the logic for IteratorTester and ListIteratorTester.

This class is GWT compatible.

Parameters:
<E> the type of element returned by the iterator
<I> the type of the iterator (java.util.Iterator or java.util.ListIterator)
Author(s):
Kevin Bourrillion
Chris Povirk
 
 abstract class AbstractIteratorTester<E, I extends Iterator<E>> {
   private boolean whenAddThrowsExceptionStopTesting;

  
Don't verify iterator behavior on remove() after a call to next() throws an exception.

JDK 6 currently has a bug where some iterators get into a undefined state when next() throws a NoSuchElementException. The correct behavior is for remove() to remove the last element returned by next, even if a subsequent next() call threw an exception; however JDK 6's HashMap and related classes throw an IllegalStateException in this case.

Calling this method causes the iterator tester to skip testing any remove() in a stimulus sequence after the reference iterator throws an exception in next().

TODO: remove this once we're on 6u5, which has the fix.

See also:
Sun Java Bug 6529795
 
   public void ignoreSunJavaBug6529795() {
   }

  
Don't verify iterator behavior after a call to add() throws an exception.

AbstractList's ListIterator implementation gets into a undefined state when add() throws an UnsupportedOperationException. Instead of leaving the iterator's position unmodified, it increments it, skipping an element or even moving past the end of the list.

Calling this method causes the iterator tester to skip testing in a stimulus sequence after the iterator under test throws an exception in add().

TODO: remove this once the behavior is fixed.

See also:
Sun Java Bug 6533203
 
   public void stopTestingWhenAddThrowsException() {
   }
 
  private Stimulus<E, ? super I>[] stimuli;
  private final Iterator<E> elementsToInsert;
  private final Set<IteratorFeaturefeatures;
  private final List<E> expectedElements;
  private final int startIndex;
  private final KnownOrder knownOrder;

  
Meta-exception thrown by AbstractIteratorTester.MultiExceptionListIterator instead of throwing any particular exception type.
  // This class is accessible but not supported in GWT.
  private static final class PermittedMetaException extends RuntimeException {
    final Set<? extends Class<? extends RuntimeException>> exceptionClasses;
        Set<? extends Class<? extends RuntimeException>> exceptionClasses) {
      super("one of " + exceptionClasses);
      this. = exceptionClasses;
    }
    PermittedMetaException(Class<? extends RuntimeExceptionexceptionClass) {
      this(Collections.singleton(exceptionClass));
    }
    // It's not supported In GWT, it always returns true.
    boolean isPermitted(RuntimeException exception) {
      for (Class<? extends RuntimeExceptionclazz : ) {
        if (Platform.checkIsInstance(clazzexception)) {
          return true;
        }
      }
      return false;
    }
    // It's not supported in GWT, it always passes.
    void assertPermitted(RuntimeException exception) {
      if (!isPermitted(exception)) {
        // TODO: use simple class names
        String message = "Exception " + exception.getClass()
            + " was thrown; expected " + this;
        Helpers.fail(exceptionmessage);
      }
    }
    @Override public String toString() {
      return getMessage();
    }
    private static final long serialVersionUID = 0;
  }
  private static final class UnknownElementException extends RuntimeException {
    private UnknownElementException(Collection<?> expectedObject actual) {
      super("Returned value '"
          + actual + "' not found. Remaining elements: " + expected);
    }
    private static final long serialVersionUID = 0;
  }

  
Quasi-implementation of java.util.ListIterator that works from a list of elements and a set of features to support (from the enclosing AbstractIteratorTester instance). Instead of throwing exceptions like java.util.NoSuchElementException at the appropriate times, it throws AbstractIteratorTester.PermittedMetaException instances, which wrap a set of all exceptions that the iterator could throw during the invocation of that method. This is necessary because, e.g., a call to iterator().remove() of an unmodifiable list could throw either java.lang.IllegalStateException or java.lang.UnsupportedOperationException. Note that iterator implementations should always throw one of the exceptions in a PermittedExceptions instance, since PermittedExceptions is thrown only when a method call is invalid.

This class is accessible but not supported in GWT as it references AbstractIteratorTester.PermittedMetaException.

  protected final class MultiExceptionListIterator implements ListIterator<E> {
    // TODO: track seen elements when order isn't guaranteed
    // TODO: verify contents afterward
    // TODO: something shiny and new instead of Stack
    // TODO: test whether null is supported (create a Feature)
    
The elements to be returned by future calls to next(), with the first at the top of the stack.
    final Stack<E> nextElements = new Stack<E>();
    
The elements to be returned by future calls to previous(), with the first at the top of the stack.
    final Stack<E> previousElements = new Stack<E>();
    
nextElements if next() was called more recently then previous, previousElements if the reverse is true, or -- overriding both of these -- null if remove() or add() has been called more recently than either. We use this to determine which stack to pop from on a call to remove() (or to pop from and push to on a call to set().
    MultiExceptionListIterator(List<E> expectedElements) {
      Helpers.addAll(, Helpers.reverse(expectedElements));
      for (int i = 0; i < i++) {
      }
    }
    @Override
    public void add(E e) {
        throw new PermittedMetaException(UnsupportedOperationException.class);
      }
      .push(e);
    }
    @Override
    public boolean hasNext() {
      return !.isEmpty();
    }
    @Override
    public boolean hasPrevious() {
      return !.isEmpty();
    }
    @Override
    public E next() {
    }
    @Override
    public int nextIndex() {
      return .size();
    }
    @Override
    public E previous() {
    }
    @Override
    public int previousIndex() {
      return nextIndex() - 1;
    }
    @Override
    public void remove() {
    }
    @Override
    public void set(E e) {
    }

    
Moves the given element from its current position in nextElements to the top of the stack so that it is returned by the next call to java.util.Iterator.next(). If the element is not in nextElements, this method throws an AbstractIteratorTester.UnknownElementException.

This method is used when testing iterators without a known ordering. We poll the target iterator's next element and pass it to the reference iterator through this method so it can return the same element. This enables the assertion to pass and the reference iterator to properly update its state.

    void promoteToNext(E e) {
      if (.remove(e)) {
        .push(e);
      } else {
        throw new UnknownElementException(e);
      }
    }
    private E transferElement(Stack<E> sourceStack<E> destination) {
      if (source.isEmpty()) {
        throw new PermittedMetaException(NoSuchElementException.class);
      }
      destination.push(source.pop());
       = destination;
      return destination.peek();
    }
    private void throwIfInvalid(IteratorFeature methodFeature) {
      Set<Class<? extends RuntimeException>> exceptions
          = new HashSet<Class<? extends RuntimeException>>();
      if (!.contains(methodFeature)) {
        exceptions.add(UnsupportedOperationException.class);
      }
      if ( == null) {
        exceptions.add(IllegalStateException.class);
      }
      if (!exceptions.isEmpty()) {
        throw new PermittedMetaException(exceptions);
      }
    }
    private List<E> getElements() {
      List<E> elements = new ArrayList<E>();
      Helpers.addAll(elements);
      Helpers.addAll(elements, Helpers.reverse());
      return elements;
    }
  }
  public enum KnownOrder { KNOWN_ORDER, UNKNOWN_ORDER }
  @SuppressWarnings("unchecked"// creating array of generic class Stimulus
  AbstractIteratorTester(int stepsIterable<E> elementsToInsertIterable,
      Iterable<? extends IteratorFeaturefeatures,
      Iterable<E> expectedElementsKnownOrder knownOrderint startIndex) {
    // periodically we should manually try (steps * 3 / 2) here; all tests but
    // one should still pass (testVerifyGetsCalled()).
     = new Stimulus[steps];
    if (!elementsToInsertIterable.iterator().hasNext()) {
      throw new IllegalArgumentException();
    }
     = Helpers.cycle(elementsToInsertIterable);
    this. = Helpers.copyToSet(features);
    this. = Helpers.copyToList(expectedElements);
    this. = knownOrder;
    this. = startIndex;
  }

  
I'd like to make this a parameter to the constructor, but I can't because the stimulus instances refer to this.
  protected abstract Iterable<? extends Stimulus<E, ? super I>>
      getStimulusValues();

  
Returns a new target iterator each time it's called. This is the iterator you are trying to test. This must return an Iterator that returns the expected elements passed to the constructor in the given order. Warning: it is not enough to simply pull multiple iterators from the same source Iterable, unless that Iterator is unmodifiable.
  protected abstract I newTargetIterator();

  
Override this to verify anything after running a list of Stimuli.

For example, verify that calls to remove() actually removed the correct elements.

Parameters:
elements the expected elements passed to the constructor, as mutated by remove(), set(), and add() calls
  protected void verify(List<E> elements) {}

  
Executes the test.
  public final void test() {
    try {
      recurse(0);
    } catch (RuntimeException e) {
      throw new RuntimeException(Arrays.toString(), e);
    }
  }
  private void recurse(int level) {
    // We're going to reuse the stimuli array 3^steps times by overwriting it
    // in a recursive loop.  Sneaky.
    if (level == .) {
      // We've filled the array.
    } else {
      // Keep recursing to fill the array.
      for (Stimulus<E, ? super I> stimulus : getStimulusValues()) {
        [level] = stimulus;
        recurse(level + 1);
      }
    }
  }
    MultiExceptionListIterator reference =
    I target = newTargetIterator();
    boolean shouldStopTestingCallsToRemove = false;
    for (int i = 0; i < .i++) {
      Stimulus<E, ? super I> stimulus = [i];
      if (stimulus.equals() && shouldStopTestingCallsToRemove) {
        break;
      }
      try {
        boolean threwException = stimulus.executeAndCompare(referencetarget);
        if (threwException
            && stimulus.equals()
          shouldStopTestingCallsToRemove = true;
        }
        if (threwException
            && stimulus.equals()
            && ) {
          break;
        }
        List<E> elements = reference.getElements();
        verify(elements);
      } catch (AssertionFailedError cause) {
        Helpers.fail(cause,
            "failed with stimuli " + subListCopy(i + 1));
      }
    }
  }
  private static List<ObjectsubListCopy(Object[] sourceint size) {
    final Object[] copy = new Object[size];
    System.arraycopy(source, 0, copy, 0, size);
    return Arrays.asList(copy);
  }
  private interface IteratorOperation {
    Object execute(Iterator<?> iterator);
  }

  
Apply this method to both iterators and return normally only if both produce the same response.

Returns:
true if an exception was thrown by the iterators.
See also:
AbstractIteratorTester.Stimulus.executeAndCompare(java.util.ListIterator,java.util.Iterator)
  private <T extends Iterator<E>> boolean internalExecuteAndCompare(
      T reference, T targetIteratorOperation method)
      throws AssertionFailedError {
    Object referenceReturnValue = null;
    PermittedMetaException referenceException = null;
    Object targetReturnValue = null;
    RuntimeException targetException = null;
    try {
      targetReturnValue = method.execute(target);
    } catch (RuntimeException e) {
      targetException = e;
    }
    try {
      if (method ==  && targetException == null
          &&  == .) {
        /*
         * We already know the iterator is an Iterator<E>, and now we know that
         * we called next(), so the returned element must be of type E.
         */
        @SuppressWarnings("unchecked")
        E targetReturnValueFromNext = (E) targetReturnValue;
        /*
         * We have an Iterator<E> and want to cast it to
         * MultiExceptionListIterator. Because we're inside an
         * AbstractIteratorTester<E>, that's implicitly a cast to
         * AbstractIteratorTester<E>.MultiExceptionListIterator. The runtime
         * won't be able to verify the AbstractIteratorTester<E> part, so it's
         * an unchecked cast. We know, however, that the only possible value for
         * the type parameter is <E>, since otherwise the
         * MultiExceptionListIterator wouldn't be an Iterator<E>. The cast is
         * safe, even though javac can't tell.
         *
         * Sun bug 6665356 is an additional complication. Until OpenJDK 7, javac
         * doesn't recognize this kind of cast as unchecked cast. Neither does
         * Eclipse 3.4. Right now, this suppression is mostly unecessary.
         */
        MultiExceptionListIterator multiExceptionListIterator =
            (MultiExceptionListIteratorreference;
        multiExceptionListIterator.promoteToNext(targetReturnValueFromNext);
      }
      referenceReturnValue = method.execute(reference);
    } catch (PermittedMetaException e) {
      referenceException = e;
    } catch (UnknownElementException e) {
      Helpers.fail(ee.getMessage());
    }
    if (referenceException == null) {
      if (targetException != null) {
        Helpers.fail(targetException,
            "Target threw exception when reference did not");
      }
      /*
       * Reference iterator returned a value, so we should expect the
       * same value from the target
       */
      assertEquals(referenceReturnValuetargetReturnValue);
      return false;
    }
    if (targetException == null) {
      fail("Target failed to throw " + referenceException);
    }
    /*
     * Reference iterator threw an exception, so we should expect an acceptable
     * exception from the target.
     */
    referenceException.assertPermitted(targetException);
    return true;
  }
  private static final IteratorOperation REMOVE_METHOD =
      new IteratorOperation() {
        @Override
        public Object execute(Iterator<?> iterator) {
          iterator.remove();
          return null;
        }
      };
  private static final IteratorOperation NEXT_METHOD =
      new IteratorOperation() {
        @Override
        public Object execute(Iterator<?> iterator) {
          return iterator.next();
        }
      };
  private static final IteratorOperation PREVIOUS_METHOD =
      new IteratorOperation() {
        @Override
        public Object execute(Iterator<?> iterator) {
          return ((ListIterator<?>) iterator).previous();
        }
      };
  private final IteratorOperation newAddMethod() {
    final Object toInsert = .next();
    return new IteratorOperation() {
      @Override
      public Object execute(Iterator<?> iterator) {
        @SuppressWarnings("unchecked")
        ListIterator<ObjectrawIterator = (ListIterator<Object>) iterator;
        rawIterator.add(toInsert);
        return null;
      }
    };
  }
  private final IteratorOperation newSetMethod() {
    final E toInsert = .next();
    return new IteratorOperation() {
      @Override
      public Object execute(Iterator<?> iterator) {
        @SuppressWarnings("unchecked")
        ListIterator<E> li = (ListIterator<E>) iterator;
        li.set(toInsert);
        return null;
      }
    };
  }
  abstract static class Stimulus<E, T extends Iterator<E>> {
    private final String toString;
    protected Stimulus(String toString) {
      this. = toString;
    }

    
Send this stimulus to both iterators and return normally only if both produce the same response.

Returns:
true if an exception was thrown by the iterators.
    abstract boolean executeAndCompare(ListIterator<E> reference, T target);
    @Override public String toString() {
      return ;
    }
  }
  Stimulus<E, Iterator<E>> hasNext = new Stimulus<E, Iterator<E>>("hasNext") {
    @Override boolean
        executeAndCompare(ListIterator<E> referenceIterator<E> target) {
      // return only if both are true or both are false
      assertEquals(reference.hasNext(), target.hasNext());
      return false;
    }
  };
  Stimulus<E, Iterator<E>> next = new Stimulus<E, Iterator<E>>("next") {
    @Override boolean
        executeAndCompare(ListIterator<E> referenceIterator<E> target) {
      return internalExecuteAndCompare(referencetarget);
    }
  };
  Stimulus<E, Iterator<E>> remove = new Stimulus<E, Iterator<E>>("remove") {
    @Override boolean
        executeAndCompare(ListIterator<E> referenceIterator<E> target) {
      return internalExecuteAndCompare(referencetarget);
    }
  };
  @SuppressWarnings("unchecked")
    return Arrays.asList();
  }
      new Stimulus<E, ListIterator<E>>("hasPrevious") {
        @Override boolean executeAndCompare(
            ListIterator<E> referenceListIterator<E> target) {
          // return only if both are true or both are false
          assertEquals(reference.hasPrevious(), target.hasPrevious());
          return false;
        }
      };
      new Stimulus<E, ListIterator<E>>("nextIndex") {
        @Override boolean executeAndCompare(
            ListIterator<E> referenceListIterator<E> target) {
          assertEquals(reference.nextIndex(), target.nextIndex());
          return false;
        }
      };
      new Stimulus<E, ListIterator<E>>("previousIndex") {
        @Override boolean executeAndCompare(
            ListIterator<E> referenceListIterator<E> target) {
          assertEquals(reference.previousIndex(), target.previousIndex());
          return false;
        }
      };
      new Stimulus<E, ListIterator<E>>("previous") {
        @Override boolean executeAndCompare(
            ListIterator<E> referenceListIterator<E> target) {
          return internalExecuteAndCompare(referencetarget);
        }
      };
  Stimulus<E, ListIterator<E>> add = new Stimulus<E, ListIterator<E>>("add") {
    @Override boolean executeAndCompare(
        ListIterator<E> referenceListIterator<E> target) {
      return internalExecuteAndCompare(referencetargetnewAddMethod());
    }
  };
  Stimulus<E, ListIterator<E>> set = new Stimulus<E, ListIterator<E>>("set") {
    @Override boolean executeAndCompare(
        ListIterator<E> referenceListIterator<E> target) {
      return internalExecuteAndCompare(referencetargetnewSetMethod());
    }
  };
  @SuppressWarnings("unchecked")
    return Arrays.asList(
  }
New to GrepCode? Check out our FAQ X