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<>(Arrays.asList(expected));
173
174    for (Object o : actual) {
175      expectedList.remove(o);
176    }
177
178    if (!expectedList.isEmpty()) {
179      Assert.fail("Not true that " + actual + " contains all of " + Arrays.asList(expected));
180    }
181  }
182
183  public static <E> boolean addAll(Collection<E> addTo, Iterable<? extends E> elementsToAdd) {
184    boolean modified = false;
185    for (E e : elementsToAdd) {
186      modified |= addTo.add(e);
187    }
188    return modified;
189  }
190
191  static <T> Iterable<T> reverse(final List<T> list) {
192    return new Iterable<T>() {
193      @Override
194      public Iterator<T> iterator() {
195        final ListIterator<T> listIter = list.listIterator(list.size());
196        return new Iterator<T>() {
197          @Override
198          public boolean hasNext() {
199            return listIter.hasPrevious();
200          }
201
202          @Override
203          public T next() {
204            return listIter.previous();
205          }
206
207          @Override
208          public void remove() {
209            listIter.remove();
210          }
211        };
212      }
213    };
214  }
215
216  static <T> Iterator<T> cycle(final Iterable<T> iterable) {
217    return new Iterator<T>() {
218      Iterator<T> iterator = Collections.<T>emptySet().iterator();
219
220      @Override
221      public boolean hasNext() {
222        return true;
223      }
224
225      @Override
226      public T next() {
227        if (!iterator.hasNext()) {
228          iterator = iterable.iterator();
229        }
230        return iterator.next();
231      }
232
233      @Override
234      public void remove() {
235        throw new UnsupportedOperationException();
236      }
237    };
238  }
239
240  static <T> T get(Iterator<T> iterator, int position) {
241    for (int i = 0; i < position; i++) {
242      iterator.next();
243    }
244    return iterator.next();
245  }
246
247  static void fail(Throwable cause, Object message) {
248    AssertionFailedError assertionFailedError = new AssertionFailedError(String.valueOf(message));
249    assertionFailedError.initCause(cause);
250    throw assertionFailedError;
251  }
252
253  public static <K, V> Comparator<Entry<K, V>> entryComparator(
254      final Comparator<? super K> keyComparator) {
255    return new Comparator<Entry<K, V>>() {
256      @Override
257      @SuppressWarnings("unchecked") // no less safe than putting it in the map!
258      public int compare(Entry<K, V> a, Entry<K, V> b) {
259        return (keyComparator == null)
260            ? ((Comparable) a.getKey()).compareTo(b.getKey())
261            : keyComparator.compare(a.getKey(), b.getKey());
262      }
263    };
264  }
265
266  /**
267   * Asserts that all pairs of {@code T} values within {@code valuesInExpectedOrder} are ordered
268   * consistently between their order within {@code valuesInExpectedOrder} and the order implied by
269   * the given {@code comparator}.
270   *
271   * @see #testComparator(Comparator, List)
272   */
273  public static <T> void testComparator(
274      Comparator<? super T> comparator, T... valuesInExpectedOrder) {
275    testComparator(comparator, Arrays.asList(valuesInExpectedOrder));
276  }
277
278  /**
279   * Asserts that all pairs of {@code T} values within {@code valuesInExpectedOrder} are ordered
280   * consistently between their order within {@code valuesInExpectedOrder} and the order implied by
281   * the given {@code comparator}.
282   *
283   * <p>In detail, this method asserts
284   *
285   * <ul>
286   *   <li><i>reflexivity</i>: {@code comparator.compare(t, t) = 0} for all {@code t} in {@code
287   *       valuesInExpectedOrder}; and
288   *   <li><i>consistency</i>: {@code comparator.compare(ti, tj) < 0} and {@code
289   *       comparator.compare(tj, ti) > 0} for {@code i < j}, where {@code ti =
290   *       valuesInExpectedOrder.get(i)} and {@code tj = valuesInExpectedOrder.get(j)}.
291   * </ul>
292   */
293  public static <T> void testComparator(
294      Comparator<? super T> comparator, List<T> valuesInExpectedOrder) {
295    // This does an O(n^2) test of all pairs of values in both orders
296    for (int i = 0; i < valuesInExpectedOrder.size(); i++) {
297      T t = valuesInExpectedOrder.get(i);
298
299      for (int j = 0; j < i; j++) {
300        T lesser = valuesInExpectedOrder.get(j);
301        assertTrue(
302            comparator + ".compare(" + lesser + ", " + t + ")", comparator.compare(lesser, t) < 0);
303      }
304
305      assertEquals(comparator + ".compare(" + t + ", " + t + ")", 0, comparator.compare(t, t));
306
307      for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) {
308        T greater = valuesInExpectedOrder.get(j);
309        assertTrue(
310            comparator + ".compare(" + greater + ", " + t + ")",
311            comparator.compare(greater, t) > 0);
312      }
313    }
314  }
315
316  @SuppressWarnings({"SelfComparison", "SelfEquals"})
317  public static <T extends Comparable<? super T>> void testCompareToAndEquals(
318      List<T> valuesInExpectedOrder) {
319    // This does an O(n^2) test of all pairs of values in both orders
320    for (int i = 0; i < valuesInExpectedOrder.size(); i++) {
321      T t = valuesInExpectedOrder.get(i);
322
323      for (int j = 0; j < i; j++) {
324        T lesser = valuesInExpectedOrder.get(j);
325        assertTrue(lesser + ".compareTo(" + t + ')', lesser.compareTo(t) < 0);
326        assertFalse(lesser.equals(t));
327      }
328
329      assertEquals(t + ".compareTo(" + t + ')', 0, t.compareTo(t));
330      assertTrue(t.equals(t));
331
332      for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) {
333        T greater = valuesInExpectedOrder.get(j);
334        assertTrue(greater + ".compareTo(" + t + ')', greater.compareTo(t) > 0);
335        assertFalse(greater.equals(t));
336      }
337    }
338  }
339
340  /**
341   * Returns a collection that simulates concurrent modification by having its size method return
342   * incorrect values. This is useful for testing methods that must treat the return value from
343   * size() as a hint only.
344   *
345   * @param delta the difference between the true size of the collection and the values returned by
346   *     the size method
347   */
348  public static <T> Collection<T> misleadingSizeCollection(final int delta) {
349    // It would be nice to be able to return a real concurrent
350    // collection like ConcurrentLinkedQueue, so that e.g. concurrent
351    // iteration would work, but that would not be GWT-compatible.
352    return new ArrayList<T>() {
353      @Override
354      public int size() {
355        return Math.max(0, super.size() + delta);
356      }
357    };
358  }
359
360  /**
361   * Returns a "nefarious" map entry with the specified key and value, meaning an entry that is
362   * suitable for testing that map entries cannot be modified via a nefarious implementation of
363   * equals. This is used for testing unmodifiable collections of map entries; for example, it
364   * should not be possible to access the raw (modifiable) map entry via a nefarious equals method.
365   */
366  public static <K, V> Entry<K, V> nefariousMapEntry(final K key, final V value) {
367    return new Entry<K, V>() {
368      @Override
369      public K getKey() {
370        return key;
371      }
372
373      @Override
374      public V getValue() {
375        return value;
376      }
377
378      @Override
379      public V setValue(V value) {
380        throw new UnsupportedOperationException();
381      }
382
383      @SuppressWarnings("unchecked")
384      @Override
385      public boolean equals(Object o) {
386        if (o instanceof Entry) {
387          Entry<K, V> e = (Entry<K, V>) o;
388          e.setValue(value); // muhahaha!
389
390          return equal(this.getKey(), e.getKey()) && equal(this.getValue(), e.getValue());
391        }
392        return false;
393      }
394
395      @Override
396      public int hashCode() {
397        K k = getKey();
398        V v = getValue();
399        return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
400      }
401
402      @Override
403      public String toString() {
404        return getKey() + "=" + getValue();
405      }
406    };
407  }
408
409  static <E> List<E> castOrCopyToList(Iterable<E> iterable) {
410    if (iterable instanceof List) {
411      return (List<E>) iterable;
412    }
413    List<E> list = new ArrayList<E>();
414    for (E e : iterable) {
415      list.add(e);
416    }
417    return list;
418  }
419
420  private static final Comparator<Comparable> NATURAL_ORDER =
421      new Comparator<Comparable>() {
422        @SuppressWarnings("unchecked") // assume any Comparable is Comparable<Self>
423        @Override
424        public int compare(Comparable left, Comparable right) {
425          return left.compareTo(right);
426        }
427      };
428
429  public static <K extends Comparable, V> Iterable<Entry<K, V>> orderEntriesByKey(
430      List<Entry<K, V>> insertionOrder) {
431    sort(insertionOrder, Helpers.<K, V>entryComparator(NATURAL_ORDER));
432    return insertionOrder;
433  }
434
435  /**
436   * Private replacement for {@link com.google.gwt.user.client.rpc.GwtTransient} to work around
437   * build-system quirks.
438   */
439  private @interface GwtTransient {}
440
441  /**
442   * Compares strings in natural order except that null comes immediately before a given value. This
443   * works better than Ordering.natural().nullsFirst() because, if null comes before all other
444   * values, it lies outside the submap/submultiset ranges we test, and the variety of tests that
445   * exercise null handling fail on those subcollections.
446   */
447  public abstract static class NullsBefore implements Comparator<String>, Serializable {
448    /*
449     * We don't serialize this class in GWT, so we don't care about whether GWT will serialize this
450     * field.
451     */
452    @GwtTransient private final String justAfterNull;
453
454    protected NullsBefore(String justAfterNull) {
455      if (justAfterNull == null) {
456        throw new NullPointerException();
457      }
458
459      this.justAfterNull = justAfterNull;
460    }
461
462    @Override
463    public int compare(String lhs, String rhs) {
464      if (lhs == rhs) {
465        return 0;
466      }
467      if (lhs == null) {
468        // lhs (null) comes just before justAfterNull.
469        // If rhs is b, lhs comes first.
470        if (rhs.equals(justAfterNull)) {
471          return -1;
472        }
473        return justAfterNull.compareTo(rhs);
474      }
475      if (rhs == null) {
476        // rhs (null) comes just before justAfterNull.
477        // If lhs is b, rhs comes first.
478        if (lhs.equals(justAfterNull)) {
479          return 1;
480        }
481        return lhs.compareTo(justAfterNull);
482      }
483      return lhs.compareTo(rhs);
484    }
485
486    @Override
487    public boolean equals(Object obj) {
488      if (obj instanceof NullsBefore) {
489        NullsBefore other = (NullsBefore) obj;
490        return justAfterNull.equals(other.justAfterNull);
491      }
492      return false;
493    }
494
495    @Override
496    public int hashCode() {
497      return justAfterNull.hashCode();
498    }
499  }
500
501  public static final class NullsBeforeB extends NullsBefore {
502    public static final NullsBeforeB INSTANCE = new NullsBeforeB();
503
504    private NullsBeforeB() {
505      super("b");
506    }
507  }
508
509  public static final class NullsBeforeTwo extends NullsBefore {
510    public static final NullsBeforeTwo INSTANCE = new NullsBeforeTwo();
511
512    private NullsBeforeTwo() {
513      super("two"); // from TestStringSortedMapGenerator's sample keys
514    }
515  }
516
517  @GwtIncompatible // reflection
518  public static Method getMethod(Class<?> clazz, String name) {
519    try {
520      return clazz.getMethod(name);
521    } catch (Exception e) {
522      throw new IllegalArgumentException(e);
523    }
524  }
525}