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