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