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;
018
019import com.google.common.annotations.GwtCompatible;
020import com.google.errorprone.annotations.CanIgnoreReturnValue;
021import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.Collection;
025import java.util.Collections;
026import java.util.List;
027import org.checkerframework.checker.nullness.qual.Nullable;
028import org.junit.Ignore;
029
030/**
031 * Base class for testers of classes (including {@link Collection} and {@link java.util.Map Map})
032 * that contain elements.
033 *
034 * @param <C> the type of the container
035 * @param <E> the type of the container's contents
036 * @author George van den Driessche
037 */
038@GwtCompatible
039@Ignore // Affects only Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
040@ElementTypesAreNonnullByDefault
041public abstract class AbstractContainerTester<C, E extends @Nullable Object>
042    extends AbstractTester<OneSizeTestContainerGenerator<C, E>> {
043  protected SampleElements<E> samples;
044  protected C container;
045
046  @Override
047  @OverridingMethodsMustInvokeSuper
048  public void setUp() throws Exception {
049    super.setUp();
050    samples = this.getSubjectGenerator().samples();
051    resetContainer();
052  }
053
054  /**
055   * @return the contents of the container under test, for use by {@link #expectContents(Object[])
056   *     expectContents(E...)} and its friends.
057   */
058  protected abstract Collection<E> actualContents();
059
060  /**
061   * Replaces the existing container under test with a new container created by the subject
062   * generator.
063   *
064   * @see #resetContainer(Object) resetContainer(C)
065   * @return the new container instance.
066   */
067  @CanIgnoreReturnValue
068  protected C resetContainer() {
069    return resetContainer(getSubjectGenerator().createTestSubject());
070  }
071
072  /**
073   * Replaces the existing container under test with a new container. This is useful when a single
074   * test method needs to create multiple containers while retaining the ability to use {@link
075   * #expectContents(Object[]) expectContents(E...)} and other convenience methods. The creation of
076   * multiple containers in a single method is discouraged in most cases, but it is vital to the
077   * iterator tests.
078   *
079   * @return the new container instance
080   * @param newValue the new container instance
081   */
082  @CanIgnoreReturnValue
083  protected C resetContainer(C newValue) {
084    container = newValue;
085    return container;
086  }
087
088  /**
089   * @see #expectContents(java.util.Collection)
090   * @param elements expected contents of {@link #container}
091   */
092  protected final void expectContents(E... elements) {
093    expectContents(Arrays.asList(elements));
094  }
095
096  /**
097   * Asserts that the collection under test contains exactly the given elements, respecting
098   * cardinality but not order. Subclasses may override this method to provide stronger assertions,
099   * e.g., to check ordering in lists, but realize that <strong>unless a test extends {@link
100   * com.google.common.collect.testing.testers.AbstractListTester AbstractListTester}, a call to
101   * {@code expectContents()} invokes this version</strong>.
102   *
103   * @param expected expected value of {@link #container}
104   */
105  /*
106   * TODO: improve this and other implementations and move out of this framework
107   * for wider use
108   *
109   * TODO: could we incorporate the overriding logic from AbstractListTester, by
110   * examining whether the features include KNOWN_ORDER?
111   */
112  protected void expectContents(Collection<E> expected) {
113    Helpers.assertEqualIgnoringOrder(expected, actualContents());
114  }
115
116  protected void expectUnchanged() {
117    expectContents(getOrderedElements());
118  }
119
120  /**
121   * Asserts that the collection under test contains exactly the elements it was initialized with
122   * plus the given elements, according to {@link #expectContents(java.util.Collection)}. In other
123   * words, for the default {@code expectContents()} implementation, the number of occurrences of
124   * each given element has increased by one since the test collection was created, and the number
125   * of occurrences of all other elements has not changed.
126   *
127   * <p>Note: This means that a test like the following will fail if {@code collection} is a {@code
128   * Set}:
129   *
130   * <pre>
131   * collection.add(existingElement);
132   * expectAdded(existingElement);</pre>
133   *
134   * <p>In this case, {@code collection} was not modified as a result of the {@code add()} call, and
135   * the test will fail because the number of occurrences of {@code existingElement} is unchanged.
136   *
137   * @param elements expected additional contents of {@link #container}
138   */
139  protected final void expectAdded(E... elements) {
140    List<E> expected = Helpers.copyToList(getSampleElements());
141    expected.addAll(Arrays.asList(elements));
142    expectContents(expected);
143  }
144
145  protected final void expectAdded(int index, E... elements) {
146    expectAdded(index, Arrays.asList(elements));
147  }
148
149  protected final void expectAdded(int index, Collection<E> elements) {
150    List<E> expected = Helpers.copyToList(getSampleElements());
151    expected.addAll(index, elements);
152    expectContents(expected);
153  }
154
155  /*
156   * TODO: if we're testing a list, we could check indexOf(). (Doing it in
157   * AbstractListTester isn't enough because many tests that run on lists don't
158   * extends AbstractListTester.) We could also iterate over all elements to
159   * verify absence
160   */
161  protected void expectMissing(E... elements) {
162    for (E element : elements) {
163      assertFalse("Should not contain " + element, actualContents().contains(element));
164    }
165  }
166
167  protected E[] createSamplesArray() {
168    E[] array = getSubjectGenerator().createArray(getNumElements());
169    getSampleElements().toArray(array);
170    return array;
171  }
172
173  protected E[] createOrderedArray() {
174    E[] array = getSubjectGenerator().createArray(getNumElements());
175    getOrderedElements().toArray(array);
176    return array;
177  }
178
179  public static class ArrayWithDuplicate<E extends @Nullable Object> {
180    public final E[] elements;
181    public final E duplicate;
182
183    private ArrayWithDuplicate(E[] elements, E duplicate) {
184      this.elements = elements;
185      this.duplicate = duplicate;
186    }
187  }
188
189  /**
190   * @return an array of the proper size with a duplicate element. The size must be at least three.
191   */
192  protected ArrayWithDuplicate<E> createArrayWithDuplicateElement() {
193    E[] elements = createSamplesArray();
194    E duplicate = elements[(elements.length / 2) - 1];
195    elements[(elements.length / 2) + 1] = duplicate;
196    return new ArrayWithDuplicate<>(elements, duplicate);
197  }
198
199  // Helper methods to improve readability of derived classes
200
201  protected int getNumElements() {
202    return getSubjectGenerator().getCollectionSize().getNumElements();
203  }
204
205  protected Collection<E> getSampleElements(int howMany) {
206    return getSubjectGenerator().getSampleElements(howMany);
207  }
208
209  protected Collection<E> getSampleElements() {
210    return getSampleElements(getNumElements());
211  }
212
213  /**
214   * Returns the {@linkplain #getSampleElements() sample elements} as ordered by {@link
215   * TestContainerGenerator#order(List)}. Tests should use this method only if they declare
216   * requirement {@link com.google.common.collect.testing.features.CollectionFeature#KNOWN_ORDER}.
217   */
218  protected List<E> getOrderedElements() {
219    List<E> list = new ArrayList<>();
220    for (E e : getSubjectGenerator().order(new ArrayList<E>(getSampleElements()))) {
221      list.add(e);
222    }
223    return Collections.unmodifiableList(list);
224  }
225
226  /**
227   * @return a suitable location for a null element, to use when initializing containers for tests
228   *     that involve a null element being present.
229   */
230  protected int getNullLocation() {
231    return getNumElements() / 2;
232  }
233
234  protected MinimalCollection<E> createDisjointCollection() {
235    return MinimalCollection.of(e3(), e4());
236  }
237
238  protected MinimalCollection<E> emptyCollection() {
239    return MinimalCollection.<E>of();
240  }
241
242  protected final E e0() {
243    return samples.e0();
244  }
245
246  protected final E e1() {
247    return samples.e1();
248  }
249
250  protected final E e2() {
251    return samples.e2();
252  }
253
254  protected final E e3() {
255    return samples.e3();
256  }
257
258  protected final E e4() {
259    return samples.e4();
260  }
261}