• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.google.common.annotations.J2ktIncompatible;
27 import com.google.errorprone.annotations.CanIgnoreReturnValue;
28 import java.io.Serializable;
29 import java.lang.reflect.Method;
30 import java.util.AbstractList;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.Comparator;
36 import java.util.Iterator;
37 import java.util.LinkedHashSet;
38 import java.util.List;
39 import java.util.ListIterator;
40 import java.util.Map;
41 import java.util.Map.Entry;
42 import java.util.Set;
43 import junit.framework.Assert;
44 import junit.framework.AssertionFailedError;
45 import org.checkerframework.checker.nullness.qual.Nullable;
46 
47 @GwtCompatible(emulated = true)
48 @ElementTypesAreNonnullByDefault
49 public class Helpers {
50   // Clone of Objects.equal
equal(@ullable Object a, @Nullable Object b)51   static boolean equal(@Nullable Object a, @Nullable Object b) {
52     return a == b || (a != null && a.equals(b));
53   }
54 
55   // Clone of Lists.newArrayList
copyToList(Iterable<? extends E> elements)56   public static <E extends @Nullable Object> List<E> copyToList(Iterable<? extends E> elements) {
57     List<E> list = new ArrayList<>();
58     addAll(list, elements);
59     return list;
60   }
61 
copyToList(E[] elements)62   public static <E extends @Nullable Object> List<E> copyToList(E[] elements) {
63     return copyToList(Arrays.asList(elements));
64   }
65 
66   // Clone of Sets.newLinkedHashSet
copyToSet(Iterable<? extends E> elements)67   public static <E extends @Nullable Object> Set<E> copyToSet(Iterable<? extends E> elements) {
68     Set<E> set = new LinkedHashSet<>();
69     addAll(set, elements);
70     return set;
71   }
72 
copyToSet(E[] elements)73   public static <E extends @Nullable Object> Set<E> copyToSet(E[] elements) {
74     return copyToSet(Arrays.asList(elements));
75   }
76 
77   // Would use Maps.immutableEntry
mapEntry( K key, V value)78   public static <K extends @Nullable Object, V extends @Nullable Object> Entry<K, V> mapEntry(
79       K key, V value) {
80     return Collections.singletonMap(key, value).entrySet().iterator().next();
81   }
82 
isEmpty(Iterable<?> iterable)83   private static boolean isEmpty(Iterable<?> iterable) {
84     return iterable instanceof Collection
85         ? ((Collection<?>) iterable).isEmpty()
86         : !iterable.iterator().hasNext();
87   }
88 
assertEmpty(Iterable<?> iterable)89   public static void assertEmpty(Iterable<?> iterable) {
90     if (!isEmpty(iterable)) {
91       Assert.fail("Not true that " + iterable + " is empty");
92     }
93   }
94 
assertEmpty(Map<?, ?> map)95   public static void assertEmpty(Map<?, ?> map) {
96     if (!map.isEmpty()) {
97       Assert.fail("Not true that " + map + " is empty");
98     }
99   }
100 
assertEqualInOrder(Iterable<?> expected, Iterable<?> actual)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 
assertContentsInOrder(Iterable<?> actual, Object... expected)127   public static void assertContentsInOrder(Iterable<?> actual, Object... expected) {
128     assertEqualInOrder(Arrays.asList(expected), actual);
129   }
130 
assertEqualIgnoringOrder(Iterable<?> expected, Iterable<?> actual)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 
assertContentsAnyOrder(Iterable<?> actual, Object... expected)155   public static void assertContentsAnyOrder(Iterable<?> actual, Object... expected) {
156     assertEqualIgnoringOrder(Arrays.asList(expected), actual);
157   }
158 
assertContains(Iterable<?> actual, Object expected)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 
assertContainsAllOf(Iterable<?> actual, Object... expected)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
addAll( Collection<E> addTo, Iterable<? extends E> elementsToAdd)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 
reverse(List<T> list)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 }
579