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 import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; 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 import org.junit.Ignore; 27 28 /** 29 * Base class for testers of classes (including {@link Collection} and {@link java.util.Map Map}) 30 * that contain elements. 31 * 32 * @param <C> the type of the container 33 * @param <E> the type of the container's contents 34 * @author George van den Driessche 35 */ 36 @GwtCompatible 37 @Ignore // Affects only Android test runner, which respects JUnit 4 annotations on JUnit 3 tests. 38 public abstract class AbstractContainerTester<C, E> 39 extends AbstractTester<OneSizeTestContainerGenerator<C, E>> { 40 protected SampleElements<E> samples; 41 protected C container; 42 43 @Override 44 @OverridingMethodsMustInvokeSuper setUp()45 public void setUp() throws Exception { 46 super.setUp(); 47 samples = this.getSubjectGenerator().samples(); 48 resetContainer(); 49 } 50 51 /** 52 * @return the contents of the container under test, for use by {@link #expectContents(Object[]) 53 * expectContents(E...)} and its friends. 54 */ actualContents()55 protected abstract Collection<E> actualContents(); 56 57 /** 58 * Replaces the existing container under test with a new container created by the subject 59 * generator. 60 * 61 * @see #resetContainer(Object) resetContainer(C) 62 * @return the new container instance. 63 */ resetContainer()64 protected C resetContainer() { 65 return resetContainer(getSubjectGenerator().createTestSubject()); 66 } 67 68 /** 69 * Replaces the existing container under test with a new container. This is useful when a single 70 * test method needs to create multiple containers while retaining the ability to use {@link 71 * #expectContents(Object[]) expectContents(E...)} and other convenience methods. The creation of 72 * multiple containers in a single method is discouraged in most cases, but it is vital to the 73 * iterator tests. 74 * 75 * @return the new container instance 76 * @param newValue the new container instance 77 */ resetContainer(C newValue)78 protected C resetContainer(C newValue) { 79 container = newValue; 80 return container; 81 } 82 83 /** 84 * @see #expectContents(java.util.Collection) 85 * @param elements expected contents of {@link #container} 86 */ expectContents(E... elements)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, respecting 93 * cardinality but not order. Subclasses may override this method to provide stronger assertions, 94 * e.g., to check ordering in lists, but realize that <strong>unless a test extends {@link 95 * com.google.common.collect.testing.testers.AbstractListTester AbstractListTester}, a call to 96 * {@code expectContents()} invokes this version</strong>. 97 * 98 * @param expected expected value of {@link #container} 99 */ 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 */ expectContents(Collection<E> expected)107 protected void expectContents(Collection<E> expected) { 108 Helpers.assertEqualIgnoringOrder(expected, actualContents()); 109 } 110 expectUnchanged()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 */ expectAdded(E... elements)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 expectAdded(int index, E... elements)140 protected final void expectAdded(int index, E... elements) { 141 expectAdded(index, Arrays.asList(elements)); 142 } 143 expectAdded(int index, Collection<E> elements)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 */ expectMissing(E... elements)156 protected void expectMissing(E... elements) { 157 for (E element : elements) { 158 assertFalse("Should not contain " + element, actualContents().contains(element)); 159 } 160 } 161 createSamplesArray()162 protected E[] createSamplesArray() { 163 E[] array = getSubjectGenerator().createArray(getNumElements()); 164 getSampleElements().toArray(array); 165 return array; 166 } 167 createOrderedArray()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 ArrayWithDuplicate(E[] elements, E duplicate)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 */ createArrayWithDuplicateElement()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 getNumElements()196 protected int getNumElements() { 197 return getSubjectGenerator().getCollectionSize().getNumElements(); 198 } 199 getSampleElements(int howMany)200 protected Collection<E> getSampleElements(int howMany) { 201 return getSubjectGenerator().getSampleElements(howMany); 202 } 203 getSampleElements()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 */ getOrderedElements()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 */ getNullLocation()225 protected int getNullLocation() { 226 return getNumElements() / 2; 227 } 228 229 @SuppressWarnings("unchecked") createDisjointCollection()230 protected MinimalCollection<E> createDisjointCollection() { 231 return MinimalCollection.of(e3(), e4()); 232 } 233 234 @SuppressWarnings("unchecked") emptyCollection()235 protected MinimalCollection<E> emptyCollection() { 236 return MinimalCollection.<E>of(); 237 } 238 e0()239 protected final E e0() { 240 return samples.e0(); 241 } 242 e1()243 protected final E e1() { 244 return samples.e1(); 245 } 246 e2()247 protected final E e2() { 248 return samples.e2(); 249 } 250 e3()251 protected final E e3() { 252 return samples.e3(); 253 } 254 e4()255 protected final E e4() { 256 return samples.e4(); 257 } 258 } 259