001/* 002 * Copyright (C) 2009 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 java.util.Collections.sort; 020import static junit.framework.Assert.assertEquals; 021import static junit.framework.Assert.assertFalse; 022import static junit.framework.Assert.assertTrue; 023 024import com.google.common.annotations.GwtCompatible; 025import com.google.common.annotations.GwtIncompatible; 026import com.google.common.annotations.J2ktIncompatible; 027import com.google.errorprone.annotations.CanIgnoreReturnValue; 028import java.io.Serializable; 029import java.lang.reflect.Method; 030import java.util.AbstractList; 031import java.util.ArrayList; 032import java.util.Arrays; 033import java.util.Collection; 034import java.util.Collections; 035import java.util.Comparator; 036import java.util.Iterator; 037import java.util.LinkedHashSet; 038import java.util.List; 039import java.util.ListIterator; 040import java.util.Map; 041import java.util.Map.Entry; 042import java.util.Set; 043import junit.framework.Assert; 044import junit.framework.AssertionFailedError; 045import org.checkerframework.checker.nullness.qual.Nullable; 046 047@GwtCompatible(emulated = true) 048@ElementTypesAreNonnullByDefault 049public class Helpers { 050 // Clone of Objects.equal 051 static boolean equal(@Nullable Object a, @Nullable Object b) { 052 return a == b || (a != null && a.equals(b)); 053 } 054 055 // Clone of Lists.newArrayList 056 public static <E extends @Nullable Object> List<E> copyToList(Iterable<? extends E> elements) { 057 List<E> list = new ArrayList<>(); 058 addAll(list, elements); 059 return list; 060 } 061 062 public static <E extends @Nullable Object> List<E> copyToList(E[] elements) { 063 return copyToList(Arrays.asList(elements)); 064 } 065 066 // Clone of Sets.newLinkedHashSet 067 public static <E extends @Nullable Object> Set<E> copyToSet(Iterable<? extends E> elements) { 068 Set<E> set = new LinkedHashSet<>(); 069 addAll(set, elements); 070 return set; 071 } 072 073 public static <E extends @Nullable Object> Set<E> copyToSet(E[] elements) { 074 return copyToSet(Arrays.asList(elements)); 075 } 076 077 // Would use Maps.immutableEntry 078 public static <K extends @Nullable Object, V extends @Nullable Object> Entry<K, V> mapEntry( 079 K key, V value) { 080 return Collections.singletonMap(key, value).entrySet().iterator().next(); 081 } 082 083 private static boolean isEmpty(Iterable<?> iterable) { 084 return iterable instanceof Collection 085 ? ((Collection<?>) iterable).isEmpty() 086 : !iterable.iterator().hasNext(); 087 } 088 089 public static void assertEmpty(Iterable<?> iterable) { 090 if (!isEmpty(iterable)) { 091 Assert.fail("Not true that " + iterable + " is empty"); 092 } 093 } 094 095 public static void assertEmpty(Map<?, ?> map) { 096 if (!map.isEmpty()) { 097 Assert.fail("Not true that " + map + " is empty"); 098 } 099 } 100 101 public static void assertEqualInOrder(Iterable<?> expected, Iterable<?> actual) { 102 Iterator<?> expectedIter = expected.iterator(); 103 Iterator<?> actualIter = actual.iterator(); 104 105 while (expectedIter.hasNext() && actualIter.hasNext()) { 106 if (!equal(expectedIter.next(), actualIter.next())) { 107 Assert.fail( 108 "contents were not equal and in the same order: " 109 + "expected = " 110 + expected 111 + ", actual = " 112 + actual); 113 } 114 } 115 116 if (expectedIter.hasNext() || actualIter.hasNext()) { 117 // actual either had too few or too many elements 118 Assert.fail( 119 "contents were not equal and in the same order: " 120 + "expected = " 121 + expected 122 + ", actual = " 123 + actual); 124 } 125 } 126 127 public static void assertContentsInOrder(Iterable<?> actual, Object... expected) { 128 assertEqualInOrder(Arrays.asList(expected), actual); 129 } 130 131 public static void assertEqualIgnoringOrder(Iterable<?> expected, Iterable<?> actual) { 132 List<?> exp = copyToList(expected); 133 List<?> act = copyToList(actual); 134 String actString = act.toString(); 135 136 // Of course we could take pains to give the complete description of the 137 // problem on any failure. 138 139 // Yeah it's n^2. 140 for (Object object : exp) { 141 if (!act.remove(object)) { 142 Assert.fail( 143 "did not contain expected element " 144 + object 145 + ", " 146 + "expected = " 147 + exp 148 + ", actual = " 149 + actString); 150 } 151 } 152 assertTrue("unexpected elements: " + act, act.isEmpty()); 153 } 154 155 public static void assertContentsAnyOrder(Iterable<?> actual, Object... expected) { 156 assertEqualIgnoringOrder(Arrays.asList(expected), actual); 157 } 158 159 public static void assertContains(Iterable<?> actual, Object expected) { 160 boolean contained = false; 161 if (actual instanceof Collection) { 162 contained = ((Collection<?>) actual).contains(expected); 163 } else { 164 for (Object o : actual) { 165 if (equal(o, expected)) { 166 contained = true; 167 break; 168 } 169 } 170 } 171 172 if (!contained) { 173 Assert.fail("Not true that " + actual + " contains " + expected); 174 } 175 } 176 177 public static void assertContainsAllOf(Iterable<?> actual, Object... expected) { 178 List<Object> expectedList = new ArrayList<>(Arrays.asList(expected)); 179 180 for (Object o : actual) { 181 expectedList.remove(o); 182 } 183 184 if (!expectedList.isEmpty()) { 185 Assert.fail("Not true that " + actual + " contains all of " + Arrays.asList(expected)); 186 } 187 } 188 189 @CanIgnoreReturnValue 190 public static <E extends @Nullable Object> boolean addAll( 191 Collection<E> addTo, Iterable<? extends E> elementsToAdd) { 192 boolean modified = false; 193 for (E e : elementsToAdd) { 194 modified |= addTo.add(e); 195 } 196 return modified; 197 } 198 199 static <T> Iterable<T> reverse(List<T> list) { 200 return new Iterable<T>() { 201 @Override 202 public Iterator<T> iterator() { 203 ListIterator<T> listIter = list.listIterator(list.size()); 204 return new Iterator<T>() { 205 @Override 206 public boolean hasNext() { 207 return listIter.hasPrevious(); 208 } 209 210 @Override 211 public T next() { 212 return listIter.previous(); 213 } 214 215 @Override 216 public void remove() { 217 listIter.remove(); 218 } 219 }; 220 } 221 }; 222 } 223 224 static <T> Iterator<T> cycle(Iterable<T> iterable) { 225 return new Iterator<T>() { 226 Iterator<T> iterator = Collections.<T>emptySet().iterator(); 227 228 @Override 229 public boolean hasNext() { 230 return true; 231 } 232 233 @Override 234 public T next() { 235 if (!iterator.hasNext()) { 236 iterator = iterable.iterator(); 237 } 238 return iterator.next(); 239 } 240 241 @Override 242 public void remove() { 243 throw new UnsupportedOperationException(); 244 } 245 }; 246 } 247 248 static <T> T get(Iterator<T> iterator, int position) { 249 for (int i = 0; i < position; i++) { 250 iterator.next(); 251 } 252 return iterator.next(); 253 } 254 255 static void fail(Throwable cause, Object message) { 256 AssertionFailedError assertionFailedError = new AssertionFailedError(String.valueOf(message)); 257 assertionFailedError.initCause(cause); 258 throw assertionFailedError; 259 } 260 261 private static class EntryComparator<K extends @Nullable Object, V extends @Nullable Object> 262 implements Comparator<Entry<K, V>> { 263 final @Nullable Comparator<? super K> keyComparator; 264 265 public EntryComparator(@Nullable Comparator<? super K> keyComparator) { 266 this.keyComparator = keyComparator; 267 } 268 269 @Override 270 @SuppressWarnings("unchecked") // no less safe than putting it in the map! 271 public int compare(Entry<K, V> a, Entry<K, V> b) { 272 return (keyComparator == null) 273 ? ((Comparable) a.getKey()).compareTo(b.getKey()) 274 : keyComparator.compare(a.getKey(), b.getKey()); 275 } 276 } 277 278 public static <K, V> Comparator<Entry<K, V>> entryComparator( 279 @Nullable Comparator<? super K> keyComparator) { 280 return new EntryComparator<K, V>(keyComparator); 281 } 282 283 /** 284 * Asserts that all pairs of {@code T} values within {@code valuesInExpectedOrder} are ordered 285 * consistently between their order within {@code valuesInExpectedOrder} and the order implied by 286 * the given {@code comparator}. 287 * 288 * @see #testComparator(Comparator, List) 289 */ 290 public static <T> void testComparator( 291 Comparator<? super T> comparator, T... valuesInExpectedOrder) { 292 testComparator(comparator, Arrays.asList(valuesInExpectedOrder)); 293 } 294 295 /** 296 * Asserts that all pairs of {@code T} values within {@code valuesInExpectedOrder} are ordered 297 * consistently between their order within {@code valuesInExpectedOrder} and the order implied by 298 * the given {@code comparator}. 299 * 300 * <p>In detail, this method asserts 301 * 302 * <ul> 303 * <li><i>reflexivity</i>: {@code comparator.compare(t, t) = 0} for all {@code t} in {@code 304 * valuesInExpectedOrder}; and 305 * <li><i>consistency</i>: {@code comparator.compare(ti, tj) < 0} and {@code 306 * comparator.compare(tj, ti) > 0} for {@code i < j}, where {@code ti = 307 * valuesInExpectedOrder.get(i)} and {@code tj = valuesInExpectedOrder.get(j)}. 308 * </ul> 309 */ 310 public static <T extends @Nullable Object> void testComparator( 311 Comparator<? super T> comparator, List<T> valuesInExpectedOrder) { 312 // This does an O(n^2) test of all pairs of values in both orders 313 for (int i = 0; i < valuesInExpectedOrder.size(); i++) { 314 T t = valuesInExpectedOrder.get(i); 315 316 for (int j = 0; j < i; j++) { 317 T lesser = valuesInExpectedOrder.get(j); 318 assertTrue( 319 comparator + ".compare(" + lesser + ", " + t + ")", comparator.compare(lesser, t) < 0); 320 } 321 322 assertEquals(comparator + ".compare(" + t + ", " + t + ")", 0, comparator.compare(t, t)); 323 324 for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) { 325 T greater = valuesInExpectedOrder.get(j); 326 assertTrue( 327 comparator + ".compare(" + greater + ", " + t + ")", 328 comparator.compare(greater, t) > 0); 329 } 330 } 331 } 332 333 @SuppressWarnings({"SelfComparison", "SelfEquals"}) 334 public static <T extends Comparable<? super T>> void testCompareToAndEquals( 335 List<T> valuesInExpectedOrder) { 336 // This does an O(n^2) test of all pairs of values in both orders 337 for (int i = 0; i < valuesInExpectedOrder.size(); i++) { 338 T t = valuesInExpectedOrder.get(i); 339 340 for (int j = 0; j < i; j++) { 341 T lesser = valuesInExpectedOrder.get(j); 342 assertTrue(lesser + ".compareTo(" + t + ')', lesser.compareTo(t) < 0); 343 assertFalse(lesser.equals(t)); 344 } 345 346 assertEquals(t + ".compareTo(" + t + ')', 0, t.compareTo(t)); 347 assertTrue(t.equals(t)); 348 349 for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) { 350 T greater = valuesInExpectedOrder.get(j); 351 assertTrue(greater + ".compareTo(" + t + ')', greater.compareTo(t) > 0); 352 assertFalse(greater.equals(t)); 353 } 354 } 355 } 356 357 /** 358 * Returns a collection that simulates concurrent modification by having its size method return 359 * incorrect values. This is useful for testing methods that must treat the return value from 360 * size() as a hint only. 361 * 362 * @param delta the difference between the true size of the collection and the values returned by 363 * the size method 364 */ 365 public static <T extends @Nullable Object> Collection<T> misleadingSizeCollection(int delta) { 366 // It would be nice to be able to return a real concurrent 367 // collection like ConcurrentLinkedQueue, so that e.g. concurrent 368 // iteration would work, but that would not be GWT-compatible. 369 // We are not "just" inheriting from ArrayList here as this doesn't work for J2kt. 370 return new AbstractList<T>() { 371 ArrayList<T> data = new ArrayList<>(); 372 373 @Override 374 public int size() { 375 return Math.max(0, data.size() + delta); 376 } 377 378 @Override 379 public T get(int index) { 380 return data.get(index); 381 } 382 383 @Override 384 public T set(int index, T element) { 385 return data.set(index, element); 386 } 387 388 @Override 389 public boolean add(T element) { 390 return data.add(element); 391 } 392 393 @Override 394 public void add(int index, T element) { 395 data.add(index, element); 396 } 397 398 @Override 399 public T remove(int index) { 400 return data.remove(index); 401 } 402 403 @Override 404 public @Nullable Object[] toArray() { 405 return data.toArray(); 406 } 407 }; 408 } 409 410 /** 411 * Returns a "nefarious" map entry with the specified key and value, meaning an entry that is 412 * suitable for testing that map entries cannot be modified via a nefarious implementation of 413 * equals. This is used for testing unmodifiable collections of map entries; for example, it 414 * should not be possible to access the raw (modifiable) map entry via a nefarious equals method. 415 */ 416 public static <K extends @Nullable Object, V extends @Nullable Object> 417 Entry<K, V> nefariousMapEntry(K key, V value) { 418 return new Entry<K, V>() { 419 @Override 420 public K getKey() { 421 return key; 422 } 423 424 @Override 425 public V getValue() { 426 return value; 427 } 428 429 @Override 430 public V setValue(V value) { 431 throw new UnsupportedOperationException(); 432 } 433 434 @SuppressWarnings("unchecked") 435 @Override 436 public boolean equals(@Nullable Object o) { 437 if (o instanceof Entry) { 438 Entry<K, V> e = (Entry<K, V>) o; 439 e.setValue(value); // muhahaha! 440 441 return equal(this.getKey(), e.getKey()) && equal(this.getValue(), e.getValue()); 442 } 443 return false; 444 } 445 446 @Override 447 public int hashCode() { 448 K k = getKey(); 449 V v = getValue(); 450 return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode()); 451 } 452 453 @Override 454 public String toString() { 455 return getKey() + "=" + getValue(); 456 } 457 }; 458 } 459 460 static <E extends @Nullable Object> List<E> castOrCopyToList(Iterable<E> iterable) { 461 if (iterable instanceof List) { 462 return (List<E>) iterable; 463 } 464 List<E> list = new ArrayList<>(); 465 for (E e : iterable) { 466 list.add(e); 467 } 468 return list; 469 } 470 471 private static final Comparator<Comparable> NATURAL_ORDER = 472 new Comparator<Comparable>() { 473 @SuppressWarnings("unchecked") // assume any Comparable is Comparable<Self> 474 @Override 475 public int compare(Comparable left, Comparable right) { 476 return left.compareTo(right); 477 } 478 }; 479 480 @J2ktIncompatible 481 public static <K extends Comparable, V> Iterable<Entry<K, V>> orderEntriesByKey( 482 List<Entry<K, V>> insertionOrder) { 483 sort(insertionOrder, Helpers.<K, V>entryComparator(NATURAL_ORDER)); 484 return insertionOrder; 485 } 486 487 /** 488 * Private replacement for {@link com.google.gwt.user.client.rpc.GwtTransient} to work around 489 * build-system quirks. 490 */ 491 private @interface GwtTransient {} 492 493 /** 494 * Compares strings in natural order except that null comes immediately before a given value. This 495 * works better than Ordering.natural().nullsFirst() because, if null comes before all other 496 * values, it lies outside the submap/submultiset ranges we test, and the variety of tests that 497 * exercise null handling fail on those subcollections. 498 */ 499 public abstract static class NullsBefore implements Comparator<@Nullable String>, Serializable { 500 /* 501 * We don't serialize this class in GWT, so we don't care about whether GWT will serialize this 502 * field. 503 */ 504 @GwtTransient private final String justAfterNull; 505 506 protected NullsBefore(String justAfterNull) { 507 if (justAfterNull == null) { 508 throw new NullPointerException(); 509 } 510 511 this.justAfterNull = justAfterNull; 512 } 513 514 @Override 515 public int compare(@Nullable String lhs, @Nullable String rhs) { 516 if (lhs == rhs) { 517 return 0; 518 } 519 if (lhs == null) { 520 // lhs (null) comes just before justAfterNull. 521 // If rhs is b, lhs comes first. 522 if (rhs.equals(justAfterNull)) { 523 return -1; 524 } 525 return justAfterNull.compareTo(rhs); 526 } 527 if (rhs == null) { 528 // rhs (null) comes just before justAfterNull. 529 // If lhs is b, rhs comes first. 530 if (lhs.equals(justAfterNull)) { 531 return 1; 532 } 533 return lhs.compareTo(justAfterNull); 534 } 535 return lhs.compareTo(rhs); 536 } 537 538 @Override 539 public boolean equals(@Nullable Object obj) { 540 if (obj instanceof NullsBefore) { 541 NullsBefore other = (NullsBefore) obj; 542 return justAfterNull.equals(other.justAfterNull); 543 } 544 return false; 545 } 546 547 @Override 548 public int hashCode() { 549 return justAfterNull.hashCode(); 550 } 551 } 552 553 public static final class NullsBeforeB extends NullsBefore { 554 public static final NullsBeforeB INSTANCE = new NullsBeforeB(); 555 556 private NullsBeforeB() { 557 super("b"); 558 } 559 } 560 561 public static final class NullsBeforeTwo extends NullsBefore { 562 public static final NullsBeforeTwo INSTANCE = new NullsBeforeTwo(); 563 564 private NullsBeforeTwo() { 565 super("two"); // from TestStringSortedMapGenerator's sample keys 566 } 567 } 568 569 @J2ktIncompatible 570 @GwtIncompatible // reflection 571 public static Method getMethod(Class<?> clazz, String name) { 572 try { 573 return clazz.getMethod(name); 574 } catch (Exception e) { 575 throw new IllegalArgumentException(e); 576 } 577 } 578}