1 /* 2 * Copyright (C) 2009 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 static junit.framework.Assert.assertEquals; 20 import static junit.framework.Assert.assertFalse; 21 import static junit.framework.Assert.assertTrue; 22 23 import junit.framework.Assert; 24 import junit.framework.AssertionFailedError; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Collection; 29 import java.util.Collections; 30 import java.util.Comparator; 31 import java.util.Iterator; 32 import java.util.LinkedHashSet; 33 import java.util.List; 34 import java.util.ListIterator; 35 import java.util.Map; 36 import java.util.Map.Entry; 37 import java.util.Set; 38 39 // This class is GWT compatible. 40 public class Helpers { 41 // Clone of Objects.equal equal(Object a, Object b)42 static boolean equal(Object a, Object b) { 43 return a == b || (a != null && a.equals(b)); 44 } 45 46 // Clone of Lists.newArrayList copyToList(Iterable<? extends E> elements)47 public static <E> List<E> copyToList(Iterable<? extends E> elements) { 48 List<E> list = new ArrayList<E>(); 49 addAll(list, elements); 50 return list; 51 } 52 copyToList(E[] elements)53 public static <E> List<E> copyToList(E[] elements) { 54 return copyToList(Arrays.asList(elements)); 55 } 56 57 // Clone of Sets.newLinkedHashSet copyToSet(Iterable<? extends E> elements)58 public static <E> Set<E> copyToSet(Iterable<? extends E> elements) { 59 Set<E> set = new LinkedHashSet<E>(); 60 addAll(set, elements); 61 return set; 62 } 63 copyToSet(E[] elements)64 public static <E> Set<E> copyToSet(E[] elements) { 65 return copyToSet(Arrays.asList(elements)); 66 } 67 68 // Would use Maps.immutableEntry mapEntry(K key, V value)69 static <K, V> Entry<K, V> mapEntry(K key, V value) { 70 return Collections.singletonMap(key, value).entrySet().iterator().next(); 71 } 72 assertEqualIgnoringOrder( Iterable<?> expected, Iterable<?> actual)73 public static void assertEqualIgnoringOrder( 74 Iterable<?> expected, Iterable<?> actual) { 75 List<?> exp = copyToList(expected); 76 List<?> act = copyToList(actual); 77 String actString = act.toString(); 78 79 // Of course we could take pains to give the complete description of the 80 // problem on any failure. 81 82 // Yeah it's n^2. 83 for (Object object : exp) { 84 if (!act.remove(object)) { 85 Assert.fail("did not contain expected element " + object + ", " 86 + "expected = " + exp + ", actual = " + actString); 87 } 88 } 89 assertTrue("unexpected elements: " + act, act.isEmpty()); 90 } 91 assertContentsAnyOrder( Iterable<?> actual, Object... expected)92 public static void assertContentsAnyOrder( 93 Iterable<?> actual, Object... expected) { 94 assertEqualIgnoringOrder(Arrays.asList(expected), actual); 95 } 96 addAll( Collection<E> addTo, Iterable<? extends E> elementsToAdd)97 public static <E> boolean addAll( 98 Collection<E> addTo, Iterable<? extends E> elementsToAdd) { 99 boolean modified = false; 100 for (E e : elementsToAdd) { 101 modified |= addTo.add(e); 102 } 103 return modified; 104 } 105 reverse(final List<T> list)106 static <T> Iterable<T> reverse(final List<T> list) { 107 return new Iterable<T>() { 108 @Override 109 public Iterator<T> iterator() { 110 final ListIterator<T> listIter = list.listIterator(list.size()); 111 return new Iterator<T>() { 112 @Override 113 public boolean hasNext() { 114 return listIter.hasPrevious(); 115 } 116 @Override 117 public T next() { 118 return listIter.previous(); 119 } 120 @Override 121 public void remove() { 122 listIter.remove(); 123 } 124 }; 125 } 126 }; 127 } 128 129 static <T> Iterator<T> cycle(final Iterable<T> iterable) { 130 return new Iterator<T>() { 131 Iterator<T> iterator = Collections.<T>emptySet().iterator(); 132 @Override 133 public boolean hasNext() { 134 return true; 135 } 136 @Override 137 public T next() { 138 if (!iterator.hasNext()) { 139 iterator = iterable.iterator(); 140 } 141 return iterator.next(); 142 } 143 @Override 144 public void remove() { 145 throw new UnsupportedOperationException(); 146 } 147 }; 148 } 149 150 static <T> T get(Iterator<T> iterator, int position) { 151 for (int i = 0; i < position; i++) { 152 iterator.next(); 153 } 154 return iterator.next(); 155 } 156 157 static void fail(Throwable cause, Object message) { 158 AssertionFailedError assertionFailedError = 159 new AssertionFailedError(String.valueOf(message)); 160 assertionFailedError.initCause(cause); 161 throw assertionFailedError; 162 } 163 164 public static <K, V> Comparator<Entry<K, V>> entryComparator( 165 final Comparator<? super K> keyComparator) { 166 return new Comparator<Entry<K, V>>() { 167 @Override 168 public int compare(Entry<K, V> a, Entry<K, V> b) { 169 return keyComparator.compare(a.getKey(), b.getKey()); 170 } 171 }; 172 } 173 174 public static <T> void testComparator( 175 Comparator<? super T> comparator, T... valuesInExpectedOrder) { 176 testComparator(comparator, Arrays.asList(valuesInExpectedOrder)); 177 } 178 179 public static <T> void testComparator( 180 Comparator<? super T> comparator, List<T> valuesInExpectedOrder) { 181 // This does an O(n^2) test of all pairs of values in both orders 182 for (int i = 0; i < valuesInExpectedOrder.size(); i++) { 183 T t = valuesInExpectedOrder.get(i); 184 185 for (int j = 0; j < i; j++) { 186 T lesser = valuesInExpectedOrder.get(j); 187 assertTrue(comparator + ".compare(" + lesser + ", " + t + ")", 188 comparator.compare(lesser, t) < 0); 189 } 190 191 assertEquals(comparator + ".compare(" + t + ", " + t + ")", 192 0, comparator.compare(t, t)); 193 194 for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) { 195 T greater = valuesInExpectedOrder.get(j); 196 assertTrue(comparator + ".compare(" + greater + ", " + t + ")", 197 comparator.compare(greater, t) > 0); 198 } 199 } 200 } 201 202 public static <T extends Comparable<? super T>> void testCompareToAndEquals( 203 List<T> valuesInExpectedOrder) { 204 // This does an O(n^2) test of all pairs of values in both orders 205 for (int i = 0; i < valuesInExpectedOrder.size(); i++) { 206 T t = valuesInExpectedOrder.get(i); 207 208 for (int j = 0; j < i; j++) { 209 T lesser = valuesInExpectedOrder.get(j); 210 assertTrue(lesser + ".compareTo(" + t + ')', lesser.compareTo(t) < 0); 211 assertFalse(lesser.equals(t)); 212 } 213 214 assertEquals(t + ".compareTo(" + t + ')', 0, t.compareTo(t)); 215 assertTrue(t.equals(t)); 216 217 for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) { 218 T greater = valuesInExpectedOrder.get(j); 219 assertTrue(greater + ".compareTo(" + t + ')', greater.compareTo(t) > 0); 220 assertFalse(greater.equals(t)); 221 } 222 } 223 } 224 225 /** 226 * Returns a collection that simulates concurrent modification by 227 * having its size method return incorrect values. This is useful 228 * for testing methods that must treat the return value from size() 229 * as a hint only. 230 * 231 * @param delta the difference between the true size of the 232 * collection and the values returned by the size method 233 */ 234 public static <T> Collection<T> misleadingSizeCollection(final int delta) { 235 // It would be nice to be able to return a real concurrent 236 // collection like ConcurrentLinkedQueue, so that e.g. concurrent 237 // iteration would work, but that would not be GWT-compatible. 238 return new ArrayList<T>() { 239 @Override public int size() { return Math.max(0, super.size() + delta); } 240 }; 241 } 242 243 /** 244 * Returns a "nefarious" map entry with the specified key and value, 245 * meaning an entry that is suitable for testing that map entries cannot be 246 * modified via a nefarious implementation of equals. This is used for testing 247 * unmodifiable collections of map entries; for example, it should not be 248 * possible to access the raw (modifiable) map entry via a nefarious equals 249 * method. 250 */ 251 public static <K, V> Map.Entry<K, V> nefariousMapEntry(final K key, 252 final V value) { 253 return new Map.Entry<K, V>() { 254 @Override public K getKey() { 255 return key; 256 } 257 @Override public V getValue() { 258 return value; 259 } 260 @Override public V setValue(V value) { 261 throw new UnsupportedOperationException(); 262 } 263 @SuppressWarnings("unchecked") 264 @Override public boolean equals(Object o) { 265 if (o instanceof Map.Entry<?, ?>) { 266 Map.Entry<K, V> e = (Map.Entry<K, V>) o; 267 e.setValue(value); // muhahaha! 268 269 return equal(this.getKey(), e.getKey()) 270 && equal(this.getValue(), e.getValue()); 271 } 272 return false; 273 } 274 275 @Override public int hashCode() { 276 K k = getKey(); 277 V v = getValue(); 278 return ((k == null) ? 279 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode()); 280 } 281 282 /** 283 * Returns a string representation of the form <code>{key}={value}</code>. 284 */ 285 @Override public String toString() { 286 return getKey() + "=" + getValue(); 287 } 288 }; 289 } 290 } 291