• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import com.google.common.annotations.GwtIncompatible;
26 import java.io.Serializable;
27 import java.lang.reflect.Method;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.Comparator;
33 import java.util.Iterator;
34 import java.util.LinkedHashSet;
35 import java.util.List;
36 import java.util.ListIterator;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.Set;
40 import junit.framework.Assert;
41 import junit.framework.AssertionFailedError;
42 
43 @GwtCompatible(emulated = true)
44 public class Helpers {
45   // Clone of Objects.equal
equal(Object a, Object b)46   static boolean equal(Object a, Object b) {
47     return a == b || (a != null && a.equals(b));
48   }
49 
50   // Clone of Lists.newArrayList
copyToList(Iterable<? extends E> elements)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 
copyToList(E[] elements)57   public static <E> List<E> copyToList(E[] elements) {
58     return copyToList(Arrays.asList(elements));
59   }
60 
61   // Clone of Sets.newLinkedHashSet
copyToSet(Iterable<? extends E> elements)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 
copyToSet(E[] elements)68   public static <E> Set<E> copyToSet(E[] elements) {
69     return copyToSet(Arrays.asList(elements));
70   }
71 
72   // Would use Maps.immutableEntry
mapEntry(K key, V value)73   public static <K, V> Entry<K, V> mapEntry(K key, V value) {
74     return Collections.singletonMap(key, value).entrySet().iterator().next();
75   }
76 
isEmpty(Iterable<?> iterable)77   private static boolean isEmpty(Iterable<?> iterable) {
78     return iterable instanceof Collection
79         ? ((Collection<?>) iterable).isEmpty()
80         : !iterable.iterator().hasNext();
81   }
82 
assertEmpty(Iterable<?> iterable)83   public static void assertEmpty(Iterable<?> iterable) {
84     if (!isEmpty(iterable)) {
85       Assert.fail("Not true that " + iterable + " is empty");
86     }
87   }
88 
assertEmpty(Map<?, ?> map)89   public static void assertEmpty(Map<?, ?> map) {
90     if (!map.isEmpty()) {
91       Assert.fail("Not true that " + map + " is empty");
92     }
93   }
94 
assertEqualInOrder(Iterable<?> expected, Iterable<?> actual)95   public static void assertEqualInOrder(Iterable<?> expected, Iterable<?> actual) {
96     Iterator<?> expectedIter = expected.iterator();
97     Iterator<?> actualIter = actual.iterator();
98 
99     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 
assertContentsInOrder(Iterable<?> actual, Object... expected)121   public static void assertContentsInOrder(Iterable<?> actual, Object... expected) {
122     assertEqualInOrder(Arrays.asList(expected), actual);
123   }
124 
assertEqualIgnoringOrder(Iterable<?> expected, Iterable<?> actual)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 
assertContentsAnyOrder(Iterable<?> actual, Object... expected)149   public static void assertContentsAnyOrder(Iterable<?> actual, Object... expected) {
150     assertEqualIgnoringOrder(Arrays.asList(expected), actual);
151   }
152 
assertContains(Iterable<?> actual, Object expected)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 
assertContainsAllOf(Iterable<?> actual, Object... expected)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 
addAll(Collection<E> addTo, Iterable<? extends E> elementsToAdd)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 
reverse(final List<T> list)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 }
527