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