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 java.util.Collections.sort; 20 import static junit.framework.Assert.assertEquals; 21 import static junit.framework.Assert.assertFalse; 22 import static junit.framework.Assert.assertTrue; 23 24 import com.google.common.annotations.GwtCompatible; 25 import com.google.common.annotations.GwtIncompatible; 26 import java.io.Serializable; 27 import java.lang.reflect.Method; 28 import java.util.ArrayList; 29 import java.util.Arrays; 30 import java.util.Collection; 31 import java.util.Collections; 32 import java.util.Comparator; 33 import java.util.Iterator; 34 import java.util.LinkedHashSet; 35 import java.util.List; 36 import java.util.ListIterator; 37 import java.util.Map; 38 import java.util.Map.Entry; 39 import java.util.Set; 40 import junit.framework.Assert; 41 import junit.framework.AssertionFailedError; 42 43 @GwtCompatible(emulated = true) 44 public class Helpers { 45 // Clone of Objects.equal equal(Object a, Object b)46 static boolean equal(Object a, Object b) { 47 return a == b || (a != null && a.equals(b)); 48 } 49 50 // Clone of Lists.newArrayList copyToList(Iterable<? extends E> elements)51 public static <E> List<E> copyToList(Iterable<? extends E> elements) { 52 List<E> list = new ArrayList<E>(); 53 addAll(list, elements); 54 return list; 55 } 56 copyToList(E[] elements)57 public static <E> List<E> copyToList(E[] elements) { 58 return copyToList(Arrays.asList(elements)); 59 } 60 61 // Clone of Sets.newLinkedHashSet copyToSet(Iterable<? extends E> elements)62 public static <E> Set<E> copyToSet(Iterable<? extends E> elements) { 63 Set<E> set = new LinkedHashSet<E>(); 64 addAll(set, elements); 65 return set; 66 } 67 copyToSet(E[] elements)68 public static <E> Set<E> copyToSet(E[] elements) { 69 return copyToSet(Arrays.asList(elements)); 70 } 71 72 // Would use Maps.immutableEntry mapEntry(K key, V value)73 public static <K, V> Entry<K, V> mapEntry(K key, V value) { 74 return Collections.singletonMap(key, value).entrySet().iterator().next(); 75 } 76 isEmpty(Iterable<?> iterable)77 private static boolean isEmpty(Iterable<?> iterable) { 78 return iterable instanceof Collection 79 ? ((Collection<?>) iterable).isEmpty() 80 : !iterable.iterator().hasNext(); 81 } 82 assertEmpty(Iterable<?> iterable)83 public static void assertEmpty(Iterable<?> iterable) { 84 if (!isEmpty(iterable)) { 85 Assert.fail("Not true that " + iterable + " is empty"); 86 } 87 } 88 assertEmpty(Map<?, ?> map)89 public static void assertEmpty(Map<?, ?> map) { 90 if (!map.isEmpty()) { 91 Assert.fail("Not true that " + map + " is empty"); 92 } 93 } 94 assertEqualInOrder(Iterable<?> expected, Iterable<?> actual)95 public static void assertEqualInOrder(Iterable<?> expected, Iterable<?> actual) { 96 Iterator<?> expectedIter = expected.iterator(); 97 Iterator<?> actualIter = actual.iterator(); 98 99 while (expectedIter.hasNext() && actualIter.hasNext()) { 100 if (!equal(expectedIter.next(), actualIter.next())) { 101 Assert.fail( 102 "contents were not equal and in the same order: " 103 + "expected = " 104 + expected 105 + ", actual = " 106 + actual); 107 } 108 } 109 110 if (expectedIter.hasNext() || actualIter.hasNext()) { 111 // actual either had too few or too many elements 112 Assert.fail( 113 "contents were not equal and in the same order: " 114 + "expected = " 115 + expected 116 + ", actual = " 117 + actual); 118 } 119 } 120 assertContentsInOrder(Iterable<?> actual, Object... expected)121 public static void assertContentsInOrder(Iterable<?> actual, Object... expected) { 122 assertEqualInOrder(Arrays.asList(expected), actual); 123 } 124 assertEqualIgnoringOrder(Iterable<?> expected, Iterable<?> actual)125 public static void assertEqualIgnoringOrder(Iterable<?> expected, Iterable<?> actual) { 126 List<?> exp = copyToList(expected); 127 List<?> act = copyToList(actual); 128 String actString = act.toString(); 129 130 // Of course we could take pains to give the complete description of the 131 // problem on any failure. 132 133 // Yeah it's n^2. 134 for (Object object : exp) { 135 if (!act.remove(object)) { 136 Assert.fail( 137 "did not contain expected element " 138 + object 139 + ", " 140 + "expected = " 141 + exp 142 + ", actual = " 143 + actString); 144 } 145 } 146 assertTrue("unexpected elements: " + act, act.isEmpty()); 147 } 148 assertContentsAnyOrder(Iterable<?> actual, Object... expected)149 public static void assertContentsAnyOrder(Iterable<?> actual, Object... expected) { 150 assertEqualIgnoringOrder(Arrays.asList(expected), actual); 151 } 152 assertContains(Iterable<?> actual, Object expected)153 public static void assertContains(Iterable<?> actual, Object expected) { 154 boolean contained = false; 155 if (actual instanceof Collection) { 156 contained = ((Collection<?>) actual).contains(expected); 157 } else { 158 for (Object o : actual) { 159 if (equal(o, expected)) { 160 contained = true; 161 break; 162 } 163 } 164 } 165 166 if (!contained) { 167 Assert.fail("Not true that " + actual + " contains " + expected); 168 } 169 } 170 assertContainsAllOf(Iterable<?> actual, Object... expected)171 public static void assertContainsAllOf(Iterable<?> actual, Object... expected) { 172 List<Object> expectedList = new ArrayList<>(); 173 expectedList.addAll(Arrays.asList(expected)); 174 175 for (Object o : actual) { 176 expectedList.remove(o); 177 } 178 179 if (!expectedList.isEmpty()) { 180 Assert.fail("Not true that " + actual + " contains all of " + Arrays.asList(expected)); 181 } 182 } 183 addAll(Collection<E> addTo, Iterable<? extends E> elementsToAdd)184 public static <E> boolean addAll(Collection<E> addTo, Iterable<? extends E> elementsToAdd) { 185 boolean modified = false; 186 for (E e : elementsToAdd) { 187 modified |= addTo.add(e); 188 } 189 return modified; 190 } 191 reverse(final List<T> list)192 static <T> Iterable<T> reverse(final List<T> list) { 193 return new Iterable<T>() { 194 @Override 195 public Iterator<T> iterator() { 196 final ListIterator<T> listIter = list.listIterator(list.size()); 197 return new Iterator<T>() { 198 @Override 199 public boolean hasNext() { 200 return listIter.hasPrevious(); 201 } 202 203 @Override 204 public T next() { 205 return listIter.previous(); 206 } 207 208 @Override 209 public void remove() { 210 listIter.remove(); 211 } 212 }; 213 } 214 }; 215 } 216 217 static <T> Iterator<T> cycle(final Iterable<T> iterable) { 218 return new Iterator<T>() { 219 Iterator<T> iterator = Collections.<T>emptySet().iterator(); 220 221 @Override 222 public boolean hasNext() { 223 return true; 224 } 225 226 @Override 227 public T next() { 228 if (!iterator.hasNext()) { 229 iterator = iterable.iterator(); 230 } 231 return iterator.next(); 232 } 233 234 @Override 235 public void remove() { 236 throw new UnsupportedOperationException(); 237 } 238 }; 239 } 240 241 static <T> T get(Iterator<T> iterator, int position) { 242 for (int i = 0; i < position; i++) { 243 iterator.next(); 244 } 245 return iterator.next(); 246 } 247 248 static void fail(Throwable cause, Object message) { 249 AssertionFailedError assertionFailedError = new AssertionFailedError(String.valueOf(message)); 250 assertionFailedError.initCause(cause); 251 throw assertionFailedError; 252 } 253 254 public static <K, V> Comparator<Entry<K, V>> entryComparator( 255 final Comparator<? super K> keyComparator) { 256 return new Comparator<Entry<K, V>>() { 257 @Override 258 @SuppressWarnings("unchecked") // no less safe than putting it in the map! 259 public int compare(Entry<K, V> a, Entry<K, V> b) { 260 return (keyComparator == null) 261 ? ((Comparable) a.getKey()).compareTo(b.getKey()) 262 : keyComparator.compare(a.getKey(), b.getKey()); 263 } 264 }; 265 } 266 267 /** 268 * Asserts that all pairs of {@code T} values within {@code valuesInExpectedOrder} are ordered 269 * consistently between their order within {@code valuesInExpectedOrder} and the order implied by 270 * the given {@code comparator}. 271 * 272 * @see #testComparator(Comparator, List) 273 */ 274 public static <T> void testComparator( 275 Comparator<? super T> comparator, T... valuesInExpectedOrder) { 276 testComparator(comparator, Arrays.asList(valuesInExpectedOrder)); 277 } 278 279 /** 280 * Asserts that all pairs of {@code T} values within {@code valuesInExpectedOrder} are ordered 281 * consistently between their order within {@code valuesInExpectedOrder} and the order implied by 282 * the given {@code comparator}. 283 * 284 * <p>In detail, this method asserts 285 * 286 * <ul> 287 * <li><i>reflexivity</i>: {@code comparator.compare(t, t) = 0} for all {@code t} in {@code 288 * valuesInExpectedOrder}; and 289 * <li><i>consistency</i>: {@code comparator.compare(ti, tj) < 0} and {@code 290 * comparator.compare(tj, ti) > 0} for {@code i < j}, where {@code ti = 291 * valuesInExpectedOrder.get(i)} and {@code tj = valuesInExpectedOrder.get(j)}. 292 * </ul> 293 */ 294 public static <T> void testComparator( 295 Comparator<? super T> comparator, List<T> valuesInExpectedOrder) { 296 // This does an O(n^2) test of all pairs of values in both orders 297 for (int i = 0; i < valuesInExpectedOrder.size(); i++) { 298 T t = valuesInExpectedOrder.get(i); 299 300 for (int j = 0; j < i; j++) { 301 T lesser = valuesInExpectedOrder.get(j); 302 assertTrue( 303 comparator + ".compare(" + lesser + ", " + t + ")", comparator.compare(lesser, t) < 0); 304 } 305 306 assertEquals(comparator + ".compare(" + t + ", " + t + ")", 0, comparator.compare(t, t)); 307 308 for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) { 309 T greater = valuesInExpectedOrder.get(j); 310 assertTrue( 311 comparator + ".compare(" + greater + ", " + t + ")", 312 comparator.compare(greater, t) > 0); 313 } 314 } 315 } 316 317 @SuppressWarnings({"SelfComparison", "SelfEquals"}) 318 public static <T extends Comparable<? super T>> void testCompareToAndEquals( 319 List<T> valuesInExpectedOrder) { 320 // This does an O(n^2) test of all pairs of values in both orders 321 for (int i = 0; i < valuesInExpectedOrder.size(); i++) { 322 T t = valuesInExpectedOrder.get(i); 323 324 for (int j = 0; j < i; j++) { 325 T lesser = valuesInExpectedOrder.get(j); 326 assertTrue(lesser + ".compareTo(" + t + ')', lesser.compareTo(t) < 0); 327 assertFalse(lesser.equals(t)); 328 } 329 330 assertEquals(t + ".compareTo(" + t + ')', 0, t.compareTo(t)); 331 assertTrue(t.equals(t)); 332 333 for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) { 334 T greater = valuesInExpectedOrder.get(j); 335 assertTrue(greater + ".compareTo(" + t + ')', greater.compareTo(t) > 0); 336 assertFalse(greater.equals(t)); 337 } 338 } 339 } 340 341 /** 342 * Returns a collection that simulates concurrent modification by having its size method return 343 * incorrect values. This is useful for testing methods that must treat the return value from 344 * size() as a hint only. 345 * 346 * @param delta the difference between the true size of the collection and the values returned by 347 * the size method 348 */ 349 public static <T> Collection<T> misleadingSizeCollection(final int delta) { 350 // It would be nice to be able to return a real concurrent 351 // collection like ConcurrentLinkedQueue, so that e.g. concurrent 352 // iteration would work, but that would not be GWT-compatible. 353 return new ArrayList<T>() { 354 @Override 355 public int size() { 356 return Math.max(0, super.size() + delta); 357 } 358 }; 359 } 360 361 /** 362 * Returns a "nefarious" map entry with the specified key and value, meaning an entry that is 363 * suitable for testing that map entries cannot be modified via a nefarious implementation of 364 * equals. This is used for testing unmodifiable collections of map entries; for example, it 365 * should not be possible to access the raw (modifiable) map entry via a nefarious equals method. 366 */ 367 public static <K, V> Entry<K, V> nefariousMapEntry(final K key, final V value) { 368 return new Entry<K, V>() { 369 @Override 370 public K getKey() { 371 return key; 372 } 373 374 @Override 375 public V getValue() { 376 return value; 377 } 378 379 @Override 380 public V setValue(V value) { 381 throw new UnsupportedOperationException(); 382 } 383 384 @SuppressWarnings("unchecked") 385 @Override 386 public boolean equals(Object o) { 387 if (o instanceof Entry) { 388 Entry<K, V> e = (Entry<K, V>) o; 389 e.setValue(value); // muhahaha! 390 391 return equal(this.getKey(), e.getKey()) && equal(this.getValue(), e.getValue()); 392 } 393 return false; 394 } 395 396 @Override 397 public int hashCode() { 398 K k = getKey(); 399 V v = getValue(); 400 return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode()); 401 } 402 403 @Override 404 public String toString() { 405 return getKey() + "=" + getValue(); 406 } 407 }; 408 } 409 410 static <E> List<E> castOrCopyToList(Iterable<E> iterable) { 411 if (iterable instanceof List) { 412 return (List<E>) iterable; 413 } 414 List<E> list = new ArrayList<E>(); 415 for (E e : iterable) { 416 list.add(e); 417 } 418 return list; 419 } 420 421 private static final Comparator<Comparable> NATURAL_ORDER = 422 new Comparator<Comparable>() { 423 @SuppressWarnings("unchecked") // assume any Comparable is Comparable<Self> 424 @Override 425 public int compare(Comparable left, Comparable right) { 426 return left.compareTo(right); 427 } 428 }; 429 430 public static <K extends Comparable, V> Iterable<Entry<K, V>> orderEntriesByKey( 431 List<Entry<K, V>> insertionOrder) { 432 sort(insertionOrder, Helpers.<K, V>entryComparator(NATURAL_ORDER)); 433 return insertionOrder; 434 } 435 436 /** 437 * Private replacement for {@link com.google.gwt.user.client.rpc.GwtTransient} to work around 438 * build-system quirks. 439 */ 440 private @interface GwtTransient {} 441 442 /** 443 * Compares strings in natural order except that null comes immediately before a given value. This 444 * works better than Ordering.natural().nullsFirst() because, if null comes before all other 445 * values, it lies outside the submap/submultiset ranges we test, and the variety of tests that 446 * exercise null handling fail on those subcollections. 447 */ 448 public abstract static class NullsBefore implements Comparator<String>, Serializable { 449 /* 450 * We don't serialize this class in GWT, so we don't care about whether GWT will serialize this 451 * field. 452 */ 453 @GwtTransient private final String justAfterNull; 454 455 protected NullsBefore(String justAfterNull) { 456 if (justAfterNull == null) { 457 throw new NullPointerException(); 458 } 459 460 this.justAfterNull = justAfterNull; 461 } 462 463 @Override 464 public int compare(String lhs, String rhs) { 465 if (lhs == rhs) { 466 return 0; 467 } 468 if (lhs == null) { 469 // lhs (null) comes just before justAfterNull. 470 // If rhs is b, lhs comes first. 471 if (rhs.equals(justAfterNull)) { 472 return -1; 473 } 474 return justAfterNull.compareTo(rhs); 475 } 476 if (rhs == null) { 477 // rhs (null) comes just before justAfterNull. 478 // If lhs is b, rhs comes first. 479 if (lhs.equals(justAfterNull)) { 480 return 1; 481 } 482 return lhs.compareTo(justAfterNull); 483 } 484 return lhs.compareTo(rhs); 485 } 486 487 @Override 488 public boolean equals(Object obj) { 489 if (obj instanceof NullsBefore) { 490 NullsBefore other = (NullsBefore) obj; 491 return justAfterNull.equals(other.justAfterNull); 492 } 493 return false; 494 } 495 496 @Override 497 public int hashCode() { 498 return justAfterNull.hashCode(); 499 } 500 } 501 502 public static final class NullsBeforeB extends NullsBefore { 503 public static final NullsBeforeB INSTANCE = new NullsBeforeB(); 504 505 private NullsBeforeB() { 506 super("b"); 507 } 508 } 509 510 public static final class NullsBeforeTwo extends NullsBefore { 511 public static final NullsBeforeTwo INSTANCE = new NullsBeforeTwo(); 512 513 private NullsBeforeTwo() { 514 super("two"); // from TestStringSortedMapGenerator's sample keys 515 } 516 } 517 518 @GwtIncompatible // reflection 519 public static Method getMethod(Class<?> clazz, String name) { 520 try { 521 return clazz.getMethod(name); 522 } catch (Exception e) { 523 throw new IllegalArgumentException(e); 524 } 525 } 526 } 527