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}