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