Home | History | Annotate | Download | only in testing
      1 /*
      2  * Copyright (C) 2008 The Guava Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.collect.testing;
     18 
     19 import com.google.common.annotations.GwtCompatible;
     20 
     21 import java.util.ArrayList;
     22 import java.util.Arrays;
     23 import java.util.Collection;
     24 import java.util.Collections;
     25 import java.util.List;
     26 
     27 /**
     28  * Base class for testers of classes (including {@link Collection}
     29  * and {@link java.util.Map Map}) that contain elements.
     30  *
     31  * @param <C> the type of the container
     32  * @param <E> the type of the container's contents
     33  *
     34  * @author George van den Driessche
     35  */
     36 @GwtCompatible
     37 public abstract class AbstractContainerTester<C, E>
     38     extends AbstractTester<OneSizeTestContainerGenerator<C, E>> {
     39   protected SampleElements<E> samples;
     40   protected C container;
     41 
     42   @Override public void setUp() throws Exception {
     43     super.setUp();
     44     samples = this.getSubjectGenerator().samples();
     45     resetContainer();
     46   }
     47 
     48   /**
     49    * @return the contents of the container under test, for use by
     50    * {@link #expectContents(Object[]) expectContents(E...)} and its friends.
     51    */
     52   protected abstract Collection<E> actualContents();
     53 
     54   /**
     55    * Replaces the existing container under test with a new container created
     56    * by the subject generator.
     57    *
     58    * @see #resetContainer(Object) resetContainer(C)
     59    *
     60    * @return the new container instance.
     61    */
     62   protected C resetContainer() {
     63     return resetContainer(getSubjectGenerator().createTestSubject());
     64   }
     65 
     66   /**
     67    * Replaces the existing container under test with a new container.
     68    * This is useful when a single test method needs to create multiple
     69    * containers while retaining the ability to use
     70    * {@link #expectContents(Object[]) expectContents(E...)} and other
     71    * convenience methods. The creation of multiple containers in a single
     72    * method is discouraged in most cases, but it is vital to the iterator tests.
     73    *
     74    * @return the new container instance
     75    * @param newValue the new container instance
     76    */
     77   protected C resetContainer(C newValue) {
     78     container = newValue;
     79     return container;
     80   }
     81 
     82   /**
     83    * @see #expectContents(java.util.Collection)
     84    *
     85    * @param elements expected contents of {@link #container}
     86    */
     87   protected final void expectContents(E... elements) {
     88     expectContents(Arrays.asList(elements));
     89   }
     90 
     91   /**
     92    * Asserts that the collection under test contains exactly the given elements,
     93    * respecting cardinality but not order. Subclasses may override this method
     94    * to provide stronger assertions, e.g., to check ordering in lists, but
     95    * realize that <strong>unless a test extends
     96    * {@link com.google.common.collect.testing.testers.AbstractListTester
     97    * AbstractListTester}, a call to {@code expectContents()} invokes this
     98    * version</strong>.
     99    *
    100    * @param expected expected value of {@link #container}
    101    */
    102   /*
    103    * TODO: improve this and other implementations and move out of this framework
    104    * for wider use
    105    *
    106    * TODO: could we incorporate the overriding logic from AbstractListTester, by
    107    * examining whether the features include KNOWN_ORDER?
    108    */
    109   protected void expectContents(Collection<E> expected) {
    110     Helpers.assertEqualIgnoringOrder(expected, actualContents());
    111   }
    112 
    113   protected void expectUnchanged() {
    114     expectContents(getOrderedElements());
    115   }
    116 
    117   /**
    118    * Asserts that the collection under test contains exactly the elements it was
    119    * initialized with plus the given elements, according to
    120    * {@link #expectContents(java.util.Collection)}. In other words, for the
    121    * default {@code expectContents()} implementation, the number of occurrences
    122    * of each given element has increased by one since the test collection was
    123    * created, and the number of occurrences of all other elements has not
    124    * changed.
    125    *
    126    * <p>Note: This means that a test like the following will fail if
    127    * {@code collection} is a {@code Set}:
    128    *
    129    * <pre>
    130    * collection.add(existingElement);
    131    * expectAdded(existingElement);</pre>
    132    *
    133    * <p>In this case, {@code collection} was not modified as a result of the
    134    * {@code add()} call, and the test will fail because the number of
    135    * 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,
    164           actualContents().contains(element));
    165     }
    166   }
    167 
    168   protected E[] createSamplesArray() {
    169     E[] array = getSubjectGenerator().createArray(getNumElements());
    170     getSampleElements().toArray(array);
    171     return array;
    172   }
    173 
    174   protected E[] createOrderedArray() {
    175     E[] array = getSubjectGenerator().createArray(getNumElements());
    176     getOrderedElements().toArray(array);
    177     return array;
    178   }
    179 
    180   public static class ArrayWithDuplicate<E> {
    181     public final E[] elements;
    182     public final E duplicate;
    183 
    184     private ArrayWithDuplicate(E[] elements, E duplicate) {
    185       this.elements = elements;
    186       this.duplicate = duplicate;
    187     }
    188   }
    189 
    190   /**
    191    * @return an array of the proper size with a duplicate element.
    192    * The size must be at least three.
    193    */
    194   protected ArrayWithDuplicate<E> createArrayWithDuplicateElement() {
    195     E[] elements = createSamplesArray();
    196     E duplicate = elements[(elements.length / 2) - 1];
    197     elements[(elements.length / 2) + 1] = duplicate;
    198     return new ArrayWithDuplicate<E>(elements, duplicate);
    199   }
    200 
    201   // Helper methods to improve readability of derived classes
    202 
    203   protected int getNumElements() {
    204     return getSubjectGenerator().getCollectionSize().getNumElements();
    205   }
    206 
    207   protected Collection<E> getSampleElements(int howMany) {
    208     return getSubjectGenerator().getSampleElements(howMany);
    209   }
    210 
    211   protected Collection<E> getSampleElements() {
    212     return getSampleElements(getNumElements());
    213   }
    214 
    215   /**
    216    * Returns the {@linkplain #getSampleElements() sample elements} as ordered by
    217    * {@link TestContainerGenerator#order(List)}. Tests should used this method
    218    * only if they declare requirement {@link
    219    * com.google.common.collect.testing.features.CollectionFeature#KNOWN_ORDER}.
    220    */
    221   protected List<E> getOrderedElements() {
    222     List<E> list = new ArrayList<E>();
    223     for (E e : getSubjectGenerator().order(
    224         new ArrayList<E>(getSampleElements()))) {
    225       list.add(e);
    226     }
    227     return Collections.unmodifiableList(list);
    228   }
    229 
    230   /**
    231    * @return a suitable location for a null element, to use when initializing
    232    * containers for tests that involve a null element being present.
    233    */
    234   protected int getNullLocation() {
    235     return getNumElements() / 2;
    236   }
    237 
    238   @SuppressWarnings("unchecked")
    239   protected MinimalCollection<E> createDisjointCollection() {
    240     return MinimalCollection.of(samples.e3, samples.e4);
    241   }
    242 
    243   @SuppressWarnings("unchecked")
    244   protected MinimalCollection<E> emptyCollection() {
    245     return MinimalCollection.<E>of();
    246   }
    247 }
    248