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