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