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 17package com.google.common.collect.testing; 18 19import com.google.common.annotations.GwtCompatible; 20 21import java.util.ArrayList; 22import java.util.Arrays; 23import java.util.Collection; 24import java.util.Collections; 25import 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 37public 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