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 java.util.ArrayList;
     20 import java.util.Arrays;
     21 import java.util.Collection;
     22 import java.util.Collections;
     23 import java.util.List;
     24 
     25 /**
     26  * Base class for testers of classes (including {@link Collection}
     27  * and {@link java.util.Map Map}) that contain elements.
     28  *
     29  * <p>This class is GWT compatible.
     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 public abstract class AbstractContainerTester<C, E>
     37     extends AbstractTester<OneSizeTestContainerGenerator<C, E>> {
     38   protected SampleElements<E> samples;
     39   protected C container;
     40 
     41   @Override public void setUp() throws Exception {
     42     super.setUp();
     43     samples = this.getSubjectGenerator().samples();
     44     resetContainer();
     45   }
     46 
     47   /**
     48    * @return the contents of the container under test, for use by
     49    * {@link #expectContents(Object[]) expectContents(E...)} and its friends.
     50    */
     51   protected abstract Collection<E> actualContents();
     52 
     53   /**
     54    * Replaces the existing container under test with a new container created
     55    * by the subject generator.
     56    *
     57    * @see #resetContainer(Object) resetContainer(C)
     58    *
     59    * @return the new container instance.
     60    */
     61   protected C resetContainer() {
     62     return resetContainer(getSubjectGenerator().createTestSubject());
     63   }
     64 
     65   /**
     66    * Replaces the existing container under test with a new container.
     67    * This is useful when a single test method needs to create multiple
     68    * containers while retaining the ability to use
     69    * {@link #expectContents(Object[]) expectContents(E...)} and other
     70    * convenience methods. The creation of multiple containers in a single
     71    * method is discouraged in most cases, but it is vital to the iterator tests.
     72    *
     73    * @return the new container instance
     74    * @param newValue the new container instance
     75    */
     76   protected C resetContainer(C newValue) {
     77     container = newValue;
     78     return container;
     79   }
     80 
     81   /**
     82    * @see #expectContents(java.util.Collection)
     83    *
     84    * @param elements expected contents of {@link #container}
     85    */
     86   protected final void expectContents(E... elements) {
     87     expectContents(Arrays.asList(elements));
     88   }
     89 
     90   /**
     91    * Asserts that the collection under test contains exactly the given elements,
     92    * respecting cardinality but not order. Subclasses may override this method
     93    * to provide stronger assertions, e.g., to check ordering in lists, but
     94    * realize that <strong>unless a test extends
     95    * {@link com.google.common.collect.testing.testers.AbstractListTester
     96    * AbstractListTester}, a call to {@code expectContents()} invokes this
     97    * version</strong>.
     98    *
     99    * @param expected expected value of {@link #container}
    100    */
    101   /*
    102    * TODO: improve this and other implementations and move out of this framework
    103    * for wider use
    104    *
    105    * TODO: could we incorporate the overriding logic from AbstractListTester, by
    106    * examining whether the features include KNOWN_ORDER?
    107    */
    108   protected void expectContents(Collection<E> expected) {
    109     Helpers.assertEqualIgnoringOrder(expected, actualContents());
    110   }
    111 
    112   protected void expectUnchanged() {
    113     expectContents(getSampleElements());
    114   }
    115 
    116   /**
    117    * Asserts that the collection under test contains exactly the elements it was
    118    * initialized with plus the given elements, according to
    119    * {@link #expectContents(java.util.Collection)}. In other words, for the
    120    * default {@code expectContents()} implementation, the number of occurrences
    121    * of each given element has increased by one since the test collection was
    122    * created, and the number of occurrences of all other elements has not
    123    * changed.
    124    *
    125    * <p>Note: This means that a test like the following will fail if
    126    * {@code collection} is a {@code Set}:
    127    *
    128    * <pre>
    129    * collection.add(existingElement);
    130    * expectAdded(existingElement);</pre>
    131    *
    132    * In this case, {@code collection} was not modified as a result of the
    133    * {@code add()} call, and the test will fail because the number of
    134    * occurrences of {@code existingElement} is unchanged.
    135    *
    136    * @param elements expected additional contents of {@link #container}
    137    */
    138   protected final void expectAdded(E... elements) {
    139     List<E> expected = Helpers.copyToList(getSampleElements());
    140     expected.addAll(Arrays.asList(elements));
    141     expectContents(expected);
    142   }
    143 
    144   protected final void expectAdded(int index, E... elements) {
    145     expectAdded(index, Arrays.asList(elements));
    146   }
    147 
    148   protected final void expectAdded(int index, Collection<E> elements) {
    149     List<E> expected = Helpers.copyToList(getSampleElements());
    150     expected.addAll(index, elements);
    151     expectContents(expected);
    152   }
    153 
    154   /*
    155    * TODO: if we're testing a list, we could check indexOf(). (Doing it in
    156    * AbstractListTester isn't enough because many tests that run on lists don't
    157    * extends AbstractListTester.) We could also iterate over all elements to
    158    * verify absence
    159    */
    160   protected void expectMissing(E... elements) {
    161     for (E element : elements) {
    162       assertFalse("Should not contain " + element,
    163           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   public static class ArrayWithDuplicate<E> {
    174     public final E[] elements;
    175     public final E duplicate;
    176 
    177     private ArrayWithDuplicate(E[] elements, E duplicate) {
    178       this.elements = elements;
    179       this.duplicate = duplicate;
    180     }
    181   }
    182 
    183   /**
    184    * @return an array of the proper size with a duplicate element.
    185    * 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
    210    * {@link TestContainerGenerator#order(List)}. Tests should used this method
    211    * only if they declare requirement {@link
    212    * com.google.common.collect.testing.features.CollectionFeature#KNOWN_ORDER}.
    213    */
    214   protected List<E> getOrderedElements() {
    215     List<E> list = new ArrayList<E>();
    216     for (E e : getSubjectGenerator().order(
    217         new ArrayList<E>(getSampleElements()))) {
    218       list.add(e);
    219     }
    220     return Collections.unmodifiableList(list);
    221   }
    222 
    223   /**
    224    * @return a suitable location for a null element, to use when initializing
    225    * containers for tests that involve a null element being present.
    226    */
    227   protected int getNullLocation() {
    228     return getNumElements() / 2;
    229   }
    230 
    231   @SuppressWarnings("unchecked")
    232   protected MinimalCollection<E> createDisjointCollection() {
    233     return MinimalCollection.of(samples.e3, samples.e4);
    234   }
    235 
    236   @SuppressWarnings("unchecked")
    237   protected MinimalCollection<E> emptyCollection() {
    238     return MinimalCollection.<E>of();
    239   }
    240 }
    241