001/* 002 * Copyright (C) 2008 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect.testing; 018 019import static com.google.common.collect.testing.Helpers.assertEqualIgnoringOrder; 020import static com.google.common.collect.testing.Helpers.copyToList; 021import static java.util.Arrays.asList; 022import static java.util.Collections.unmodifiableList; 023 024import com.google.common.annotations.GwtCompatible; 025import com.google.errorprone.annotations.CanIgnoreReturnValue; 026import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; 027import java.util.ArrayList; 028import java.util.Collection; 029import java.util.List; 030import org.checkerframework.checker.nullness.qual.Nullable; 031import org.junit.Ignore; 032 033/** 034 * Base class for testers of classes (including {@link Collection} and {@link java.util.Map Map}) 035 * that contain elements. 036 * 037 * @param <C> the type of the container 038 * @param <E> the type of the container's contents 039 * @author George van den Driessche 040 */ 041@GwtCompatible 042@Ignore("test runners must not instantiate and run this directly, only via suites we build") 043// @Ignore affects the Android test runner, which respects JUnit 4 annotations on JUnit 3 tests. 044@SuppressWarnings("JUnit4ClassUsedInJUnit3") 045@ElementTypesAreNonnullByDefault 046public abstract class AbstractContainerTester<C, E extends @Nullable Object> 047 extends AbstractTester<OneSizeTestContainerGenerator<C, E>> { 048 protected SampleElements<E> samples; 049 protected C container; 050 051 @Override 052 @OverridingMethodsMustInvokeSuper 053 public void setUp() throws Exception { 054 super.setUp(); 055 samples = this.getSubjectGenerator().samples(); 056 resetContainer(); 057 } 058 059 /** 060 * @return the contents of the container under test, for use by {@link #expectContents(Object[]) 061 * expectContents(E...)} and its friends. 062 */ 063 protected abstract Collection<E> actualContents(); 064 065 /** 066 * Replaces the existing container under test with a new container created by the subject 067 * generator. 068 * 069 * @see #resetContainer(Object) resetContainer(C) 070 * @return the new container instance. 071 */ 072 @CanIgnoreReturnValue 073 protected C resetContainer() { 074 return resetContainer(getSubjectGenerator().createTestSubject()); 075 } 076 077 /** 078 * Replaces the existing container under test with a new container. This is useful when a single 079 * test method needs to create multiple containers while retaining the ability to use {@link 080 * #expectContents(Object[]) expectContents(E...)} and other convenience methods. The creation of 081 * multiple containers in a single method is discouraged in most cases, but it is vital to the 082 * iterator tests. 083 * 084 * @return the new container instance 085 * @param newValue the new container instance 086 */ 087 @CanIgnoreReturnValue 088 protected C resetContainer(C newValue) { 089 container = newValue; 090 return container; 091 } 092 093 /** 094 * @see #expectContents(java.util.Collection) 095 * @param elements expected contents of {@link #container} 096 */ 097 protected final void expectContents(E... elements) { 098 expectContents(asList(elements)); 099 } 100 101 /** 102 * Asserts that the collection under test contains exactly the given elements, respecting 103 * cardinality but not order. Subclasses may override this method to provide stronger assertions, 104 * e.g., to check ordering in lists, but realize that <strong>unless a test extends {@link 105 * com.google.common.collect.testing.testers.AbstractListTester AbstractListTester}, a call to 106 * {@code expectContents()} invokes this version</strong>. 107 * 108 * @param expected expected value of {@link #container} 109 */ 110 /* 111 * TODO: improve this and other implementations and move out of this framework 112 * for wider use 113 * 114 * TODO: could we incorporate the overriding logic from AbstractListTester, by 115 * examining whether the features include KNOWN_ORDER? 116 */ 117 protected void expectContents(Collection<E> expected) { 118 assertEqualIgnoringOrder(expected, actualContents()); 119 } 120 121 protected void expectUnchanged() { 122 expectContents(getOrderedElements()); 123 } 124 125 /** 126 * Asserts that the collection under test contains exactly the elements it was initialized with 127 * plus the given elements, according to {@link #expectContents(java.util.Collection)}. In other 128 * words, for the default {@code expectContents()} implementation, the number of occurrences of 129 * each given element has increased by one since the test collection was created, and the number 130 * of occurrences of all other elements has not changed. 131 * 132 * <p>Note: This means that a test like the following will fail if {@code collection} is a {@code 133 * Set}: 134 * 135 * <pre> 136 * collection.add(existingElement); 137 * expectAdded(existingElement);</pre> 138 * 139 * <p>In this case, {@code collection} was not modified as a result of the {@code add()} call, and 140 * the test will fail because the number of occurrences of {@code existingElement} is unchanged. 141 * 142 * @param elements expected additional contents of {@link #container} 143 */ 144 protected final void expectAdded(E... elements) { 145 List<E> expected = copyToList(getSampleElements()); 146 expected.addAll(asList(elements)); 147 expectContents(expected); 148 } 149 150 protected final void expectAdded(int index, E... elements) { 151 expectAdded(index, asList(elements)); 152 } 153 154 protected final void expectAdded(int index, Collection<E> elements) { 155 List<E> expected = copyToList(getSampleElements()); 156 expected.addAll(index, elements); 157 expectContents(expected); 158 } 159 160 /* 161 * TODO: if we're testing a list, we could check indexOf(). (Doing it in 162 * AbstractListTester isn't enough because many tests that run on lists don't 163 * extends AbstractListTester.) We could also iterate over all elements to 164 * verify absence 165 */ 166 protected void expectMissing(E... elements) { 167 for (E element : elements) { 168 assertFalse("Should not contain " + element, actualContents().contains(element)); 169 } 170 } 171 172 protected E[] createSamplesArray() { 173 E[] array = getSubjectGenerator().createArray(getNumElements()); 174 getSampleElements().toArray(array); 175 return array; 176 } 177 178 protected E[] createOrderedArray() { 179 E[] array = getSubjectGenerator().createArray(getNumElements()); 180 getOrderedElements().toArray(array); 181 return array; 182 } 183 184 public static class ArrayWithDuplicate<E extends @Nullable Object> { 185 public final E[] elements; 186 public final E duplicate; 187 188 private ArrayWithDuplicate(E[] elements, E duplicate) { 189 this.elements = elements; 190 this.duplicate = duplicate; 191 } 192 } 193 194 /** 195 * @return an array of the proper size with a duplicate element. The size must be at least three. 196 */ 197 protected ArrayWithDuplicate<E> createArrayWithDuplicateElement() { 198 E[] elements = createSamplesArray(); 199 E duplicate = elements[(elements.length / 2) - 1]; 200 elements[(elements.length / 2) + 1] = duplicate; 201 return new ArrayWithDuplicate<>(elements, duplicate); 202 } 203 204 // Helper methods to improve readability of derived classes 205 206 protected int getNumElements() { 207 return getSubjectGenerator().getCollectionSize().getNumElements(); 208 } 209 210 protected Collection<E> getSampleElements(int howMany) { 211 return getSubjectGenerator().getSampleElements(howMany); 212 } 213 214 protected Collection<E> getSampleElements() { 215 return getSampleElements(getNumElements()); 216 } 217 218 /** 219 * Returns the {@linkplain #getSampleElements() sample elements} as ordered by {@link 220 * TestContainerGenerator#order(List)}. Tests should use this method only if they declare 221 * requirement {@link com.google.common.collect.testing.features.CollectionFeature#KNOWN_ORDER}. 222 */ 223 protected List<E> getOrderedElements() { 224 List<E> list = new ArrayList<>(); 225 for (E e : getSubjectGenerator().order(new ArrayList<E>(getSampleElements()))) { 226 list.add(e); 227 } 228 return unmodifiableList(list); 229 } 230 231 /** 232 * @return a suitable location for a null element, to use when initializing containers for tests 233 * that involve a null element being present. 234 */ 235 protected int getNullLocation() { 236 return getNumElements() / 2; 237 } 238 239 protected MinimalCollection<E> createDisjointCollection() { 240 return MinimalCollection.of(e3(), e4()); 241 } 242 243 protected MinimalCollection<E> emptyCollection() { 244 return MinimalCollection.<E>of(); 245 } 246 247 protected final E e0() { 248 return samples.e0(); 249 } 250 251 protected final E e1() { 252 return samples.e1(); 253 } 254 255 protected final E e2() { 256 return samples.e2(); 257 } 258 259 protected final E e3() { 260 return samples.e3(); 261 } 262 263 protected final E e4() { 264 return samples.e4(); 265 } 266}