Home | History | Annotate | Download | only in testing
      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 
     26 import junit.framework.Assert;
     27 import junit.framework.AssertionFailedError;
     28 
     29 import java.io.Serializable;
     30 import java.util.ArrayList;
     31 import java.util.Arrays;
     32 import java.util.Collection;
     33 import java.util.Collections;
     34 import java.util.Comparator;
     35 import java.util.Iterator;
     36 import java.util.LinkedHashSet;
     37 import java.util.List;
     38 import java.util.ListIterator;
     39 import java.util.Map;
     40 import java.util.Map.Entry;
     41 import java.util.Set;
     42 
     43 @GwtCompatible(emulated = true)
     44 public class Helpers {
     45   // Clone of Objects.equal
     46   static boolean equal(Object a, Object b) {
     47     return a == b || (a != null && a.equals(b));
     48   }
     49 
     50   // Clone of Lists.newArrayList
     51   public static <E> List<E> copyToList(Iterable<? extends E> elements) {
     52     List<E> list = new ArrayList<E>();
     53     addAll(list, elements);
     54     return list;
     55   }
     56 
     57   public static <E> List<E> copyToList(E[] elements) {
     58     return copyToList(Arrays.asList(elements));
     59   }
     60 
     61   // Clone of Sets.newLinkedHashSet
     62   public static <E> Set<E> copyToSet(Iterable<? extends E> elements) {
     63     Set<E> set = new LinkedHashSet<E>();
     64     addAll(set, elements);
     65     return set;
     66   }
     67 
     68   public static <E> Set<E> copyToSet(E[] elements) {
     69     return copyToSet(Arrays.asList(elements));
     70   }
     71 
     72   // Would use Maps.immutableEntry
     73   public static <K, V> Entry<K, V> mapEntry(K key, V value) {
     74     return Collections.singletonMap(key, value).entrySet().iterator().next();
     75   }
     76 
     77   public static void assertEqualIgnoringOrder(
     78       Iterable<?> expected, Iterable<?> actual) {
     79     List<?> exp = copyToList(expected);
     80     List<?> act = copyToList(actual);
     81     String actString = act.toString();
     82 
     83     // Of course we could take pains to give the complete description of the
     84     // problem on any failure.
     85 
     86     // Yeah it's n^2.
     87     for (Object object : exp) {
     88       if (!act.remove(object)) {
     89         Assert.fail("did not contain expected element " + object + ", "
     90             + "expected = " + exp + ", actual = " + actString);
     91       }
     92     }
     93     assertTrue("unexpected elements: " + act, act.isEmpty());
     94   }
     95 
     96   public static void assertContentsAnyOrder(
     97       Iterable<?> actual, Object... expected) {
     98     assertEqualIgnoringOrder(Arrays.asList(expected), actual);
     99   }
    100 
    101   public static <E> boolean addAll(
    102       Collection<E> addTo, Iterable<? extends E> elementsToAdd) {
    103     boolean modified = false;
    104     for (E e : elementsToAdd) {
    105       modified |= addTo.add(e);
    106     }
    107     return modified;
    108   }
    109 
    110   static <T> Iterable<T> reverse(final List<T> list) {
    111     return new Iterable<T>() {
    112       @Override
    113       public Iterator<T> iterator() {
    114         final ListIterator<T> listIter = list.listIterator(list.size());
    115         return new Iterator<T>() {
    116           @Override
    117           public boolean hasNext() {
    118             return listIter.hasPrevious();
    119           }
    120           @Override
    121           public T next() {
    122             return listIter.previous();
    123           }
    124           @Override
    125           public void remove() {
    126             listIter.remove();
    127           }
    128         };
    129       }
    130     };
    131   }
    132 
    133   static <T> Iterator<T> cycle(final Iterable<T> iterable) {
    134     return new Iterator<T>() {
    135       Iterator<T> iterator = Collections.<T>emptySet().iterator();
    136       @Override
    137       public boolean hasNext() {
    138         return true;
    139       }
    140       @Override
    141       public T next() {
    142         if (!iterator.hasNext()) {
    143           iterator = iterable.iterator();
    144         }
    145         return iterator.next();
    146       }
    147       @Override
    148       public void remove() {
    149         throw new UnsupportedOperationException();
    150       }
    151     };
    152   }
    153 
    154   static <T> T get(Iterator<T> iterator, int position) {
    155     for (int i = 0; i < position; i++) {
    156       iterator.next();
    157     }
    158     return iterator.next();
    159   }
    160 
    161   static void fail(Throwable cause, Object message) {
    162     AssertionFailedError assertionFailedError =
    163         new AssertionFailedError(String.valueOf(message));
    164     assertionFailedError.initCause(cause);
    165     throw assertionFailedError;
    166   }
    167 
    168   public static <K, V> Comparator<Entry<K, V>> entryComparator(
    169       final Comparator<? super K> keyComparator) {
    170     return new Comparator<Entry<K, V>>() {
    171       @Override
    172       @SuppressWarnings("unchecked") // no less safe than putting it in the map!
    173       public int compare(Entry<K, V> a, Entry<K, V> b) {
    174         return (keyComparator == null)
    175             ? ((Comparable) a.getKey()).compareTo(b.getKey())
    176             : keyComparator.compare(a.getKey(), b.getKey());
    177       }
    178     };
    179   }
    180 
    181   public static <T> void testComparator(
    182       Comparator<? super T> comparator, T... valuesInExpectedOrder) {
    183     testComparator(comparator, Arrays.asList(valuesInExpectedOrder));
    184   }
    185 
    186   public static <T> void testComparator(
    187       Comparator<? super T> comparator, List<T> valuesInExpectedOrder) {
    188     // This does an O(n^2) test of all pairs of values in both orders
    189     for (int i = 0; i < valuesInExpectedOrder.size(); i++) {
    190       T t = valuesInExpectedOrder.get(i);
    191 
    192       for (int j = 0; j < i; j++) {
    193         T lesser = valuesInExpectedOrder.get(j);
    194         assertTrue(comparator + ".compare(" + lesser + ", " + t + ")",
    195             comparator.compare(lesser, t) < 0);
    196       }
    197 
    198       assertEquals(comparator + ".compare(" + t + ", " + t + ")",
    199           0, comparator.compare(t, t));
    200 
    201       for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) {
    202         T greater = valuesInExpectedOrder.get(j);
    203         assertTrue(comparator + ".compare(" + greater + ", " + t + ")",
    204             comparator.compare(greater, t) > 0);
    205       }
    206     }
    207   }
    208 
    209   public static <T extends Comparable<? super T>> void testCompareToAndEquals(
    210       List<T> valuesInExpectedOrder) {
    211     // This does an O(n^2) test of all pairs of values in both orders
    212     for (int i = 0; i < valuesInExpectedOrder.size(); i++) {
    213       T t = valuesInExpectedOrder.get(i);
    214 
    215       for (int j = 0; j < i; j++) {
    216         T lesser = valuesInExpectedOrder.get(j);
    217         assertTrue(lesser + ".compareTo(" + t + ')', lesser.compareTo(t) < 0);
    218         assertFalse(lesser.equals(t));
    219       }
    220 
    221       assertEquals(t + ".compareTo(" + t + ')', 0, t.compareTo(t));
    222       assertTrue(t.equals(t));
    223 
    224       for (int j = i + 1; j < valuesInExpectedOrder.size(); j++) {
    225         T greater = valuesInExpectedOrder.get(j);
    226         assertTrue(greater + ".compareTo(" + t + ')', greater.compareTo(t) > 0);
    227         assertFalse(greater.equals(t));
    228       }
    229     }
    230   }
    231 
    232   /**
    233    * Returns a collection that simulates concurrent modification by
    234    * having its size method return incorrect values.  This is useful
    235    * for testing methods that must treat the return value from size()
    236    * as a hint only.
    237    *
    238    * @param delta the difference between the true size of the
    239    * collection and the values returned by the size method
    240    */
    241   public static <T> Collection<T> misleadingSizeCollection(final int delta) {
    242     // It would be nice to be able to return a real concurrent
    243     // collection like ConcurrentLinkedQueue, so that e.g. concurrent
    244     // iteration would work, but that would not be GWT-compatible.
    245     return new ArrayList<T>() {
    246       @Override public int size() { return Math.max(0, super.size() + delta); }
    247     };
    248   }
    249 
    250   /**
    251    * Returns a "nefarious" map entry with the specified key and value,
    252    * meaning an entry that is suitable for testing that map entries cannot be
    253    * modified via a nefarious implementation of equals. This is used for testing
    254    * unmodifiable collections of map entries; for example, it should not be
    255    * possible to access the raw (modifiable) map entry via a nefarious equals
    256    * method.
    257    */
    258   public static <K, V> Map.Entry<K, V> nefariousMapEntry(final K key,
    259       final V value) {
    260     return new Map.Entry<K, V>() {
    261       @Override public K getKey() {
    262         return key;
    263       }
    264       @Override public V getValue() {
    265         return value;
    266       }
    267       @Override public V setValue(V value) {
    268         throw new UnsupportedOperationException();
    269       }
    270       @SuppressWarnings("unchecked")
    271       @Override public boolean equals(Object o) {
    272         if (o instanceof Map.Entry) {
    273           Map.Entry<K, V> e = (Map.Entry<K, V>) o;
    274           e.setValue(value); // muhahaha!
    275 
    276           return equal(this.getKey(), e.getKey())
    277               && equal(this.getValue(), e.getValue());
    278         }
    279         return false;
    280       }
    281 
    282       @Override public int hashCode() {
    283         K k = getKey();
    284         V v = getValue();
    285         return ((k == null) ?
    286             0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
    287       }
    288 
    289       /**
    290        * Returns a string representation of the form <code>{key}={value}</code>.
    291        */
    292       @Override public String toString() {
    293         return getKey() + "=" + getValue();
    294       }
    295     };
    296   }
    297 
    298   static <E> List<E> castOrCopyToList(Iterable<E> iterable) {
    299     if (iterable instanceof List) {
    300       return (List<E>) iterable;
    301     }
    302     List<E> list = new ArrayList<E>();
    303     for (E e : iterable) {
    304       list.add(e);
    305     }
    306     return list;
    307   }
    308 
    309   private static final Comparator<Comparable> NATURAL_ORDER = new Comparator<Comparable>() {
    310     @SuppressWarnings("unchecked") // assume any Comparable is Comparable<Self>
    311     @Override public int compare(Comparable left, Comparable right) {
    312       return left.compareTo(right);
    313     }
    314   };
    315 
    316   public static <K extends Comparable, V> Iterable<Entry<K, V>> orderEntriesByKey(
    317       List<Entry<K, V>> insertionOrder) {
    318     sort(insertionOrder, Helpers.<K, V>entryComparator(NATURAL_ORDER));
    319     return insertionOrder;
    320   }
    321 
    322   /**
    323    * Private replacement for {@link com.google.gwt.user.client.rpc.GwtTransient} to work around
    324    * build-system quirks.
    325    */
    326   private @interface GwtTransient {}
    327 
    328   /**
    329    * Compares strings in natural order except that null comes immediately before a given value. This
    330    * works better than Ordering.natural().nullsFirst() because, if null comes before all other
    331    * values, it lies outside the submap/submultiset ranges we test, and the variety of tests that
    332    * exercise null handling fail on those subcollections.
    333    */
    334   public abstract static class NullsBefore implements Comparator<String>, Serializable {
    335     /*
    336      * We don't serialize this class in GWT, so we don't care about whether GWT will serialize this
    337      * field.
    338      */
    339     @GwtTransient private final String justAfterNull;
    340 
    341     protected NullsBefore(String justAfterNull) {
    342       if (justAfterNull == null) {
    343         throw new NullPointerException();
    344       }
    345 
    346       this.justAfterNull = justAfterNull;
    347     }
    348 
    349     @Override
    350     public int compare(String lhs, String rhs) {
    351       if (lhs == rhs) {
    352         return 0;
    353       }
    354       if (lhs == null) {
    355         // lhs (null) comes just before justAfterNull.
    356         // If rhs is b, lhs comes first.
    357         if (rhs.equals(justAfterNull)) {
    358           return -1;
    359         }
    360         return justAfterNull.compareTo(rhs);
    361       }
    362       if (rhs == null) {
    363         // rhs (null) comes just before justAfterNull.
    364         // If lhs is b, rhs comes first.
    365         if (lhs.equals(justAfterNull)) {
    366           return 1;
    367         }
    368         return lhs.compareTo(justAfterNull);
    369       }
    370       return lhs.compareTo(rhs);
    371     }
    372 
    373     @Override
    374     public boolean equals(Object obj) {
    375       if (obj instanceof NullsBefore) {
    376         NullsBefore other = (NullsBefore) obj;
    377         return justAfterNull.equals(other.justAfterNull);
    378       }
    379       return false;
    380     }
    381 
    382     @Override
    383     public int hashCode() {
    384       return justAfterNull.hashCode();
    385     }
    386   }
    387 
    388   public static final class NullsBeforeB extends NullsBefore {
    389     public static final NullsBeforeB INSTANCE = new NullsBeforeB();
    390 
    391     private NullsBeforeB() {
    392       super("b");
    393     }
    394   }
    395 
    396   public static final class NullsBeforeTwo extends NullsBefore {
    397     public static final NullsBeforeTwo INSTANCE = new NullsBeforeTwo();
    398 
    399     private NullsBeforeTwo() {
    400       super("two"); // from TestStringSortedMapGenerator's sample keys
    401     }
    402   }
    403 }
    404 
    405