001/*
002 * Copyright (C) 2009 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;
018
019import static java.util.Arrays.asList;
020
021import com.google.common.annotations.GwtCompatible;
022import java.util.Collection;
023import java.util.Iterator;
024import org.jspecify.annotations.Nullable;
025
026/**
027 * An implementation of {@code Iterable} which throws an exception on all invocations of the {@link
028 * #iterator()} method after the first, and whose iterator is always unmodifiable.
029 *
030 * <p>The {@code Iterable} specification does not make it absolutely clear what should happen on a
031 * second invocation, so implementors have made various choices, including:
032 *
033 * <ul>
034 *   <li>returning the same iterator again
035 *   <li>throwing an exception of some kind
036 *   <li>or the usual, <i>robust</i> behavior, which all known {@link Collection} implementations
037 *       have, of returning a new, independent iterator
038 * </ul>
039 *
040 * <p>Because of this situation, any public method accepting an iterable should invoke the {@code
041 * iterator} method only once, and should be tested using this class. Exceptions to this rule should
042 * be clearly documented.
043 *
044 * <p>Note that although your APIs should be liberal in what they accept, your methods which
045 * <i>return</i> iterables should make every attempt to return ones of the robust variety.
046 *
047 * <p>This testing utility is not thread-safe.
048 *
049 * @author Kevin Bourrillion
050 */
051@GwtCompatible
052public final class MinimalIterable<E extends @Nullable Object> implements Iterable<E> {
053  /** Returns an iterable whose iterator returns the given elements in order. */
054  public static <E extends @Nullable Object> MinimalIterable<E> of(E... elements) {
055    // Make sure to get an unmodifiable iterator
056    return new MinimalIterable<>(asList(elements).iterator());
057  }
058
059  /**
060   * Returns an iterable whose iterator returns the given elements in order. The elements are copied
061   * out of the source collection at the time this method is called.
062   */
063  @SuppressWarnings("unchecked") // Es come in, Es go out
064  public static <E extends @Nullable Object> MinimalIterable<E> from(Collection<E> elements) {
065    return (MinimalIterable) of(elements.toArray());
066  }
067
068  private @Nullable Iterator<E> iterator;
069
070  private MinimalIterable(Iterator<E> iterator) {
071    this.iterator = iterator;
072  }
073
074  @Override
075  public Iterator<E> iterator() {
076    if (iterator == null) {
077      // TODO: throw something else? Do we worry that people's code and tests
078      // might be relying on this particular type of exception?
079      throw new IllegalStateException();
080    }
081    try {
082      return iterator;
083    } finally {
084      iterator = null;
085    }
086  }
087}