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