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}