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