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