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